System.Text.Json DateTime & DateTimeOffset “\/Date()\/” serialization

Part of the series: Fun with System.Text.Json

I was working on porting some code to .NET Core that has to call a whole bunch of external services. The external dependencies are all over the map, .NET Core, Web API, WCF, and some stuff I’m not even sure what it is using. One of those services is using the old Microsoft Date format which looks like:

{
	"Date": "\/Date(1580803200000-0800)\/"
}

What we’re looking at is a DateTimeOffset represented by the number of milliseconds since the Unix Epoch and an optional time zone offset.

Let’s go on a tangent for a moment.

When I’m interviewing people who mention REST or JSON I love to ask them: What are the basic types supported in JSON? The answers are usually surprising and, sometimes, very entertaining. Because JSON doesn’t really support a lot of types. The shortlist: object, array, string, number, boolean, and null. I’m sure many will argue the question is unfair because it’s testing people’s reference recall when–practicality speaking–Google is available at all times to augment our recall, but the list is so short it’s easy to remember. I’m actually not interested in the recall part of it, what I’m really trying to figure out is: Has this candidate worked in a mixed-technology enterprise where real data is being moved around, or have they made services for their own frontend? In my opinion, if you’ve done anything non-trivial with JSON, you’ve run into the lack of binary and/or date[time] support and this list is now 3D printed into your grey matter. For me, it’s a quick way to gauge the depth of experience someone has had stitching services together.

Anyway, supporting binary data (byte[]) is pretty simple, we Base64 encode it and transmit as strings. Dates are a different story. Once upon a time, there wasn’t a consensus, and Microsoft gave birth to this “\/Date()\/” standard. This is what we’re dealing with in this case. Since then, everyone has pretty much standardized around ISO 8601. If you’re reading this, you are probably talking to an old legacy service using the short-lived format and it’s blowing up your System.Text.Json parser.

Don’t worry, I’ve got your back and I have already created a couple JsonConverters to deal with Dates being transported in the old Microsoft format. Check out: JsonMicrosoftDateTimeConverter & JsonMicrosoftDateTimeOffsetConverter. Both available in Macross.Json.Extensions.

Usage is simple:

public class TestClass
{
	[JsonConverter(typeof(JsonMicrosoftDateTimeConverter))]
	public DateTime DateTime { get; set; }

	[JsonConverter(typeof(JsonMicrosoftDateTimeConverter))]
	public DateTime? NullableDateTime { get; set; }

	[JsonConverter(typeof(JsonMicrosoftDateTimeOffsetConverter))]
	public DateTimeOffset DateTimeOffset { get; set; }

	[JsonConverter(typeof(JsonMicrosoftDateTimeOffsetConverter))]
	public DateTimeOffset? NullableDateTimeOffset { get; set; }
}

Note:

You can also add an instance to your JsonSerializerOptions.Converters collection if you have some kind of static options instance dialed in. If your choice is between using the attributes and newing up an options instance each call to the engine, go with the attributes, friends. System.Text.Json builds a cache of all your types at runtime so the attribute route will be faster than allocating new options each time you need to do work.

Reproduced from my post on TimeSpan serialization.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.