40
votes

I am migrating a web API from .NET Core 2.2 to 3.0 and want to use the new System.Text.Json. When using Newtonsoft I was able to format DateTime using the code below. How can I accomplish the same?

.AddJsonOptions(options =>
    {
        options.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Utc;
        options.SerializerSettings.DateFormatString = "yyyy'-'MM'-'dd'T'HH':'mm':'ssZ";
    });
2
What's the actual question? How to treat DateTime as UTC even if it's not? Both JSON.NET and System.Text.Json use ISO8601 by default. If the DateTimeKind is UTC, Z is appended to the string. A local time will include the local timezone offsetPanagiotis Kanavos
That's not what your code does though, since JSON.NET already uses ISO8601- the same format you used. What you did there was force it to use UTC for all DateTime kinds. And I already explained that System.Text.Json already takes care of dates whose DateTime.Kind is UTC. Which means the dates you want to store are either Local or Unspecified.Panagiotis Kanavos
Why do you want to convert to UTC though? Why not let System.Text.Json emit the offset? In any case, date formatting is explained in DateTime and DateTimeOffset support in System.Text.Json. There's no way to force the format short of creating a custom formatter. You could make sure all the dates you use are UTC or use DateTimeOffset to make sure the offset is specifiedPanagiotis Kanavos
I want to serialize the DateTime without the fractional seconds, and always UTC. When accessing my API using swift (iOS app) the fractional seconds and offset causes a json parsing failure.D. English
related issue here: github.com/dotnet/runtime/issues/1566mkb

2 Answers

59
votes

Solved with a custom formatter. Thank you Panagiotis for the suggestion.

public class DateTimeConverter : JsonConverter<DateTime>
{
    public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        Debug.Assert(typeToConvert == typeof(DateTime));
        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"));
    }
}


// in the ConfigureServices()
services.AddControllers()
    .AddJsonOptions(options =>
     {
         options.JsonSerializerOptions.Converters.Add(new DateTimeConverter());
     });
10
votes

Migrating to Core 3 I had to replace System.Text.Json to use Newtonsoft again by :

services.AddControllers().AddNewtonsoftJson();

But I was having same issue with UTC dates in an Angular app and I had to add this to get dates in UTC:

services.AddControllers().AddNewtonsoftJson(
       options => options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Utc);

In your case you should be able to do this:

services.AddControllers().AddNewtonsoftJson(options =>
    {
        options.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Utc;
        options.SerializerSettings.DateFormatString = "yyyy'-'MM'-'dd'T'HH':'mm':'ssZ";
    });

It works and I hope it helps...