STJ doesn't handle nulls, empty strings, or anything really bizarre correctly. That means there are a ton of gotchas in every single STJ implementation. My options looks like this:
public static JsonSerializerOptions AddOptions(this JsonSerializerOptions options)
{
if (options == null)
{
options = new JsonSerializerOptions();
}
options.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
options.PropertyNameCaseInsensitive = true;
options.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
options.NumberHandling = JsonNumberHandling.AllowReadingFromString;
options.Converters.Add(new DateTimeConverter());
options.Converters.Add(new NullableDateTimeConverter());
options.Converters.Add(new NullableIntConverter());
options.Converters.Add(new NullableLongConverter());
options.Converters.Add(new NullableDecimalConverter());
options.Converters.Add(new BooleanConverter());
options.Converters.Add(new JsonStringEnumConverter());
return options;
}
It would be used like this:
services.AddMvc(options => options.EnableEndpointRouting = false).AddJsonOptions(o => JsonExtensions.AddOptions(o.JsonSerializerOptions));
This is a preface to WHY the accepted answer may not be wholly correct. First, deserialization from null and empty strings simply won't work. Second, deserialization from slashes in the date simply won't work. Third, deserialization from a string with Z at the end may throw errors in times: var myDate = "2023-12-01T01:00:00Z"; with a simple DateTime.Parse may result in a 2023-11-30 timeframe because timezones. Therefore, I recommend trying the default UTFJsonReader, if it doesn't work, then in the catch use DateTimeOffset. The DateTimeOffset will not allow you to specify the Kind on it. So, create a new DateTime, specifying that it is UTC instead of unspecified and then you can convert back and forth without further issue.
public class DateTimeConverter : JsonConverter<DateTime>
{
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
try
{
return reader.GetDateTime();
}
catch
{
if (reader.TokenType == JsonTokenType.String)
{
var info = reader.GetString();
var offset = DateTimeOffset.Parse(reader.GetString() ?? string.Empty);
if (info?.ToLower()?.EndsWith('z') == true)
{
return new DateTime(offset.DateTime.Ticks, DateTimeKind.Utc);
}
return offset.DateTime;
}
throw;
}
}
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
{
writer.WriteStringValue(value);
}
}
I realize my above information does not answer wholly your question... but it does show you where you can do these kinds of things and just how undeveloped but customizable STJ is. For example for your shenanigans:
writer.WriteStringValue(value.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ssZ")); //why do you hate me?
Z
is appended to the string. A local time will include the local timezone offset – Supplejack