ZonedTime从JSON到JSON

时间:2016-12-22 04:22:41

标签: haskell aeson servant

我被Aeson的{​​{1}}和Servant转换所迷惑。

在我的ZonedTime应用中,我会在网址中留出一些时间:Servant

.../2016-12-18T07:51:00+03:00/...可以使用Servant轻松将其转换为ZonedTime

然后我的应用程序进行了一些计算,在json-response中我想回馈给客户端以及其他一些... :> Capture "zt" ZonedTime :> ... - 以防客户想要再次将这些时间提供给我的应用程序。

如果输入时区不为零ZonedTime(X / = 0),那么在输出中我也得到+0X:00,但如果输入我给+0X:00,那么作为回应我得到.../2016-12-18T07:51:00+00:00/...。如果我尝试使用2016-12-18T07:51:00Z再次将此字符串反馈给Servant,则.../2016-12-18T07:51:00Z/...无法将其转换为Servant。实际上是返回ZonedTime

为什么呢?为什么?

2 个答案:

答案 0 :(得分:0)

ISO 8601是JSON中使用的时间的标准文本表示。当时区为UTC时,“+00:00”或“Z”是有效的时区后缀。看起来Aeson在ISO 8601中使用“Z”后缀(如果它是UTC)和“+ xx:xx”后缀输出时间。不幸的是,Servant(实际上,Web.HttpApiData)使用一种简单的方法来解析不允许使用“Z”后缀的URL片段ZonedTime。如果你改为解析UTCTime,那么它会使用(并要求)“Z”后缀。

您可以为ZonedTime定义一个新类型别名,通过尝试解析为ZonedTime来处理这两种格式,并且 - 如果失败,则UTCTime进行转换:

module ZonedTimeTest where

import Data.Time.LocalTime
import Servant.API

newtype ZonedTime' = ZonedTime' { getZonedTime :: ZonedTime }

instance FromHttpApiData ZonedTime' where
  parseUrlPiece u =     ZonedTime' <$> parseUrlPiece u            -- "...+xx:xx"
                    <!> ZonedTime' . fromUTC <$> parseUrlPiece u  -- "...Z"
    where fromUTC = utcToZonedTime utc
          infixl 3 <!>
          Left _ <!> y = y
          x      <!> _ = x

然后Capture "zt" ZonedTime'应该为您处理这两种格式(尽管您需要在适当的时候将ZonedTime'打包到ZonedTime

答案 1 :(得分:0)

确定。

因此,只要...Z表示法被Servant正确解析为UTCTime,我就会创建另一个捕获行:

:<|> "myendpoint" :> Capture "zt" ZonedTime :> ...
:<|> "myendpoint" :> Capture "utct" UTCTime :> ...

并做了相应的处理程序。这个带+xx:xx的文字被视为ZonedTime并转到一个处理程序,带有Z的文字被第二行占用并转到第二个处理程序,这与第一个处理程序相同,但动态地将UTC转换为Zoned

<强>更新

我开始理解,我的系统如何工作的方式导致了这样一个事实,即在URL中我可能有不同的字符串编码时间变化。

  1. 如果时区可能是+03:00,或只是Z,如果是时区。
  2. 我可能有像2016-12-09T15:04:26.349857693845+05:00
  3. 这样的小数秒

    Capture的标准ZonedTime并不理解Z作为时区,也不理解小数秒。

    所以我按照这里的另一个答案提出的方向做了某种方向。

    我只放了一条捕获线

    "daymonth" :> Capture "zt" ZonedTime' :> Capture "fl" Double :> Get '[JSON] Value
    

    我创建了新类型ZonedTime',这就是为我做的一切。

    newtype ZonedTime' = ZonedTime' { unwrap :: ZonedTime }
    
    instance FromHttpApiData ZonedTime' where
      parseUrlPiece text = Right zt
        where
          strRaw = unpack text
          str = subRegex (mkRegex "Z$") strRaw "+00:00"
          zt = ZonedTime' (parseTimeOrError False defaultTimeLocale "%Y-%m-%dT%H:%M:%S%Q%z" str)
    
    1. 我处理Z问题,用+00:00
    2. 代替
    3. 然后我手动编写字符串解析,给出格式字符串,其中%Q捕获小数部分秒。