我被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
。
为什么呢?为什么?
答案 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中我可能有不同的字符串编码时间变化。
+03:00
,或只是Z
,如果是时区。2016-12-09T15:04:26.349857693845+05:00
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)
Z
问题,用+00:00
%Q
捕获小数部分秒。