-
Notifications
You must be signed in to change notification settings - Fork 4.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
System.Text.Json default DateTimeZoneHandling #1566
Comments
cc @layomia on dates Since a DateTime can be set in each of those formats (e.g. with and without the timezone\offset), the reader\writer (and thus the serializer) uses what is available and uses\assumes an ISO 8601 format to represent that. |
@btecu the ISO 8601 profile is used by default in the serializer, e.g. 2019-07-26T16:59:57-05:00. For deserializing, if the datetime offset is given as "hh:mm", a DateTime with For more on DateTime and DateTimeOffset support in System.Text.Json, and how you can implement custom parsing or formatting, see https://docs.microsoft.com/en-us/dotnet/standard/datetime/system-text-json-support. |
@btecu unfortunately the only way, I think, to have the similar option in services.AddControllers()
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.Converters.Add(new DateTimeConverter());
}); and implement DateTimeConverter like that public class DateTimeConverter : JsonConverter<DateTime>
{
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return DateTime.Parse(reader.GetString());
}
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.ToUniversalTime().ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ssZ"));
}
} |
This extends @mpashkovskiy solution and relies on the functionality in public class DateTimeConverter : JsonConverter<DateTime>
{
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return reader.GetDateTime().ToUniversalTime();
}
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.ToUniversalTime());
}
} |
This solution should come natively so that we have the best possible performance. JsonConverter creates problems when poorly implemented. |
Just adding to @mpashkovskiy solution, you could use the SpecifyKind method in .Net to do this as follows:
|
@davidfowl and @JamesNK , what do you guys recommend here? We are building up new project using System.Text.json, want to ensure we use the right guidance and get benefit from system.text.json. |
Exactly what I was looking for! I save all DateTime as UTC in the database because I have different timezones in development and production. I then parse the UTC time to local time in the client, but by default the json serializer didn't append a "Z" so I had to do some ugly string concatenation to make it work. This solves that issue by specifying that the date is already in UTC and will therefore return a nice ISO string that javascript also understands. The issue with using |
@ysbakker , javascript is not sending string ending with "Z"? |
|
Is there still no built in feature for forcing deserializer to add 'Z' to the end? I also need this feature. We used this in Json.NET:
|
Same, except it was @dalle's solution that worked for me. This has been a world of pain for a globally distributed system. |
@backnotprop , @dalle , @amay5027 and @davidfowl , We decided not to use JsonConverter and instead pass DateTime as string for two reasons:
Our solution was to wrap in an extension method:
Your thoughts? |
Also stumbled upon this issue, since every other system expects and ISO string in json. This does sound like an unnecessary hack. |
@rbhanda , Do we have an option to set this globally like Json.NET in .NET 6 ? Can you add it to backlog of .NET 7 otherwise?
|
In almost every typical client-server web system the server uses and stores dates in UTC (default behavior for SQL DateTime mapping with EF Core for example), while browsers should show the local timezone as users are from all around the internet. Having this feature in a similar fashion to json.net - even if not making it the default behavior to break things - would just make a lot of sense. |
@amay5027 Note that the
@danilobreda what are the performance issues you are identified with the proposed workarounds? It would seem to me that the solution proposed in #1566 (comment) would be as fast as a native feature.
@killerwife the default DateTime serialization uses ISO 8601. I believe the ask here is whether we should introduce a feature that automatically converts the TZ offsets on the serialization layer. |
@eiriktsarpalis I won't know what the performance issues are, and that's the idea. Using a solution that comes natively doesn't bring that kind of questioning. |
I personally wouldn't agree with this line of thinking. Ultimately not every requested feature will find its way as an OOTB feature (or it may take multiple releases before it does). As such I wholeheartedly encourage building successful third-party extension libraries (there are quite a few quality ones already out there). As a maintainer I would prioritize addressing extensibility concerns in the core infrastructure over complete feature parity with other offerings. Bottom line in this case, I would argue that the custom converter proposed here as a workaround would be just as fast (and likely faster) than a configurable built-in converter.
I believe that the Newtonsoft offering might simply reflect the fact that earlier versions of the library didn't use ISO 8601 when serializing dates. This has been the only supported format in STJ from day 1, and as such any TZ information is always accurately represented in the underlying JSON. I guess I'm trying to better understand the motivating use cases, and I can only think of the following:
Am I forgetting something? |
@eiriktsarpalis Applications that used JSON.NET with |
This is a really annoying thing when you want to upgrade to .net 6 because the default de-serialiser of a view model will add the timezone given by the frontend. If you forward this to a Postgres database you will get an error like |
Edit: Please do not use this, see replies from @eiriktsarpalis and @OskarKlintrot below. For anyone who uses public class NullableDateTimeConverter : JsonConverter<DateTime?>
{
public override DateTime? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return reader.TryGetDateTime(out var value) ? value.ToUniversalTime() : null;
}
public override void Write(Utf8JsonWriter writer, DateTime? value, JsonSerializerOptions options)
{
if (value.HasValue)
{
writer.WriteStringValue(value.Value.ToUniversalTime());
}
else
{
writer.WriteNullValue();
}
}
} |
Writing dedicated converters for nullable types is not recommended. Authoring a custom converter for the underlying struct should suffice, the generic nullable converter will compose with that. |
And you can access the other converters from inside your converter (to avoid doing the convertion yourself if there's already a perfectly good converter at your disposal once you done with type checks or whatever you want to do):
|
Thanks @eiriktsarpalis and @OskarKlintrot, will edit. |
Would be great to have some build it converter in .Net for these kind of scenarios. |
If the goal is to get pure local time (by stripping timezone part from the datetime), then one solution I found is to change the contract of the received object properties to And then you could use |
Hi @dalle Thank you for the solution above! It's almost there, but I noticed one subtle issue. When calling Here's my proposed solution to handle this correctly: public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var date = reader.GetDateTime();
return date.Kind == DateTimeKind.Utc
? date
: DateTime.SpecifyKind(date, DateTimeKind.Utc);
} |
In JSON.NET you can:
Is there anything similar in
System.Text.Json
?If there is not an option to set the default, can it be passed in manually?
Also, what is the default (
Local
,Utc
,Unspecified
)?The text was updated successfully, but these errors were encountered: