When you consume a SOAP web service that uses xsd:dateTime
, Visual Studio will always create the client proxy class using a DateTime
.
If there is no offset in the data, the values will come across with DateTimeKind.Unspecified
.
If instead of an offset, the Z
specifier is sent, then the values will come through with DateTimeKind.Utc
.
If there is any offset at all, then the values come through with DateTimeKind.Local
. Even when the offset is zero. Whatever the offset is, it is applied, and then the value is converted to local time. Essentially, it calls .ToLocalTime()
internally.
This kind of stinks, but the easiest way to deal with it is to convert back to UTC using .ToUniversalTime()
, or convert to another time zone using the TimeZoneInfo
object.
Thanks to the hidden "4th kind", you can safely convert from local back to UTC without ambiguity. (The offset from the original value will disambiguate.)
As far as I know, there is no way to get it to create a DateTimeOffset
instead. That would be ideal. However, if you really want to dive deep, you may be able to get it to ignore the offset completely - though that's not necessarily the best idea.
Also, it's worth mentioning that if you were to try to create your own service and expose a DateTimeOffset
type directly - you'd run into problems. There isn't a mapping from DateTimeOffset
back to xsd:dateTime
or any of the other XML Schema data types used by SOAP. Instead, you get a custom complex type in the schema, and the data doesn't get passed along at all. On the client, instead of receiving a System.DateTimeOffset
, you get a YourServiceReference.DateTimeOffset
object that doesn't do anything at all. It's unfortunate, because it should be great advice to use DateTimeOffset
in a public-facing API, but it simply doesn't work. At least not for SOAP/XML. Things are much better in the REST/JSON world.