using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Collections.ObjectModel;
using System.Text.Json.Serialization;
public class DateTimeOffsetConverter : JsonConverter<DateTimeOffset>
const string TZDateFormat = "O";
public override void Write(Utf8JsonWriter writer, DateTimeOffset value, JsonSerializerOptions options) =>
writer.WriteStringValue(value.ToString(TZDateFormat, CultureInfo.InvariantCulture));
const string _date = "_date";
public override DateTimeOffset Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
switch (reader.TokenType)
case JsonTokenType.String:
return DateTimeOffset.ParseExact(reader.GetString(), TZDateFormat, CultureInfo.InvariantCulture);
case JsonTokenType.StartObject:
using var doc = JsonDocument.ParseValue(ref reader);
if (doc.RootElement.TryGetProperty(_date, out var value))
return DateTimeOffset.ParseExact(value.GetString(), TZDateFormat, CultureInfo.InvariantCulture);
return default(DateTimeOffset);
throw new JsonException();
public class DateTimeOffsetConverter2 : JsonConverter<DateTimeOffset>
const string TZDateFormat = "O";
public override void Write(Utf8JsonWriter writer, DateTimeOffset value, JsonSerializerOptions options) =>
writer.WriteStringValue(value.ToString(TZDateFormat, CultureInfo.InvariantCulture));
class DateTimeOffsetDTO { public string _date { get; set; } }
public override DateTimeOffset Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
switch (reader.TokenType)
case JsonTokenType.String:
return DateTimeOffset.ParseExact(reader.GetString(), TZDateFormat, CultureInfo.InvariantCulture);
case JsonTokenType.StartObject:
var dto = JsonSerializer.Deserialize<DateTimeOffsetDTO>(ref reader);
return DateTimeOffset.ParseExact(dto._date, TZDateFormat, CultureInfo.InvariantCulture);
throw new JsonException();
public class DateTimeOffsetConverter3 : JsonConverter<DateTimeOffset>
const string TZDateFormat = "O";
public override void Write(Utf8JsonWriter writer, DateTimeOffset value, JsonSerializerOptions options) =>
writer.WriteStringValue(value.ToString(TZDateFormat, CultureInfo.InvariantCulture));
static byte [] _date = Encoding.UTF8.GetBytes("_date");
public override DateTimeOffset Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
switch (reader.TokenType)
case JsonTokenType.String:
return DateTimeOffset.ParseExact(reader.GetString(), TZDateFormat, CultureInfo.InvariantCulture);
case JsonTokenType.StartObject:
DateTimeOffset? value = null;
switch (reader.TokenType)
case JsonTokenType.EndObject:
return value.GetValueOrDefault();
case JsonTokenType.PropertyName:
var match = reader.ValueTextEquals(_date);
value = DateTimeOffset.ParseExact(reader.GetString(), TZDateFormat, CultureInfo.InvariantCulture);
throw new JsonException();
throw new JsonException();
public class DateTimeOffsetDTO { public DateTimeOffset _date { get; set; } }
public DateTimeOffsetDTO end { get; set; }
public DateTimeOffset end { get; set; }
public static void Test()
Test<DateTimeOffsetConverter>();
Test<DateTimeOffsetConverter2>();
Test<DateTimeOffsetConverter3>();
public static void Test<DateTimeOffsetConverter>() where DateTimeOffsetConverter : JsonConverter<DateTimeOffset>, new()
end = new ModelOut.DateTimeOffsetDTO { _date = DateTimeOffset.Parse("2021-04-07T18:18:00.000Z", CultureInfo.InvariantCulture) },
var options = new JsonSerializerOptions
Converters = { new DateTimeOffsetConverter() },
var json = JsonSerializer.Serialize(model, options);
var model2 = JsonSerializer.Deserialize<Model>(json, options);
Assert.AreEqual(model.end._date, model2.end);
public static void Main()
Console.WriteLine("Environment version: {0} ({1})", System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription , GetNetCoreVersion());
Console.WriteLine("System.Text.Json version: " + typeof(JsonSerializer).Assembly.FullName);
Console.WriteLine("Failed with unhandled exception: ");
public static string GetNetCoreVersion()
var assembly = typeof(System.Runtime.GCSettings).GetTypeInfo().Assembly;
var assemblyPath = assembly.Location.Split(new[] { '/', '\\' }, StringSplitOptions.RemoveEmptyEntries);
int netCoreAppIndex = Array.IndexOf(assemblyPath, "Microsoft.NETCore.App");
if (netCoreAppIndex > 0 && netCoreAppIndex < assemblyPath.Length - 2)
return assemblyPath[netCoreAppIndex + 1];