Formatting DateTime in ASP.NET Core 3.0 using System.Text.Json
Solution 1
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());
});
Solution 2
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...
Solution 3
This dumpster fire of asp.net core date serialization/deserialization is maybe easier to understand when you see the dumpster fire of Date.Parse() and Date.ParseExact(). We're passing dates to and from javascript, so we don't want to be formatting. We just want to transparently serialize and deserialize between DateTime and ISO 8601 in UTC.
That this is not the default, and that there's no easy configuration option, and that the solution is so funky and fragile, is credibility-destroying. This is currently what's working for me, based on D.English's answer for writing, and the linked answer for reading, and using this answer to access the JsonDocument correctly...
Update this is for the dumptser fire of model binding. For the dumpster fire of query string parsing, it's over here
// in Startup.cs ConfigureServices()
services.AddMvc().AddJsonOptions(options =>
{
options.JsonSerializerOptions.Converters.Add(new UtcDateTimeConverter());
});
public class BobbyUtcDateTimeConverter : JsonConverter<DateTime>
{
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
using (var jsonDoc = JsonDocument.ParseValue(ref reader))
{
var stringValue = jsonDoc.RootElement.GetRawText().Trim('"').Trim('\'');
var value = DateTime.Parse(stringValue, null, System.Globalization.DateTimeStyles.RoundtripKind);
return value;
}
}
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.ToString("yyyy-MM-ddTHH:mm:ss.fffZ", System.Globalization.CultureInfo.InvariantCulture));
}
}
Admin
Updated on July 31, 2022Comments
-
Admin almost 2 years
I am migrating a web API from .NET Core 2.2 to 3.0 and want to use the new
System.Text.Json
. When usingNewtonsoft
I was able to formatDateTime
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"; });
-
Carlos Muñoz over 3 yearsThere are two problems with this code. 1) NewtonSoft.Json doesn't always call
.ToUniversalTime()
on value. It depends on itsDateTimeKind
. The provided format string strips down the 7 decimal precision thatNewtonSoft.Json
mantains. I can update your answer with the correct code if you are ok with it. Otherwise i can create a new answer with the correct code. -
mkb over 3 yearsthe thing is question is about System.Text.Json not NewtonSoft.Json
-
mkb over 3 yearsSince I'am already using UTC in client code too I exluded
ToUniversalTime()
, well all I needed was theZ
at the end of the date string and this accoplished that, this is the correct approach I guess?!. also apparantlyreader
has a methodreader.GetDateTime()
which can be used inRead
method -
Anton Shakalo almost 3 yearsquestion was not about newtonsoft.json
-
Necip Sunmaz over 2 yearsThis is a good solution for problem. Thanks mate you saved my day.
-
AntonIva over 2 yearsI will accept this answer, kk. Thanks
-
bbsimonbb over 2 years15 lines of code, a fragile modification in Startup, just to have a complete unambiguous date in my API output. This is credibility-affecting.
-
bbsimonbb over 2 yearsBeware the timezone! The above code will assume your C# DateTime is in local time, and will convert it to UTC before serializing as UTC. If, to stay sane, all your dates are already UTC, an unwanted timezone delta will sneak in at this step. (To fix this, just delete
ToUniversalTime()
in theWrite()
method.) -
Jonathan Allen about 2 years
DateTime.SpecifyKind
doesn't work. If you round-trip a date, it will be off by your local time zone.