Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WCF DateTimeOffset compatibility

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?

like image 916
Holstebroe Avatar asked Feb 07 '12 07:02

Holstebroe


2 Answers

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.

like image 136
hangy Avatar answered Sep 18 '22 11:09

hangy


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.

like image 26
Joe Avatar answered Sep 20 '22 11:09

Joe