Monday, June 6, 2011

DateTime serialization issue within a DataSet

For most of our SOAP-based web services we return either simple strings or manually created XmlNodes. We did this to try and make the web services as easy to use with languages other than .NET as possible and because early on we had run into some issues with the built-in serialization code. The built-in serialization is nice when you control both endpoints but if you don't, I've found they can have some unexpected behaviors like below.

For a handful of web services we have a huge variable set of data that needs to be returned. Rather than write a blob of custom serialization code we took the easy way out and return a .NET DataSet (letting the built-in serializer to the work). Things were good until we started to get reports of DateTimes being off when the client-code was calling from a different timezone than the server's timezone. There are two options for the times we return they can be either in UTC or adjusted to a user specified timezone. Neither option was using the server's local time but when the DataSet was unserialized in the client it was being adjusted by the delta between the client and server's timezone.

For example a value in the DataSet might look like the following before serialization:
In the client it would come with a offset specified:

The client code would adjust this to its local time (much like Outlook when you schedule an appointment with someone in a different timezone).

This was a particularly tricky issue to deal with because the delta was between the two different timezones and not some known value like UTC. Since we didn't know what timezone the calling code was in how were we to account for it. This Microsoft KB article suggests as a workaround creating a new web service that the client can call to adjust the times in the DataSet. This seemed to be a really bad idea and knew their had to be a better way.

Thankfully one of the developers on the team found it. The DataColumn objects in the DataSet have a property called DateTimeMode which controls the serialization of times. UnspecifiedLocal is the default which was causing our issues. Switching this to Unspecified allowed the serialization to happen without an offset to be applied. Hooray!

foreach (DataColumn column in table.Columns) {
    if (column.DataType == typeof(DateTime)) {
      column.DateTimeMode = DataSetDateTime.Unspecified;


Anonymous said...

Great solution.
I've placed it inside my serialize function.

Thank you,

Anonymous said...

Thank U Very Much.
It works Perfect!!!!!!!!!!