Click here to Skip to main content
15,880,891 members
Articles / Programming Languages / C#
Article

How to fix DateTime values after .NET Xml Serialization

Rate me:
Please Sign up or sign in to vote.
3.40/5 (4 votes)
15 Sep 20043 min read 117.8K   2   25   10
This will explain what happens when you use the .NET XmlSerializer class directly or indirectly (via .NET Remoting or Web Service calls) to send DataTables with DateTime values in them across different time zones. .NET framework automatically converts the values to the caller's timezone.

Introduction

The new .NET technologies, Remoting and Web Services has made life much easier than the days of trying to get DCOM to work. Although with anything that has been made easier there are some details that have been made too easy. In the case of Remoting or calling a web service, the Microsoft .NET Framework includes an automatic feature that converts all returned DataTables with DateTime values to the caller's time zone. So if you're in Seattle and need to find out a certain DateTime value in a database table row (let's say sale_date) on a server that runs in New York City you can make a web service call to find out. What happens is the sale_date value may have a value of 8/22/2004 9:05 am on the server in New York, but your web service call will result in a value of 8/22/2004 6:05 am. Which is clearly wrong. This article will tell you how to fix this problem.

Background

The problem seems to only occur whenever you send a DataTable as a return value. This is because .NET Framework will automatically serialize the DataTable into xml using it's System.Xml.Serialization.XmlSerializer class. The XmlSerializer will convert the DateTime values upon deserialization on the client. The idea here is to take control of the xml serialization process and manipulate the xml using regular expressions to give us the correct result.

Using the code

1. In the web service we first need to convert the DataTable to an xml string and send back the string. We use the System.IO.StringWriter class to write out the xml string:

C#
using System.Data;
using System.IO;
using System.Web.Services;
...
namespace NYDataServices
{
...
// Web service is running in New York City
public class MyWebService : System.Web.Services.WebService
{
...

[WebMethod]
public string GetData()
{
  DataTable dataTable = null;
  // Get data from database as a DataTable
  ...

  // Now convert the DataTable to an xml string and return it to client
  return convertDataTableToString( dataTable );
}

private string convertDataTableToString( DataTable dataTable )
{
  DataSet dataSet = new DataSet();
  dataSet.Tables.Add( dataTable );
  StringWriter writer = new StringWriter();
  dataSet.WriteXml( writer, XmlWriteMode.WriteSchema );

  return writer.ToString();
}

2. On the client side we make the call to get the data and receive the data as an xml string.

C#
using System.Data;
using System.Text.RegularExpressions;
...
namespace SeattleClient
{
...
// Client program running in Seattle
public class MyClient : System.Windows.Form
{
...

public void GetDataFromServer()
{
  NYDataServices.MyWebService ws = new NYDataServices.MyWebService();
  string xmlString = ws.GetData();
  DataTable dataTable = convertStringToDataTable( xmlString );
  // Do something with dataTable
  ...
}

3. Converting the xml string back to a DataTable requires the use of regular expressions to search, adjust time values and replace. The DateTime values take on the form of 2004-08-22T00:00:00.0000000-05:00. The last 5 characters in the string indicate the UTC (Universal Time Coordinate) time. During xml deserialization back into a DataTable, the XmlSerializer class reads this value and creates an offset value based on the client's UTC time. It then adds this offset into all DateTime values upon deserialization. The kicker here is that if the DateTime value happens to be on DST (Daylight Savings Time) and the client is not on DST it will adjust for this too. We use some of the magic of the System.Text.RegularExpression namespace such as the Regex.Replace() function, Match class and MatchEvaluator delegate.

C#
private DataTable convertStringToDataTable( string xmlString )
{
 // Search for datetime values of the format
 // --> 2004-08-22T00:00:00.0000000-05:00
 string rp = @"(?<DATE>\d{4}-\d{2}-\d{2})(?<TIME>T\d{2}:\d{2}:\d{2}."+
       "\d{7}-)(?<HOUR>\d{2})(?<LAST>:\d{2})";
 // Replace UTC offset value
 string fixedString = Regex.Replace( xmlString, rp,
      new MatchEvaluator( getHourOffset ) );

 DataSet dataSet = new DataSet();
 StringReader stringReader = new StringReader( fixedString );
 dataSet.ReadXml( stringReader );

 return dataSet.Tables[ 0 ];
}

private static string getHourOffset( Match m )
{
 // Need to also account for Daylights Savings
 // Time when calculating UTC offset value
 DateTime dtLocal = DateTime.Parse( m.Result( "${date}" ) );
 DateTime dtUTC = dtLocal.ToUniversalTime();
 int hourLocalOffset = dtUTC.Hour - dtLocal.Hour;
 int hourServer = int.Parse( m.Result( "${hour}" ) );
 string newHour = ( hourServer + ( hourLocalOffset -
     hourServer ) ).ToString( "0#" );
 string retString = m.Result( "${date}" + "${time}" +
    newHour + "${last}" );

 return retString;
}

Points of Interest

I know this problem happens when sending back DataTables. I'm not sure if the same applies to custom classes, although I suspect it does.

Here are links that I found very useful --

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralModificaciones por Zona Horaria con minutos gmt (+05:45) o 05:30 [modified] Pin
javierace22-Apr-10 9:19
javierace22-Apr-10 9:19 
QuestionHow to fix DateTime values BEFORE .NET Xml Serialization (without additional parsing, etc.) Pin
cjgin8-Jun-09 19:20
cjgin8-Jun-09 19:20 
AnswerIs it really works? Pin
McSdwarken14-Oct-09 23:12
McSdwarken14-Oct-09 23:12 
GeneralRe: Is it really works? [modified] Pin
sanme9830-Dec-09 1:12
sanme9830-Dec-09 1:12 
AnswerRe: How to fix DateTime values BEFORE .NET Xml Serialization (without additional parsing, etc.) Pin
kilkfoe126-Mar-10 10:46
kilkfoe126-Mar-10 10:46 
Generalbug in fixup code [modified] Pin
VroDAX3-Aug-06 8:10
VroDAX3-Aug-06 8:10 
GeneralCreate datetime in C#,ASP.NET Pin
hvan22036-Apr-05 22:02
hvan22036-Apr-05 22:02 
GeneralCreate datetime in C#,ASP.NET Pin
hvan22036-Apr-05 22:00
hvan22036-Apr-05 22:00 
Generalfixup - be careful Pin
Anonymous4-Oct-04 8:57
Anonymous4-Oct-04 8:57 
regarding "fixing up" DateTime values.

I disagree that it is clearly wrong that a value of "8/22/2004 9:05 am" in New York is different than a value of "8/22/2004 6:05 am" in Seattle. In fact, they are the same moment in time.

An alternative to using Regex and string manipulation to "fix it up", is to (a) consider timezone in calculations, and (b) format the Date in the preferred timezone when necessary. In other words, if you want to look at the moment in time described by "8/22/2004 6:05 am in Seattle", formatted for the New York timezone, then just format it differently. . .

here is a thread on the issue:

http://tinyurl.com/3qnkk[^]


and a code sample to illustrate:

http://www.winisp.net/cheeso/srcview.aspx?dir=xml-serialization&file=DateTime.cs[^]
GeneralRe: fixup - be careful Pin
bobddddd4-Oct-04 9:56
bobddddd4-Oct-04 9:56 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.