You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Possible loss of DateTime's Kind with DotNetclient #367
I'm trying to upgrade my code to everything latest, .net8 and all fable related stuff, including Fable.Remoting. In one of my tests I'm checking if a certain server call returns a UTC Kind in a DateTime. It fails, because Kind is Local. This used to work with an older version of the library. I've checked the server side code and I can see that Kind is indeed UTC. Could it be that the value is lost in serialisation/deserialisation?
Could it be that the value is lost in serialisation/deserialisation?
Hi there @zelenij
Yes, it is possible that Kind is lost when sent across the wire. However, for the longest time I can remember, we recommend using DateTimeOffset if you care about if you care about UTC vs. Local which will maintain its offset when sent/received from either server or client.
I saw the advise regarding DateTimeOffset. Unfortunately, DateTime is all over my codebase, and changing it would be a huge pain. All my times are in UTC, so DateTimeOffset is not strictly necessary.
@zelenij Alright, let's find out why this happens. Since you are using the dotnet client, it means that both client and server use Fable.Remoting.Json to handle all JSON-related things. In my unit test for a universal DateTime, I see this:
testCase "Union with DateTime conversion"<|fun()->letdateInput= DateTime.Now.ToUniversalTime()letserialized= serialize (UnionWithDateTime.Date dateInput)letdeserialized= deserialize<UnionWithDateTime> serialized
match deserialized with| Int _-> fail()| Date dateOutput ->
Expect.equal dateInput.Second dateOutput.Second "Seconds are the same"
Expect.equal dateInput.Minute dateOutput.Minute "Minutes are the same"
Expect.equal dateInput.Hour dateOutput.Hour "Hours are the same"
Expect.equal dateInput.Day dateOutput.Day "Days are the same"
Expect.equal dateInput.Month dateOutput.Month "Months are the same"
Expect.equal dateInput.Year dateOutput.Year "Year are the same"
Expect.equal dateInput.Kind dateOutput.Kind "Kinds are the same"
Which shows that the Kind is maintained when serialized then deserialized to JSON.
In the dotnet client, we do use specific settings where we set DateParseHandling to None which should be fine actually, since the default behaviour is lossy:
/// Parses a JSON iput string to a .NET type using Fable JSON converterletparseAs<'t>(json:string)=letoptions= JsonSerializerSettings()
options.Converters.Add converter
options.DateParseHandling <- DateParseHandling.None
JsonConvert.DeserializeObject<'t>(json, options)
Any chance you could provide an example of a DateTime roundtrip that reproduces the issue?
Thanks, I'll do more debugging on my side to see if I can clearly rule out any other option and/or create a small standalone test to reproduce the problem
So far I can see that by server side code prepares a DateTime with Utc Kind. However, when it arrives serialised through the HTTP request via the DotNetClient, it looks like this:
"2024-07-16T15:57:10.9807420Z"
If I read the deserialiser code correctly, it then calls DateTime.Parse on this string. And the result has Local Kind:
Activity
Zaid-Ajaj commentedon Jul 12, 2024
Hi there @zelenij
Yes, it is possible that
Kindis lost when sent across the wire. However, for the longest time I can remember, we recommend usingDateTimeOffsetif you care about if you care about UTC vs. Local which will maintain its offset when sent/received from either server or client.Hope this helps!
zelenij commentedon Jul 12, 2024
I saw the advise regarding
DateTimeOffset. Unfortunately,DateTimeis all over my codebase, and changing it would be a huge pain. All my times are in UTC, soDateTimeOffsetis not strictly necessary.Zaid-Ajaj commentedon Jul 12, 2024
@zelenij Alright, let's find out why this happens. Since you are using the dotnet client, it means that both client and server use Fable.Remoting.Json to handle all JSON-related things. In my unit test for a universal
DateTime, I see this:Which shows that the
Kindis maintained when serialized then deserialized to JSON.In the dotnet client, we do use specific settings where we set
DateParseHandlingtoNonewhich should be fine actually, since the default behaviour is lossy:Any chance you could provide an example of a
DateTimeroundtrip that reproduces the issue?zelenij commentedon Jul 14, 2024
Thanks, I'll do more debugging on my side to see if I can clearly rule out any other option and/or create a small standalone test to reproduce the problem
zelenij commentedon Jul 16, 2024
So far I can see that by server side code prepares a
DateTimewithUtcKind. However, when it arrives serialised through the HTTP request via the DotNetClient, it looks like this:If I read the deserialiser code correctly, it then calls
DateTime.Parseon this string. And the result hasLocalKind:Maybe the Json serialisation is at fault here?
kerams commentedon Mar 21, 2025
I think the solution could be
DateTime.Parse (x, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind). SeeThe return value and DateTime.Kindhttps://learn.microsoft.com/en-us/dotnet/api/system.datetime.parse?view=net-8.0#remarksZaid-Ajaj commentedon Apr 18, 2026
@kerams does this still require revisiting?
kerams commentedon Apr 19, 2026
I don't think anything's changed in this area in the meantime, so likely yes.