Introduction
Despite the fact that WCF technology is powerful and flexible, there are some areas requiring improvement. In this article, I'll show issues related to webservice date format interoperability and how it can be solved.
Background
My company is a financial institution which has many different applications exchanging data. Most of these applications are implemented in Java while mine exposes webservice implemented in WCF .NET.
To exchange dates, I’ve proposed an xs:dateTime
format. This is because then I was not aware about the peculiarities of this type.
First issue: UTC format. When I was testing webservice with soapUI, I entered manually 1969-03-17T00:00:00.000+01:00
as an input argument for 1969-03-17
date of birth. Everything was fine. However when the actual webservice client sent 1969-03-16T23:00:00.000Z
(equivalent datetime in UTC format), then it appeared that .NET treated this as 1969-03-16
date (one day shift).
One more explanation: I’m working in Poland, so the winter time is GMT+1 and summer time is GMT+2 CET zone with daylight savings time.
So it looks like UTC time is not correctly handled. Fortunately, a simple workaround exists:
if (date.Kind == DateTimeKind.Utc)
date = date.ToLocalTime()
Second, more difficult issue is the following: For some date values, different frameworks have different representation. For example, my WCF webservice got 1941-12-05T00:00:00.000+02:00
. Java client intent was to send 1941-12-05
date while .NET service treats this as a 1941-12-04
. We’ve found that about 5% of dates had similar issue. Most of these dates were from 40s but not only. A possible explanation is that daylight saving time was not used in 40s. Or maybe one framework used Germany's daylight saving time for II WW period?
If you start thinking about the daylight time differences between frameworks, then the idea of representing dates in this way becomes just crazy. So frameworks have to remember historical dates of daylight time period? Do they take into account historical accidents like changing borders (and timezones)? Where is it documented? What to do if algorithms differ? What parameters have influence on TZ interpretation? We know that most important are regional setting on Windows. How about Linux, AIX? Do all servers have correct and compatible settings?
Ok, so xs:dateTime
is not a good option because of differences between frameworks. What are the other alternatives? What about xs:string
? Unfortunately, this is also not a good option: there are plenty of different formats in use: dd-MM-yyyy, yyyy-MM-dd, yyyyMMdd, … . In some scenarios, it is ok – for example one webservice for one client. For some, it is not sufficient: when webservices from multiple systems are reused on ServiceBus
to create new webservice, then all must agree to one format. Sometimes however, the format can’t be changed because many clients are using it.
The best option would be to use xs:date
without timezones (option available for xs:date
). However in WCF, this is not supported. I’ve Googled much and haven’t found a satisfactory solution. Ok, I’ve found that one can force WCF to use XmlSerializer
which is able to use xs:date
. But I prefer to use DataContractSerializer
because of other reasons. And most important: XmlSerializer
will not handle xs:date
for simple service parameters. XmlSerializer
requirement is that date has to be a property of the object.
So what is my proposal? I found the following solution: custom-made xs:date
. It’s not as complicated as it seems.
Using the Code
I’ve defined my own type – WcfDate
which implements IXmlSerializable
interface. It is enough to use that type instead of DateTime
in .NET code in Service Contract.
For example:
[ServiceContract]
public interface IService1
{
[OperationContract]
string GetData(WcfDate value);
[OperationContract]
CompositeType GetDataUsingDataContract(CompositeType composite);
}
[DataContract]
public class CompositeType
{
bool boolValue = true;
string stringValue = "Hello ";
WcfDate dateValue = new WcfDate(DateTime.Today);
[DataMember]
public bool BoolValue
{
get { return boolValue; }
set { boolValue = value; }
}
[DataMember]
public string StringValue
{
get { return stringValue; }
set { stringValue = value; }
}
[DataMember]
public WcfDate DateValue
{
get { return dateValue; }
set { dateValue = value; }
}
}
WcfDate
is rendered as xs:date
in soap envelop during runtime. I’ve also added some extension methods to make easy conversion between WcfDate
and DateTime
. For example, it is possible to increment incoming date in one line:
composite.DateValue = composite.DateValue.GetDate().AddDays(1).ToWcfDate();
All details are in the attached code: WcfCommon
project provides WcfDate
type and WsdlDocumentation
attribute (copied from Microsoft samples) and WcfSampleService
shows how to use WcfDate
.
Shortcomings
xs:date
is not supported on client side when you generate proxy. Element xs:date
is treated then as xs:string
. Client has to parse date
by itself but still it is better than before because xs:date
enforces standard date
layout.
Further Conclusions
Date
type is very useful. It exists in most databases including SQL Server and in many frameworks and languages (although not all). Our life would be easier if Microsoft supported it in WCF and in the .NET Framework natively.
History
- 15th April, 2011: Initial version