I am befuzzled by Aeson
and Servant
conversions of ZonedTime
.
To my Servant
app I give some time in the url: .../2016-12-18T07:51:00+03:00/...
.
Servant
easily converts it to ZonedTime
with ... :> Capture "zt" ZonedTime :> ...
.
Then my app does some calculations and in json-response I want to give back to the client this and some other ZonedTime
s — in case if client wants to give these times to my app again.
If input timezone was not zero +0X:00
(X /= 0), then on the output I also get +0X:00
, but if on input I give .../2016-12-18T07:51:00+00:00/...
, then in response I get 2016-12-18T07:51:00Z
. And if I try to feed this string to Servant
again with .../2016-12-18T07:51:00Z/...
, then Servant
fails to convert it to ZonedTime
. Actually is returns HTTP 400 (Bad Request)
.
Why? What for?
ISO 8601 is the standard textual representation for times used in JSON. When the timezone is UTC, either "+00:00" or "Z" is a valid timezone suffix. It looks like Aeson outputs times in ISO 8601 using the "Z" suffix if it's UTC and a "+xx:xx" suffix otherwise. Unfortunately, Servant (actually,
Web.HttpApiData
) uses a naive method of parsingZonedTime
from URL pieces that doesn't permit the "Z" suffix. If you parse aUTCTime
instead, then it uses (and requires) the "Z" suffix.You can define a newtype alias for
ZonedTime
as follows that handles both formats by trying to parse as aZonedTime
and -- failing that -- aUTCTime
with conversion:and then
Capture "zt" ZonedTime'
should handle both formats for you (though you'll need to unwrap theZonedTime'
to aZonedTime
where appropriate).