The JSON value could not be converted to System.DateTime

By FoxLearn 3/14/2025 3:19:03 AM   132
When using System.Text.Json to deserialize a DateTime value, an error occurs if the value is not in the expected format. The default expected format is the ISO-8601-1:2019 format, such as 2025-03-12T12:35:34+00:00.

For example, consider the following code where a DateTime value is being deserialized with an unexpected format:

var eventJson = "{\"HappenedAt\":\"2025-03-26 18:30:41.720\", \"Name\":\"Meltdown\"}";
var sysEvent = JsonSerializer.Deserialize<SystemEvent>(eventJson);

This will result in the following exception:

System.Text.Json.JsonException: The JSON value could not be converted to System.DateTime. Path: $.HappenedAt | LineNumber: 0 | BytePositionInLine: 39.
---> System.FormatException: The JSON value is not in a supported DateTime format.

If you need to deserialize the JSON while retaining the original DateTime format, and cannot change the format, you can resolve this by creating and using a custom JSON converter. The solution is similar for DateTime, DateTime?, DateTimeOffset, and DateTimeOffset?.

Solution: Use a Custom JSON Converter for DateTime

Here’s how to create a custom converter that can handle the deserialization of a DateTime value with your desired format.

Step 1: Subclass JsonConverter

Create a custom JsonConverter by subclassing JsonConverter<DateTime>:

using System.Text.Json;
using System.Text.Json.Serialization;

public class CustomDateTimeConverter : JsonConverter<DateTime>
{
    public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        throw new NotImplementedException();
    }

    public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
    {
        // Only implement this if you need the custom converter for serialization as well
        throw new NotImplementedException();
    }
}

Step 2: Implement the Read() Method

Since you are focusing on deserialization, implement the Read() method. You don’t need to implement Write() unless you plan to use the converter for serialization as well.

In the Read() method, use reader.GetString() to retrieve the DateTime as a string and then parse it. If you want to strictly match a specific format, use DateTime.ParseExact():

public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
    return DateTime.ParseExact(reader.GetString(), "yyyy-MM-dd H:mm:ss.fff", null);
}

Alternatively, if the format is more flexible, you can use DateTime.Parse() to allow parsing a broader range of formats:

public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
    return DateTime.Parse(reader.GetString());
}

However, be cautious with DateTime.Parse(), as it supports a wide variety of formats. To restrict the accepted format, prefer using DateTime.ParseExact().

Step 3: Use the Custom Converter with JsonSerializer

To apply the custom converter, you need to add it to JsonSerializerOptions.Converters. Then, pass the options to JsonSerializer.Deserialize():

var eventJson = "{\"HappenedAt\":\"2025-03-26 18:30:41.720\", \"Name\":\"Meltdown\"}";

var options = new JsonSerializerOptions();
options.Converters.Add(new CustomDateTimeConverter());

var sysEvent = JsonSerializer.Deserialize<SystemEvent>(eventJson, options);

When JsonSerializer encounters the HappenedAt property, it will use the custom converter to properly parse the DateTime value.