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 ZonedTimes — 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 parsingZonedTimefrom URL pieces that doesn't permit the "Z" suffix. If you parse aUTCTimeinstead, then it uses (and requires) the "Z" suffix.You can define a newtype alias for
ZonedTimeas follows that handles both formats by trying to parse as aZonedTimeand -- failing that -- aUTCTimewith conversion:and then
Capture "zt" ZonedTime'should handle both formats for you (though you'll need to unwrap theZonedTime'to aZonedTimewhere appropriate).