Thoth.Json
Thoth.Json copied to clipboard
On serializing/deserializing a DateTime, "Kind" information is lost and is set to UTC
Issue by sachabroute
Thursday Jul 25, 2019 at 11:00 GMT
Originally opened as https://github.com/MangelMaxime/Thoth/issues/156
When serializing a DateTime CEST, on deserializing we lose the "Kind" information and it is set by default to UTC.
Client:
Server:
Comment by MangelMaxime
Thursday Jul 25, 2019 at 11:16 GMT
By default, we transfer UTC over the JSON because your client and server can be on a different timezone. I think this is what most JSON serialize do but can be wrong.
In general, if you need a specific DateTime
handler, you should write your own.
It's also possible that DateTimeOffset
is a solution for that too, I don't know. Handling date is really complex :)
Comment by sachabroute
Thursday Jul 25, 2019 at 11:51 GMT
Makes sense, I was also thinking it might have been done deliberately as server should always have the UTC time. However it seems there is some ambiguity as to other JSON serializers do since I think Newtonsoft.Json does deserialize the Kind properly, but Microsoft's don't. Maybe this could deserve some kind of note somewhere?
Comment by MangelMaxime
Thursday Jul 25, 2019 at 11:54 GMT
Maybe this could deserve some kind of note somewhere?
We can add that to the doc comment here and here.
Note that the projects are in a separate repo.
The split of this repo isn't complete yet.
Thoth.Json should not assume that the DateTime sent from server should always be in UTC. There are many cases where local DateTime will be sent (like alarm time).
Unless the server sends timestamp with the Z
specifier (ex. 2021-03-03T09:30:00Z
) or with the timezone difference (ex. 2021-03-03T09:30:00−02:00
), Thoth.Json should return the DateTime with Kind
set to Unspecified
. IMO, this is the correct behavior.
.NET and Fable already behaves as expected.
DateTime.Parse("2021-03-03T09:30:00") // DateTime.Kind is Unspecified
DateTime.Parse("2021-03-03T09:30:00Z") // DateTime.Kind is Local
However in Decode.fs
let datetime : Decoder<System.DateTime> =
fun path value ->
if Helpers.isString value then
match System.DateTime.TryParse (Helpers.asString value) with
| true, x -> x.ToUniversalTime() |> Ok
| _ -> (path, BadPrimitive("a datetime", value)) |> Error
there's conversion x.ToUniversalTime()
. Is this conversion required when the user did not ask for it?
I'm not sure what's the motive of doing this conversion so I may be wrong too.
In PR #149, we the Decode.datetime
as being marked as obsolete to make it explicit was is happening to the date.
I think this also fix the issue too.