Prevent timezone conversion on deserialization of DateTime value

39,749

Solution 1

Instead of parsing as a DateTime you can parse it as a DateTimeOffset and use the DateTimeOffset.DateTime property to ignore the timezone. Like this:

[XmlIgnore()]
public DateTime Time { get; set; }

[XmlElement(ElementName = "Time")]
public string XmlTime
{
    get { return XmlConvert.ToString(Time, XmlDateTimeSerializationMode.RoundtripKind); }
    set { Time = DateTimeOffset.Parse(value).DateTime; }
}

Solution 2

What I did, it was to use DateTime.SpecifyKind method, as following:

DateTime dateTime = DateTime.SpecifyKind(DateTime.Now, DateTimeKind.Unspecified);

And this resolve my problem, I hope this help you.

Solution 3

I know this is old but hope this helps someone in the future.

Here is the XML I was deserializing:

<timePeriod>1982-03-31T00:00:00+11:00</t

After deserializing the XML I end up with the 30th not the 31st:

enter image description here

It appears the 3rd party who produce this XML (that I'm using) change the TimeZone to +11 during daylight saving and keep it as +10 when its not Daylight Saving (DST).

According to Jon Skeet UTC's shouldn't consider DST: https://stackoverflow.com/a/5495816/495455


Also note the documentation Coding Best Practices Using DateTime in the .NET Framework:

The XML serializer always assumes that DateTime values being serialized represent local machine time, so it applies the machine local time zone offset as the offset portion of the encoded XML time. When we deserialize this onto another machine, the original offset is subtracted from the value being parsed, and the current machine's time-zone offset is added.


The following code allowed me to get the date formatted as the 31st but it wont work 100% for non Daylioght Saving dates (given in this feed):
TimeZoneInfo easternZone = TimeZoneInfo.FindSystemTimeZoneById("AUS Eastern Standard Time");
DateTime easternTimeNow = TimeZoneInfo.ConvertTimeFromUtc(dataPoint.timePeriod, easternZone);
System.Diagnostics.Debug.WriteLine(easternTimeNow.ToString());

Hence the solution is fix the XML feed so it doesn't alternate UTC's with DST.

EDIT: why the data was screwed up

As it turns out its NOT the 3rd party vendor changing the UTC with the DST. The XML feed is created by Java Swing framework reading a SQL dB. Normally I would recommend keeping with the XML standard representation (xsd:dateTime) – IS0 8601, but in this case using string and ripping everything after the T works. Disclaimer, I am still trying to get the feed changed, recommend you do NOT do this in PROD. Use at your own risk!!

Solution 4

Could you try something like this post suggests and make a new string property and XmlIgnore the existing one:

Put [XmlIgnore] on the Time property.

Then add a new property:

[XmlElement(DataType="string",ElementName="Time")]
public String TimeString
{
   get { return this.timeField.ToString("yyyy-MM-dd"); }
   set { this.timeField = DateTime.ParseExact(value, "yyyy-MM-dd", CultureInfo.InvariantCulture); }
}
Share:
39,749
Odrade
Author by

Odrade

Updated on April 25, 2020

Comments

  • Odrade
    Odrade about 4 years

    I have a class that I serialize/deserialize using XmlSerializer. This class contains a DateTime field.

    When serialized, the DateTime field is represented by a string that includes the offset from GMT, e.g 2010-05-05T09:13:45-05:00. When deserialized, these times are converted to the local time of the machine performing the deserialization.

    For reasons not worth explaining, I'd like to prevent this timezone conversion from happening. The serialization happens out in the wild, where multiple version of this class exist. The deserialization happens on a server that's under my control. As such, it seems like this would be best handled during deserialization.

    How can I make this happen, other than implementing IXmlSerializable and doing all of the deserialization "by hand?"

  • Odrade
    Odrade almost 14 years
    I need to deserialize old versions of the class using the updated version. Won't this break compatability? I can rename my DateTime property and add a string property that has the same name that the DateTime used to. But, this will break clients that reference the DateTime property.
  • Odrade
    Odrade almost 14 years
    Oh, I see now that the Element name will stay the same in the Xml. Let me try this out.
  • Adam Hughes
    Adam Hughes almost 14 years
    This code won't work with your existing clients because the DateTime.ParseExact will fail (since the time isn't in that format). If you parse as a DateTimeOffset instead it will work with your existing clients.
  • Odrade
    Odrade almost 14 years
    I adapted this approach to my situation (remove the UTC offset when it's there, then parse). Your approach does look cleaner, though.
  • Chris Rosete
    Chris Rosete almost 8 years
    Also, because I am using entity framework I had to put [NotMapped] on top of the [XmlElement...] but this solution works perfect for me. thanks
  • Michael Freidgeim
    Michael Freidgeim almost 3 years
    DateTimeKind.Unspecified is explained in DateTime Unspecified Kind
  • Evgeny Gorbovoy
    Evgeny Gorbovoy about 2 years
    How can it be used in Serialization which topic is about?