Exception from serializer.WriteObject()

The code below fails when the time zone is set to Berlin (+1:00) or beyond.

DateTime Test = new DateTime();

Test = DateTime.MinValue;

Person myPerson = new Person("Chris", "Pietschmann");

// Serialize to JSON

System.Runtime.Serialization.Json.DataContractJsonSerializer serializer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(myPerson.GetType());

MemoryStream ms = new MemoryStream();

serializer.WriteObject(ms, Test); ==========================> Exception thrown here

 

The exception thrown by serializer.WriteObject() is:

System.Runtime.Serialization.SerializationException was unhandled

  Message="DateTime values that are greater than DateTime.MaxValue or smaller than DateTime.MinValue when converted to UTC cannot be serialized to JSON."

  Source="System.ServiceModel.Web"

  StackTrace:

       at System.Runtime.Serialization.Json.JsonWriterDelegator.WriteDateTime(DateTime value)

 

The exception happens from within WriteDateTime() which actually tries to calculate the tickCount using the code below:

long tickCount = value.Ticks - TimeZone.CurrentTimeZone.GetUtcOffset(value).Ticks;

 

The problem occurs when CurrentTimeZone.GetUtcOffset is > 0  So if I set my time zone to Berlin (+1:00) or beyond, it will return a positive number which means that tickcount will return a negative number since value.Ticks == 0 (minValue), resulting in the exception.

There are probably a couple of workarounds to this issue. They are:

1. If you are using DateTime.MaxValue or DateTime.MinValue as the default values for some DateTime variables then a simple workaround is to define some MaxDefaultDateTime and MinDefaultDateTime values that do not overflow when converted to UTC. An example can be:

 static DateTime MaxDefaultDateTime = DateTime.MaxValue.Subtract(TimeSpan.FromHours(12));

static DateTime MinDefaultDateTime = DateTime.MinValue.Add(TimeSpan.FromHours(12));

 and for the sake of completeness, you can have a method that ensures all DateTime values are set correctly, something like:

 static DateTime GetLimitDateTime(DateTime value)        

{

     if (value.Kind != DateTimeKind.Utc)           

     {

        long ticks = value.Ticks - TimeZone.CurrentTimeZone.GetUtcOffset(value).Ticks;

 

        if (ticks > DateTime.MaxValue.Ticks)          

        {

           return MaxDefaultDateTime;

        }

       if (ticks < DateTime.MinValue.Ticks)                

       {

           return MinDefaultDateTime;

       }

    }

    return value;

}

 

2. Another option is to always convert DateTime values to UTC and serialize/de-serialize UTC values:

 DateTime now = DateTime.Now.ToUniversalTime();

DateTime max = DateTime.MaxValue.ToUniversalTime();

DateTime min = DateTime.MinValue.ToUniversalTime();

DateTime value = new DateTime(2000, 12, 31, 20, 0, 0, DateTimeKind.Local).ToUniversalTime();

 static DateTime GetUTCDateTime(DateTime value)

{

  return value.ToUniversalTime();

}

 DateTime time = GetUTCDateTime(DateTime.MinValue);

 

Written By
Shamik Misra
Support Escalation Engineer, Microsoft Developer Support