Udostępnij za pośrednictwem


JSON Serialization / Deserialization of DateTime Not Equal

I recently used the DataContractJsonSerializer to serialize a class. I noticed that for a DateTime field, the deserialized result appeared identical to the original value, but the equals operator failed.  The following simple program reproduced the problem.

 using System;
using System.Runtime.Serialization.Json;
using System.IO;
using System.Runtime.Serialization;

public static class JsonHandler {
    public static byte[] SerializeToJsonBytes(object obj) {
        DataContractJsonSerializer dcjs = new DataContractJsonSerializer(obj.GetType());
        MemoryStream ms = new MemoryStream();
        dcjs.WriteObject(ms, obj);
        ms.Close();
        return ms.ToArray();
    }

    public static T DeserializeFromJson<T>(byte[] buff)
        where T : class {
        MemoryStream ms = new MemoryStream(buff);
        DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
        T obj = serializer.ReadObject(ms) as T;
        ms.Close();
        return obj;
    }

}
    [DataContract]
    public class Foo {
        [DataMember]
        public DateTime dt;

        public Foo(DateTime dt) {
            this.dt = dt;
        }

        public bool Equals(Foo p) {

            if ((object)p == null) {
                return false;
            }
            return (p.dt == dt);
        }
    }


class Program {

    static void Main(string[] args) {
        var f1 = new Foo(DateTime.UtcNow);
        byte[] buff = JsonHandler.SerializeToJsonBytes(f1);
        System.Threading.Thread.Sleep(1500);
        Console.WriteLine(System.Text.Encoding.ASCII.GetString(buff));
        var f2 = JsonHandler.DeserializeFromJson<Foo>(buff);
        byte[] buff2 = JsonHandler.SerializeToJsonBytes(f2);
        Console.WriteLine(System.Text.Encoding.ASCII.GetString(buff2));
        Console.WriteLine("Equals: " + f1.dt.Equals(f2.dt));
    }
}

While the console output was identical, a watch on the Ticks field showed the difference.

Ticks

The JavaScript Date type has a resolution of 1 millisecond, while the .NET DateTime type has a resolution of 100 nanoseconds. You can see in the watch window the last four digits of the deserialized value are zero; only the millisecond information is retained.

JSON serialization isn't intended to preserve full fidelity of information, so this is by design.  If you need to preserve full fidelity, use a different serialized like BinaryFormatter, XmlSerializer, DataContractSerializer, etc.

You can download my sample here. Also included in the download is a Web Forms project that demonstrates this phenomenon. This Web Forms project is a slight modification of the code Rick Strahl posted in his blog entry DataContractJsonSerializer in .NET 3.5. I once overheard a really smart developer here at Microsoft rave over Rick Strahl’s blog.

Special thanks to Levi Broderick for explaining where to look and Eric Fleischman for pointing out the issue.

As always, let me know if this was useful.

Rick.Anderson at Microsoft.com

Comments

  • Anonymous
    February 26, 2012
    You may also be interested in this: connect.microsoft.com/.../723368

  • Anonymous
    March 01, 2012
    This behavior is described in the article at msdn.microsoft.com/.../bb412170.aspx (see section "Date/Times and JSON". Definitely not easy to find, so it's good to have this post (and others) describing the issue as well.