I have a .NET WCF service with a few operation contracts that takes a DateTimeOffset. The idea is to avoid any confusion with DST and time zones.
However I am in doubt that using DateTimeOffset is a good idea after all, since it is fairly non-standard and would cause headaches for anyone trying to connect with, say, a Java application or a .NET application bound to an older .NET version.
An alternative is to expect a UTC DateTime, but this introduces the risk that someone will forget to use UTC time and call the service with a local time. I could also expect a local time DateTime, since clients will always be in the same timezone, but this leaves some subtle, but classic, ambiguity around DST changes.
Does anyone have headache stories with DateTimeOffset in a service interface or is it relatively unproblematic to use after all?
I'm currently changing some of our infrastructure to WCF and stumbled upon this unanswered question and decided to try it. :)
The way that WCF serializes DateTime
and DateTimeOffset
seems to be a bit weird. As the following sample shows, using DateTime
looks like the better option when working with other platforms:
using System;
using System.Runtime.Serialization;
using System.ServiceModel;
[ServiceContract]
public class DateTimeOffsetService
{
[OperationContract]
public Container DoWork()
{
return new Container
{
NowDateTime = DateTime.Now,
UtcNowDateTime = DateTime.UtcNow,
NowDateTimeOffset = DateTimeOffset.Now,
UtcNowDateTimeOffset = DateTimeOffset.UtcNow
};
}
}
[DataContract]
public class Container
{
[DataMember]
public DateTime NowDateTime { get; set; }
[DataMember]
public DateTime UtcNowDateTime { get; set; }
[DataMember]
public DateTimeOffset NowDateTimeOffset { get; set; }
[DataMember]
public DateTimeOffset UtcNowDateTimeOffset { get; set; }
}
The response XML of the request is:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header />
<s:Body>
<DoWorkResponse xmlns="http://tempuri.org/">
<DoWorkResult xmlns:a="http://schemas.datacontract.org/2004/07/RD.MES.WcfService" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:NowDateTime>2012-03-23T15:59:47.8328698+01:00</a:NowDateTime>
<a:NowDateTimeOffset xmlns:b="http://schemas.datacontract.org/2004/07/System">
<b:DateTime>2012-03-23T14:59:47.8328698Z</b:DateTime>
<b:OffsetMinutes>60</b:OffsetMinutes>
</a:NowDateTimeOffset>
<a:UtcNowDateTime>2012-03-23T14:59:47.8328698Z</a:UtcNowDateTime>
<a:UtcNowDateTimeOffset xmlns:b="http://schemas.datacontract.org/2004/07/System">
<b:DateTime>2012-03-23T14:59:47.8328698Z</b:DateTime>
<b:OffsetMinutes>0</b:OffsetMinutes>
</a:UtcNowDateTimeOffset>
</DoWorkResult>
</DoWorkResponse>
</s:Body>
</s:Envelope>
I'm in the GMT+01.00 timezone, so the values seem about right. Why is it this way? Well, the WSDL defines Container
like this:
<xs:schema elementFormDefault="qualified" targetNamespace="http://schemas.datacontract.org/2004/07/WcfService">
<xs:import schemaLocation="http://localhost:3608/DateTimeOffsetService.svc?xsd=xsd3" namespace="http://schemas.datacontract.org/2004/07/System"/>
<xs:complexType name="Container">
<xs:sequence>
<xs:element minOccurs="0" name="NowDateTime" type="xs:dateTime"/>
<xs:element minOccurs="0" name="NowDateTimeOffset" type="q1:DateTimeOffset"/>
<xs:element minOccurs="0" name="UtcNowDateTime" type="xs:dateTime"/>
<xs:element minOccurs="0" name="UtcNowDateTimeOffset" type="q2:DateTimeOffset"/>
</xs:sequence>
</xs:complexType>
<xs:element name="Container" nillable="true" type="tns:Container"/>
</xs:schema>
And DateTimeOffset
- in WSDL - is defined as:
<xs:schema elementFormDefault="qualified" targetNamespace="http://schemas.datacontract.org/2004/07/System">
<xs:import schemaLocation="http://localhost:3608/DateTimeOffsetService.svc?xsd=xsd1" namespace="http://schemas.microsoft.com/2003/10/Serialization/"/>
<xs:complexType name="DateTimeOffset">
<xs:annotation>
<xs:appinfo>
<IsValueType>true</IsValueType>
</xs:appinfo>
</xs:annotation>
<xs:sequence>
<xs:element name="DateTime" type="xs:dateTime"/>
<xs:element name="OffsetMinutes" type="xs:short"/>
</xs:sequence>
</xs:complexType>
<xs:element name="DateTimeOffset" nillable="true" type="tns:DateTimeOffset"/>
</xs:schema>
So basically, DateTime
is serialized as a standard xs:dateTime
(which does have the correct timezone component) and DateTimeOffset
is serialized into a non-standard complex type, which the caller would have to understand and handle correctly.
FWIW; Since I found this out, I will probably use DateTime
for the WCF interface unless I actually need to take care of different timezone offsets.
Currently, the only justification I could see in favour of using the complex type (since xs:dateTime
should be able to contain all information that it does!) is that if xs:dateTime
had been used to serialize DateTime
and DateTimeOffset
, a WCF client would have no idea which type to use.
IMHO the biggest headache in using DateTime with a WCF Service is that WCF doesn't currently support xs:Date - see this related question and the linked Connect suggestions.
DateTimeOffset doesn't help with this problem.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With