防止对 DateTime 值的反序列化进行时区转换
Posted
技术标签:
【中文标题】防止对 DateTime 值的反序列化进行时区转换【英文标题】:Prevent timezone conversion on deserialization of DateTime value 【发布时间】:2011-03-12 11:06:06 【问题描述】:我有一个使用XmlSerializer
序列化/反序列化的类。这个类包含一个DateTime
字段。
序列化时,DateTime
字段由包含与 GMT 的偏移量的字符串表示,例如 2010-05-05T09:13:45-05:00
。反序列化时,这些时间将转换为执行反序列化的机器的本地时间。
出于不值得解释的原因,我想阻止这种时区转换发生。序列化发生在野外,存在这个类的多个版本。反序列化发生在我控制的服务器上。因此,这似乎最好在反序列化期间处理。
除了实现IXmlSerializable
并“手动”完成所有反序列化之外,我该如何实现?
【问题讨论】:
谁能给我一个关于这个问题的反之亦然的链接? (将 DateTime 从 .Net 服务器传递到 javascript 客户端) 【参考方案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://***.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);
这解决了我的问题,希望对你有所帮助。
【讨论】:
DateTimeKind.Unspecified 在DateTime Unspecified Kind中解释 如何在序列化中使用哪个主题?以上是关于防止对 DateTime 值的反序列化进行时区转换的主要内容,如果未能解决你的问题,请参考以下文章
mysql数据库里的日期用timestamp还是datetime好
使用 Jackson 进行 DateTime 反序列化的默认时区(Joda-Time 模块)