我从服务器收到一个json,其时间戳为UTC格式:
{
"foo": "2017-11-05T08:30:00"
}
并使用CCD_ 1将其转换为.NET实例。我接收到的DateTime
属性具有一个包含DateTimeKind = Unspecified
的有效值。
然后我调用obj.foo.ToLocalTime()
并获得2017-11-05 00:30 AM
,而我在计算机上的真实本地时间是2017-11-05 01:30 AM
(-7)
为什么损失了1个小时(我想这与夏令时有关)?
我如何在反序列化级别上解决这个问题,以便每个实例都能正确地转换为有效的UTC DateTime实例?
更新:这发生在2017年11月5日,当时夏令时机会出现,客户(-7)有待定的UTC夏令时更改,而UTC已经超过了该点(UTC时间为8:30,而客户时间为凌晨1:30,我们预计时间更改为凌晨2:00)。现在它工作正常,没有任何更改,但值得修复服务器(Z
)和客户端(UTC
)端。
您的问题是您的时间戳值"2017-11-05T08:30:00"完全缺少时区指示符,UTC为"2017-11-05 T08:30:00Z",本地时区为"2017-11-105T08:00-07:00"。也就是说,您关于时间戳是UTC格式的的声明是错误的。
当这种情况发生时,Json.NET将该值解析为具有Json.Deserialize
0的DateTime
(这是有道理的,因为实际上Json中未指定时区)。后来,其他一些代码将其解释为本地时间,但由于夏令时实际上在您在个人资料中列出的地点(美国华盛顿特区)提出此问题时到期,事情变得混乱起来,因为DateTime
不记得它的时区偏移,只记得它是否在机器的本地时区。(有关此限制的更多信息,请参阅本文档页以及Jon Skeet的DateTime到底出了什么问题?,其中特别提到.Net日期和时间类型的某些错误只能在夏令时更改期间发生。)如果夏令时在反序列化时间戳和随后处理时间戳之间过期,你会得到你所看到的错误。
话虽如此,您会问,我如何在反序列化级别上解决这个问题,以便每个实例都可以正确地转换为有效的UTC DateTime实例这可以通过在反序列化期间设置JsonSerializerSettings.DateTimeZoneHandling == DateTimeZoneHandling.Utc
来完成:
var settings = new JsonSerializerSettings
{
DateTimeZoneHandling = DateTimeZoneHandling.Utc,
};
var root = JsonConvert.DeserializeObject<RootObject>(json, settings);
这里解释了DateTimeZoneHandling
的可能值:
本地:视为本地时间。如果DateTime对象表示协调世界时(UTC),则会将其转换为本地时间。
Utc:视为Utc。如果DateTime对象表示本地时间,则会将其转换为UTC。
未指定:如果DateTime正在转换为字符串,则视为本地时间。如果字符串正在被转换为DateTime,如果指定了时区,则转换为本地时间。
RoundtripKind:转换时应保留时区信息。
通过使用DateTimeZoneHandling.Utc
,时间戳将从一开始就被假定为UTC,因此不应出现由于夏令时变化而导致的奇怪行为。
您还可以考虑修复服务器代码,使其在时间戳值后正确地附加一个Z,以表明该值实际上是UTC。
小提琴样品显示了所有四种设置的作用。