none
JSON deserialization of a DateTime incorrect?

    Question

  • Hi,

    I've been experimenting with the DateTime deserialization and have some strange behaviour.

    Using this code:

            DataContractJsonSerializer dcjs = new DataContractJsonSerializer(typeof(DateTime));
            DateTime dateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0).ToUniversalTime();
            dcjs.WriteObject(Response.OutputStream, dateTime);

    I would be expecting the response to be:
    \/Date(0)\/
    but am actually getting
    \/Date(-39600000)\/


    Am I missing something here? According to this article http://msdn.microsoft.com/en-us/library/bb299886.aspx#intro_to_json_sidebarb it's meant to be the ticks since 1/1/1970.

    Even the example given - "A date and time in UTC like November 29, 1989, 4:55:30 AM would be written out as "@62831853071@.", using this calculator http://www.epochconverter.com/ does not work.

    Thanks for your help in advance.

    AussieGuy
    Monday, February 23, 2009 11:24 PM

Answers

  • This has to do with the specific DateTimeKind applied to your specific DateTime.  The kind of date represented is specified as either Local, Unspecified or UTC.  Unspecified, when serialized by JSON, defaults to Local, which means, it still has the UTC offset.  UTC does not, for obvious reasons.  There are several solutions to this issue.  One of them (which is one I've used in the past) is to never serialize a date.  Instead, serialize the date to string, and pass the string back and forth, creating a Javascript function to create a new date on the client based on the formatted string.  Obviously, this can get a little hairy.  The other solution is to ensure that all DateTime's created are created as UTC.  There are a few overloads of the DateTime constructor that can accept the DateTimeKind specification.  Either use one of those, or call the static DateTime.SpecifyKind method.  Check the following code for an example of these issues and the result:

    static void Main(string[] args)

    {

     

        DateTime dateTime = new DateTime(2000, 1, 1);

     

        // output the original information.

        OutputDate(dateTime);

        // manually change the kind of the datetime.

        dateTime = DateTime.SpecifyKind(dateTime, DateTimeKind.Utc);

     

        // output the new information.

        OutputDate(dateTime);

     

        Console.ReadLine();

    }

     

    static void OutputDate(DateTime dateTime)

    {

        Console.WriteLine("{0} Time: {1}\tUTC: {2}",

            dateTime.Kind.ToString().PadRight(12, ' '),

            dateTime, dateTime.ToUniversalTime());

        Console.WriteLine("Serialized value: {0}", GetSerializedString(dateTime));

        Console.WriteLine();

    }

     

    static string GetSerializedString(DateTime dt)

    {

        string result = null;

        DataContractJsonSerializer dcjs = new DataContractJsonSerializer(typeof(DateTime));

        using (MemoryStream ms = new MemoryStream())

        {

            dcjs.WriteObject(ms, dt);

            ms.Position = 0;

            using (StreamReader reader = new StreamReader(ms))

            {

                result = reader.ReadToEnd();

            }

        }

        return result;

    } 


    David Morton - http://blog.davemorton.net/
    • Proposed as answer by Harry Zhu Friday, February 27, 2009 7:20 AM
    • Marked as answer by Harry Zhu Monday, March 02, 2009 3:28 AM
    Tuesday, February 24, 2009 2:33 PM

All replies

  • Ok, so that actually does make sense as i'm in a +11 hour offset from UTC .. so i'll refrase the question to that of the original bug I had.

    Say for example that I change the date to 1/1/2000

            DataContractJsonSerializer dcjs = new DataContractJsonSerializer(typeof(DateTime));
            DateTime dateTime = new DateTime(2000, 1, 1);
            dcjs.WriteObject(Response.OutputStream, dateTime);

    The result I get is:

    "\/Date(946645200000+1100)\/"

    Placed into the calculator I provided above that ticks translates into

    GMT: Fri, 29 Dec 31967 16:00:00 GMT
    Your timezone: Saturday, 30 December 31967 3:00:00 AM

    Which is not 11 hours offset.

    If you remove the last 3 digits from the end then you get the correct ticks, and that appears to work in all cases, but the question is why?

    Cheers,

    AussieGuy
    Tuesday, February 24, 2009 12:04 AM
  • This has to do with the specific DateTimeKind applied to your specific DateTime.  The kind of date represented is specified as either Local, Unspecified or UTC.  Unspecified, when serialized by JSON, defaults to Local, which means, it still has the UTC offset.  UTC does not, for obvious reasons.  There are several solutions to this issue.  One of them (which is one I've used in the past) is to never serialize a date.  Instead, serialize the date to string, and pass the string back and forth, creating a Javascript function to create a new date on the client based on the formatted string.  Obviously, this can get a little hairy.  The other solution is to ensure that all DateTime's created are created as UTC.  There are a few overloads of the DateTime constructor that can accept the DateTimeKind specification.  Either use one of those, or call the static DateTime.SpecifyKind method.  Check the following code for an example of these issues and the result:

    static void Main(string[] args)

    {

     

        DateTime dateTime = new DateTime(2000, 1, 1);

     

        // output the original information.

        OutputDate(dateTime);

        // manually change the kind of the datetime.

        dateTime = DateTime.SpecifyKind(dateTime, DateTimeKind.Utc);

     

        // output the new information.

        OutputDate(dateTime);

     

        Console.ReadLine();

    }

     

    static void OutputDate(DateTime dateTime)

    {

        Console.WriteLine("{0} Time: {1}\tUTC: {2}",

            dateTime.Kind.ToString().PadRight(12, ' '),

            dateTime, dateTime.ToUniversalTime());

        Console.WriteLine("Serialized value: {0}", GetSerializedString(dateTime));

        Console.WriteLine();

    }

     

    static string GetSerializedString(DateTime dt)

    {

        string result = null;

        DataContractJsonSerializer dcjs = new DataContractJsonSerializer(typeof(DateTime));

        using (MemoryStream ms = new MemoryStream())

        {

            dcjs.WriteObject(ms, dt);

            ms.Position = 0;

            using (StreamReader reader = new StreamReader(ms))

            {

                result = reader.ReadToEnd();

            }

        }

        return result;

    } 


    David Morton - http://blog.davemorton.net/
    • Proposed as answer by Harry Zhu Friday, February 27, 2009 7:20 AM
    • Marked as answer by Harry Zhu Monday, March 02, 2009 3:28 AM
    Tuesday, February 24, 2009 2:33 PM