Newtonsoft.json: IsoDateTimeConverter - always append Z or explicit timezone, to avoid browser incompatibilities

Created on 13 Dec 2013  路  5Comments  路  Source: JamesNK/Newtonsoft.Json

Due to an issue in ES5.1, browsers have different interpretations of ISO-8601 dates that are missing a trailing timezone (neither 'Z' nor explicit timezone value).

Currently, IsoDateTimeConverter does not set 'Z' when serializing a DateTime object that was created without a DateTimeKind.UTC parameter:

var date = new DateTime(2009, 2, 15, 0, 0, 0, DateTimeKind.Local);
var settings = new JsonSerializerSettings();
settings.Converters.Add(new IsoDateTimeConverter());

// Succeeds
Assert.IsTrue(JsonConvert.SerializeObject(date.ToUniversalTime(), settings).EndsWith("Z\""));

// Fails
Assert.IsTrue(JsonConvert.SerializeObject(date, settings).EndsWith("Z\""));

To make it easier to work with output from Json.NET, it should always append the 'Z' (or set an explicit timezone) when converting dates to strings in IsoDateTimeConverter.

The easiest fix is to use the result of .ToUniversalTime() on each date object when serializing it (as shown above).

Most helpful comment

I was thrown off by this because the documentation page shows it does append a trailing Z:

http://www.newtonsoft.com/json/help/html/DatesInJSON.htm

Shows: "Details":"Application started.","LogDate":"2009-02-15T00:00:00Z" ... But the actual output is not that - It does not have a trailing Z. I was able to get the Z without calling ToUniversalTime by settings this option in the serializer settings:

_jsonSettings.DateTimeZoneHandling = DateTimeZoneHandling.Utc;

Probably just a documentation issue.

All 5 comments

This is a subtle breaking change that will sting a lot of people who rely on the current behavior. If you want to change DateTime serialization I suggest you create your own JsonConverter.

I agree that this isn't really a JSON.Net issue, but it would be nice to not have to deal with it. How about adding it as an optional, non-breaking feature (perhaps a flag on the IsoDateTimeConverter?) I wasted time researching this browser-dependent implementation detail and more time on figuring out how to solve it when using JSON.Net.

Furthermore, having the browser misinterpret your DateTime is the kind of bug that can easily go by unnoticed. People could have this bug without even knowing about it. Exposing this as a feature gives them both the opportunity to learn about it, and a way to get around it.

I've just noticed this issue. Whatever about not changing the implementation, it should be in the documentation at the very least.

Taken from http://en.wikipedia.org/wiki/ISO_8601#Time_zone_designators:

"Time zones in ISO 8601 are represented as local time (with the location unspecified), as UTC, or as an offset from UTC.

If no UTC relation information is given with a time representation, the time is assumed to be in local time. While it may be safe to assume local time when communicating in the same time zone, it is ambiguous when used in communicating across different time zones. It is usually preferable to indicate a time zone (zone designator) using the standard's notation."

I was thrown off by this because the documentation page shows it does append a trailing Z:

http://www.newtonsoft.com/json/help/html/DatesInJSON.htm

Shows: "Details":"Application started.","LogDate":"2009-02-15T00:00:00Z" ... But the actual output is not that - It does not have a trailing Z. I was able to get the Z without calling ToUniversalTime by settings this option in the serializer settings:

_jsonSettings.DateTimeZoneHandling = DateTimeZoneHandling.Utc;

Probably just a documentation issue.

@grennis , the docs are maybe unclear but not incorrect. It doesn't say that it always appends a Z, it says it uses the ISO format. That is, Z for UTC dates, but not all dates are UTC.

It later states:

set DateTimeZoneHandling to Utc to serialize all DateTimes as UTC dates

Which implies that non-UTC dates will not be serialized as UTC dates. :)

Was this page helpful?
0 / 5 - 0 ratings