JSON serialization of TimeOnly and DateOnly types in .NET 6
In case you are having trouble serializing the new types in .NET 6 using System.Text.Json namespace to convert DateOnly and TimeOnly types, then you are not alone. I found this after dealing with using DateOnly and TimeOnly types while using Npgsql with a Blazor app I was working on.
It turns out that you will have to write a custom converter that will handle serialization of these types to JSON and back. I checked and tried to hand roll one myself. Luckily, I found some inspiration from an msdn blog post, not sure whose it is, as I cannot find the site at the moment, but it helped me along the right path. I have these two classes to do the work for me.
public class DateOnlyConverter : JsonConverter<DateOnly>{private readonly string serializationFormat;public DateOnlyConverter() : this(null){}public DateOnlyConverter(string? serializationFormat){this.serializationFormat = serializationFormat ?? "yyyy-MM-dd";}public override DateOnly Read(ref Utf8JsonReader reader,Type typeToConvert, JsonSerializerOptions options){var value = reader.GetString();return DateOnly.Parse(value!);}public override void Write(Utf8JsonWriter writer, DateOnly value,JsonSerializerOptions options)=> writer.WriteStringValue(value.ToString(serializationFormat));}
This is the DateOnlyConverter class that does the obvious. And here is the TimeOnlyConverter class.
public class TimeOnlyConverter : JsonConverter<TimeOnly>{private readonly string serializationFormat;public TimeOnlyConverter() : this(null){}public TimeOnlyConverter(string? serializationFormat){this.serializationFormat = serializationFormat ?? "HH:mm:ss.fff";}public override TimeOnly Read(ref Utf8JsonReader reader,Type typeToConvert, JsonSerializerOptions options){var value = reader.GetString();return TimeOnly.Parse(value!);}public override void Write(Utf8JsonWriter writer, TimeOnly value,JsonSerializerOptions options)=> writer.WriteStringValue(value.ToString(serializationFormat));}
You would then add this to your Startup.cs if its an old style .NetCore app:
public void ConfigureServices(IServiceCollection services){...services.AddControllers().AddJsonOptions(options =>{options.JsonSerializerOptions.Converters.Add(new DateOnlyConverter());options.JsonSerializerOptions.Converters.Add(new TimeOnlyConverter());});...}
Or if you prefer the minimal API way of doing things then:
builder.Services.Configure<JsonOptions>(options =>{
...options.SerializerOptions.Converters.Add(new DateOnlyConverter());options.SerializerOptions.Converters.Add(new TimeOnlyConverter());
...});
After this, you can be on your merry way and DateOnly and TimeOnly won’t be a problem.
Cherrio and God bless.