Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
Markdown Monster - The Markdown Editor for Windows

Watch out for Date Kind in JSON Deserialization


:P
On this page:

If you're working with dates that have been sent from the client encoded in JSON format, and you're using a JSON parser to handle the parsing for you make sure you deal carefully with date values. The various JSON serializers out there handle date formatting slightly differently and this can make a subtle difference that you might not immediately notice when dates are retrieved from the JSON.

Specifically the issue is that Microsoft JSON deserializers - JavaScriptSerializer and DataContractJsonSerializer - return dates as Utc style dates.

This can result in what appears to be  strange results when you run code that handles both encoding and decoding:

[TestMethod]
public void DateTest()
{
    DateTime date = DateTime.Now.AddDays(-10);

    JavaScriptSerializer sr = new JavaScriptSerializer();
    string json = sr.Serialize(date);
    DateTime retrieved =  sr.Deserialize<DateTime>(json);

    Assert.AreEqual(retrieved, date, "Date failed to deserialize");
}

This code will fail because the dates are off by the timezone offset difference between the Utc date and the local time. So to be safe it's a good idea to always convert the date to the proper date kind before using it to be sure you have the right date context. The following should work reliably:

Assert.AreEqual(retrieved.ToLocalTime(),date, "Date failed to deserialize");

or using .ToUtcTime() if you expect the date to be in Utc. Explicitly forcing the date to a specific DateKind is a good idea just to make sure if you end up switching parsers in the future.

The reasoning behind this makes some sense - the JSON encoded value is actually a tick count that is given in UTC and since there's no information on what kind of date you are dealing with the date returned is always in Utc. Of course the .NET code can make a decision to return the date in any format it chooses but the parsed raw date tends to be in Utc first.

Still returning Utc seems very inconsistent - what API (except explicit Utc related/named methods) returns a UTC date? The above behavior might be very unexpected and worse often go undetected for some time until somebody carefully checks captured data because the date values will be close to right but just off by the timezone offset.

In any case it's probably a good idea to always force dates returned from JSON to the appropriate date kind just to be safe.

BTW, I'm happy to see Microsoft removed the 'Deprecated' tag from the System.Web.Extensions.JavaScriptSerializer class. Although DataContractJsonSerializer was supposed to supercede DataContractSerializer, the interface and pre-requisites for JSON serialization tend to be easier and more flexible using the JavaScriptSerializer.

Posted in ASP.NET  

The Voices of Reason


 

KierenH
May 18, 2009

# re: Watch out for Date Kind in JSON Deserialization

You're a legend with these date posts Rick. There's definately potential for alot of pain.

Martin
June 12, 2013

# re: Watch out for Date Kind in JSON Deserialization

There is one more issue.

If you pass the data to the JavaScriptSerializer.Deserialize in the form as it was serialized: "\/Date(286769410010)\/"
you get UTC time (even if the 286769410010 has some additional timezone info like +0400).

But if you have some Javascript component (for example JSON.stringify) which sends DateTime values in the following way:
1979-02-02T02:10:10Z
it will be converted to the local time, which is completely unexpected. We had to do a Regex to replace all of our "1979-02-02T02:10:10Z" format strings to the strings expected by JavaScriptSerializer to fix this issue.

West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2024