Запрет преобразования часового пояса при десериализации значения DateTime - PullRequest
28 голосов
/ 06 июля 2010

У меня есть класс, который я сериализую / десериализую, используя XmlSerializer.Этот класс содержит поле DateTime.

При сериализации поле DateTime представляется строкой, содержащей смещение по Гринвичу, например, 2010-05-05T09:13:45-05:00.При десериализации эти времена преобразуются в местное время машины, выполняющей десериализацию.

По причинам, которые не стоит объяснять, я бы хотел предотвратить преобразование этого часового пояса.Сериализация происходит в дикой природе, где существует несколько версий этого класса.Десериализация происходит на сервере, который находится под моим контролем.Таким образом, кажется, что это лучше всего обрабатывать во время десериализации.

Как я могу это сделать, кроме реализации IXmlSerializable и выполнения всей десериализации "вручную?"

Ответы [ 4 ]

29 голосов
/ 15 октября 2013

Что я сделал, так это использовал метод DateTime.SpecifyKind, как показано ниже:

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

И это решило мою проблему, надеюсь, это поможет вам.

24 голосов
/ 06 июля 2010

Вместо синтаксического анализа как DateTime вы можете проанализировать его как DateTimeOffset и использовать свойство DateTimeOffset.DateTime, чтобы игнорировать часовой пояс. Как это:

[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; }
}
2 голосов
/ 25 января 2013

Я знаю, что это старо, но надеюсь, что это поможет кому-то в будущем.

Вот XML, который я десериализовал:

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

После десериализации XML я получаю 30-е, а не 31-е:

enter image description here

Похоже, третьи лица, которые производят этот XML (который я использую), изменяют часовой пояс на +11 во время перехода на летнее время и сохраняют его на +10, когда это не летнее время (DST).

Согласно Джону Скиту, UTC не должен учитывать DST: https://stackoverflow.com/a/5495816/495455


Также обратите внимание на документацию Рекомендации по кодированию с использованием DateTime в .NET Framework :

Сериализатор XML всегда предполагает, что сериализованные значения DateTime представляют время локального компьютера, поэтому он применяет смещение локального часового пояса компьютера как часть смещения закодированного времени XML. Когда мы десериализовываем это на другом компьютере, исходное смещение вычитается из анализируемого значения и добавляется смещение часового пояса текущего компьютера.


Следующий код позволил мне получить дату, отформатированную как 31-е, но она не будет работать на 100% для дат без летнего времени (приведенных в этом фиде):
TimeZoneInfo easternZone = TimeZoneInfo.FindSystemTimeZoneById("AUS Eastern Standard Time");
DateTime easternTimeNow = TimeZoneInfo.ConvertTimeFromUtc(dataPoint.timePeriod, easternZone);
System.Diagnostics.Debug.WriteLine(easternTimeNow.ToString());

Следовательно, решение состоит в том, чтобы исправить канал XML, чтобы он не чередовал UTC с DST.

РЕДАКТИРОВАТЬ: почему данные были испорчены

Как выяснилось, это НЕ сторонний поставщик, изменяющий UTC с помощью летнего времени. Подача XML создается платформой Java Swing с чтением SQL дБ. Обычно я бы рекомендовал придерживаться стандартного представления XML (xsd: dateTime) - IS0 8601, но в этом случае использовать строку и копировать все после того, как T сработает. Отказ от ответственности, я все еще пытаюсь изменить канал, рекомендую вам НЕ делать это в PROD. Используйте на свой страх и риск !!

2 голосов
/ 06 июля 2010

Не могли бы вы попробовать что-то вроде , которое предлагает этот пост , создать новое строковое свойство и XmlIgnore существующего:

Поместите [XmlIgnore] в свойство Time.

Затем добавьте новое свойство:

[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); }
}
...