C# – Changing the JSON serialization date format

When you serialize a date with System.Text.Json, it uses the standard ISO-8601 date format (ex: “2022-01-31T13:15:05.2151663-05:00”). Internally, it uses the DateTimeConverter class for handling DateTime, which doesn’t give you a way to change the date format.

To change the date format, you have to create a custom converter and pass it in:

using System.Text.Json; var options = new JsonSerializerOptions() { WriteIndented = true }; options.Converters.Add(new CustomDateTimeConverter("yyyy-MM-dd")); var nikolaTesla = new Person() { BirthDate = new DateTime(year: 1856, month: 7, day: 10) }; var json = JsonSerializer.Serialize(nikolaTesla, options); Console.WriteLine(json);
Code language: C# (cs)

Here’s the custom converter class:

using System.Text.Json; using System.Text.Json.Serialization; public class CustomDateTimeConverter : JsonConverter<DateTime> { private readonly string Format; public CustomDateTimeConverter(string format) { Format = format; } public override void Write(Utf8JsonWriter writer, DateTime date, JsonSerializerOptions options) { writer.WriteStringValue(date.ToString(Format)); } public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return DateTime.ParseExact(reader.GetString(), Format, null); } }
Code language: C# (cs)

Note: If you need to deal with DateTimeOffset as well, you’ll need another custom converter. Consider using JsonConverterFactory in that scenario.

Running the code above generates the following JSON with the custom date format:

{ "BirthDate": "1856-07-10" }
Code language: JSON / JSON with Comments (json)

Newtonsoft – Change date format through settings

It’s much simpler to change the date format when you’re using Newtonsoft. By default, it uses the ISO-8601 date format, but you can change it by setting the DateFormatString setting:

using Newtonsoft.Json; var settings = new JsonSerializerSettings() { DateFormatString = "yyyy-MM-dd" }; var nikolaTesla = new Person() { BirthDate = new DateTime(year: 1856, month: 7, day: 10) }; var json = JsonConvert.SerializeObject(nikolaTesla, Formatting.Indented, settings); Console.WriteLine(json);
Code language: C# (cs)

This outputs the following JSON:

{ "BirthDate": "1856-07-10" }
Code language: JSON / JSON with Comments (json)

Handling DateOnly and TimeOnly

The DateOnly and TimeOnly types (introduced in .NET 6) aren’t supported by System.Text.Json. If you try to use them, you’ll get the following exception:

System.NotSupportedException: Serialization and deserialization of ‘System.DateOnly’ instances are not supported.

To be able to handle DateOnly and TimeOnly, you have to create and use custom converters, like this:

using System.Text.Json; var options = new JsonSerializerOptions() { WriteIndented = true }; options.Converters.Add(new CustomDateOnlyConverter("yyyy-MM-dd")); options.Converters.Add(new CustomTimeOnlyConverter("HH:mm")); var activity = new Activity() { Date = new DateOnly(year: 2022, month: 1, day: 31), Time = new TimeOnly(hour: 14, minute: 39) }; var json = JsonSerializer.Serialize(activity, options); Console.WriteLine(json);
Code language: C# (cs)

This outputs the following JSON:

{ "Date": "2022-01-31", "Time": "14:39" }
Code language: JSON / JSON with Comments (json)

Here are the DateOnly and TimeOnly custom converter classes:

using System.Text.Json; using System.Text.Json.Serialization; public class CustomDateOnlyConverter : JsonConverter<DateOnly> { private readonly string Format; public CustomDateOnlyConverter(string format) { Format = format; } public override void Write(Utf8JsonWriter writer, DateOnly date, JsonSerializerOptions options) { writer.WriteStringValue(date.ToString(Format)); } public override DateOnly Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return DateOnly.ParseExact(reader.GetString(), Format); } } public class CustomTimeOnlyConverter : JsonConverter<TimeOnly> { private readonly string Format; public CustomTimeOnlyConverter(string format) { Format = format; } public override void Write(Utf8JsonWriter writer, TimeOnly date, JsonSerializerOptions options) { writer.WriteStringValue(date.ToString(Format)); } public override TimeOnly Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return TimeOnly.ParseExact(reader.GetString(), Format); } }
Code language: C# (cs)

Newtonsoft doesn’t handle DateOnly / TimeOnly well

Unlike System.Text.Json, Newtonsoft attempts to handle DateOnly / TimeOnly without throwing an exception, but the results are undesirable. Here’s an example to see what I mean.

using Newtonsoft.Json; var nikolaTesla = new Person() { BirthDate = new DateOnly(year: 1856, month: 7, day: 10) }; var json = JsonConvert.SerializeObject(nikolaTesla, Formatting.Indented); Console.WriteLine(json);
Code language: C# (cs)

This outputs the following JSON:

{ "BirthDate": { "Year": 1856, "Month": 7, "Day": 10, "DayOfWeek": 4, "DayOfYear": 192, "DayNumber": 677715 } }
Code language: JSON / JSON with Comments (json)

It’s really just serializing all of the public DateOnly properties. I don’t think anyone would want to receive a date like this. Furthermore, it can’t deserialize this back into a DateOnly property (because none of the properties have public setters). You’d need to write a custom converter (same approach as System.Text.Json) to handle DateOnly / TimeOnly properly.

Leave a Comment