【问题标题】:Prevent timezone conversion on deserialization of DateTime value防止对 DateTime 值的反序列化进行时区转换
【发布时间】:2011-03-12 11:06:06
【问题描述】:

我有一个使用XmlSerializer 序列化/反序列化的类。这个类包含一个DateTime 字段。

序列化时,DateTime 字段由包含与 GMT 的偏移量的字符串表示,例如 2010-05-05T09:13:45-05:00。反序列化时,这些时间将转换为执行反序列化的机器的本地时间。

出于不值得解释的原因,我想阻止这种时区转换发生。序列化发生在野外,存在这个类的多个版本。反序列化发生在我控制的服务器上。因此,这似乎最好在反序列化期间处理。

除了实现IXmlSerializable 并“手动”完成所有反序列化之外,我该如何实现?

【问题讨论】:

  • 谁能给我一个关于这个问题的反之亦然的链接? (将 DateTime 从 .Net 服务器传递到 JavaScript 客户端)

标签: c# datetime xml-serialization timezone


【解决方案1】:

您可以将其解析为DateTimeOffset 并使用DateTimeOffset.DateTime 属性忽略时区,而不是解析为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; }
}

【讨论】:

  • 另外,因为我使用的是实体框架,所以我不得不将 [NotMapped] 放在 [XmlElement...] 之上,但这个解决方案非常适合我。谢谢
【解决方案2】:

您能否尝试类似this 帖子建议的方法并创建一个新的字符串属性并 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); }
}

【讨论】:

  • 我需要使用更新版本反序列化旧版本的类。这不会破坏兼容性吗?我可以重命名我的 DateTime 属性并添加一个与 DateTime 使用的名称相同的字符串属性。但是,这会破坏引用 DateTime 属性的客户端。
  • 哦,我现在看到元素名称在 Xml 中将保持不变。让我试试这个。
  • 此代码不适用于您现有的客户端,因为 DateTime.ParseExact 将失败(因为时间不是那种格式)。如果您将其解析为 DateTimeOffset,它将适用于您现有的客户端。
  • 我根据我的情况调整了这种方法(删除 UTC 偏移量,然后解析)。不过,您的方法确实看起来更干净。
【解决方案3】:

我知道这是旧的,但希望这对未来的人有所帮助。

这是我反序列化的 XML:

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

在反序列化 XML 后,我得到的是第 30 个而不是第 31 个:

似乎是生成此 XML(我正在使用)的第 3 方在夏令时将 TimeZone 更改为 +11,并在非夏令时 (DST) 时将其保持为 +10。

根据 Jon Skeet 的说法,UTC 不应该考虑 DST:https://stackoverflow.com/a/5495816/495455


另请注意文档Coding Best Practices Using DateTime in the .NET Framework

XML 序列化程序始终假定被序列化的 DateTime 值表示本地机器时间,因此它将机器本地时区偏移量应用为编码 XML 时间的偏移量部分。当我们将其反序列化到另一台机器上时,会从正在解析的值中减去原始偏移量,并添加当前机器的时区偏移量。


以下代码允许我将日期格式化为 31 日,但对于非 Daylioght Saving 日期(在此提要中给出),它不会 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 交替。

编辑: 为什么数据被搞砸了

事实证明,它不是使用 DST 更改 UTC 的第 3 方供应商。 XML 提要由读取 SQL dB 的 Java Swing 框架创建。通常我会建议保持 XML 标准表示 (xsd:dateTime) – IS0 8601,但在这种情况下使用字符串并在 T 工作后撕掉所有内容。免责声明,我仍在尝试更改提要,建议您不要在 PROD 中执行此操作。使用风险自负!

【讨论】:

    【解决方案4】:

    我所做的是使用 DateTime.SpecifyKind 方法,如下:

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

    这解决了我的问题,希望对你有所帮助。

    【讨论】:

    猜你喜欢
    • 2016-06-28
    • 1970-01-01
    • 1970-01-01
    • 2013-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-06
    相关资源
    最近更新 更多