WCF: DateTime localization challenge
Issue
1. Client desktop application consumes WCF service.
2. WCF service communicates with SQL database in the background.
3. Client application passes DateTime value in local time zone.
4. WCF service receives the DateTime value (Dataset was the wrapping type) in UTC.
5. Hence, SQL database stores the propagated DateTime value in UTC.
6. My customer’s requirement was to store the DateTime value in client local time zone value in the SQL. When client is to receive any response from WCF service, it should retrieve the value in client local time zone.
Assessment
Generally, DateTime field is serialized in UTC across time zones.
In web service world, it is a recommendation practice. There can be clients from multiple time zones communicating with the web service. To have unique results (consistency in format) on the backend, it is always serialized in UTC rather than having time zone confusion.
Workaround discussion
It is harder to work around this problem in WCF or Web Services - some options for using a UTC or a whole date with services.
1. Internally use the data as a DateTime, but serialize it either as a String using the format mentioned above or as an Int64 tick count.
2. Call DateTime.ToLocalTime on the DateTime before putting it in the serializable class and call DateTime.ToUniversalTime after taking it out. This will effectively “cancel out” the adjustment, and can be used whether you are dealing with a whole date or a UTC time.
3. For whole dates where you do not need to serialize the time portion, you can change the XML schema to indicate that it is a date rather than a date and time, which will change the format to “yyyy-MM-dd”, which will serialize correctly.
4. For UTC times, you can have an extra property on the class that exists for serialization only. This work-around is outlined in this article.
5. Make all machines use the same time zone.
6. If you have a chance to pre-process the XML before it is sent out, you can manually strip out the time zone offset out of the XML text.
For example, a typical XML date and time looks like this: “2005-01-28T03:14:42.0000000-07:00”. You can use a Regex to remove the “-07:00”. You do not need to re-inject anything on the other end, as no adjustment is made if there is no time zone information. Do not try to replace the time zone offset with “Z” or “+00:00”. While technically a more correct representation, the existence of time zone information will cause the serializer to do an extra conversion to local.
Solution
It is possible to modify the DateTimeMode between UnspecifiedLocal and Unspecified because that only affects serialization and not the actual value.
After every serialization and deserialization (in WCF service), had put the following section of code for the dataset:
/* iterate (underneath dataset) the columns and set DataColumn.DateTimeMode <br> to DataSetDateTime.Unspecified to remove offset when serialized */
foreach (DataTable table in data.Tables)
{
foreach (DataColumn item in table.Columns)
{
// Switching from UnspecifiedLocal to Unspecified is allowed even after the DataSet has rows.
if (item.DataType == typeof(DateTime) && item.DateTimeMode == DataSetDateTime.UnspecifiedLocal)
{
item.DateTimeMode = DataSetDateTime.Unspecified;
}
}
}
Modifying the column’s mode to Unspecified results in a DateTime value with no offset. This value now matches the database record exactly. This leaves the problem of formatting the value for display completely up to the client-side application.
Important references Work around problems serializing DateTime DateTime, Serialization and TimeZones Coding best practices using DateTime
Happy Coding!