.NET System.DateTime.ToLocalTime() returns 本地时间值无效
.NET System.DateTime.ToLocalTime() returns invalid local time value
我从服务器收到一个 json,带有 UTC 格式的时间戳:
{
"foo": "2017-11-05T08:30:00"
}
并使用 Json.Deserialize
将其转换为 .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”完全缺少 time zone designator,或者“2017-11-05T08:30:00Z”表示 UTC 或“2017-11-05T08:30:00-07:00”表示您当地的时区。 IE。你关于你的时间戳是 UTC 格式 的说法是错误的。
发生这种情况时,Json.NET 将值解析为 DateTime
和 DateTime.Kind == DateTimeKind.Unspecified
(which makes sense, since the time zone is, in fact, unspecified in the JSON). Later on, some other code interpreted that to mean local time but since daylight savings time did in fact expire around the time you asked this question in the location (Washington, DC, United States) listed in your profile, things became confused, since DateTime
doesn't remember its time zone offset, only whether or not it is in the machine's local time zone. (For more on this limitation see this documentation page as well as What's wrong with DateTime anyway?,作者 Jon Skeet 特别提到 .Net 日期和时间类型的某些错误只能发生在夏令时更改期间。)如果夏令时在反序列化时间戳和随后处理时间戳之间过期,您将完全得到您所看到的错误。
话虽这么说,您问了,我如何在反序列化级别修复它,以便每个实例都可以正确转换为有效的 UTC DateTime 实例? 这可以通过以下方式完成在反序列化期间设置 JsonSerializerSettings.DateTimeZoneHandling == DateTimeZoneHandling.Utc
:
var settings = new JsonSerializerSettings
{
DateTimeZoneHandling = DateTimeZoneHandling.Utc,
};
var root = JsonConvert.DeserializeObject<RootObject>(json, settings);
解释 DateTimeZoneHandling
的可能值 here:
Local: Treat as local time. If the DateTime object represents a Coordinated Universal Time (UTC), it is converted to the local time.
Utc: Treat as a UTC. If the DateTime object represents a local time, it is converted to a UTC.
Unspecified: Treat as a local time if a DateTime is being converted to a string. If a string is being converted to DateTime,
convert to a local time if a time zone is specified.
RoundtripKind: Time zone information should be preserved when converting.
通过使用 DateTimeZoneHandling.Utc
,时间戳将从一开始就被假定为 UTC,因此不应发生由于夏令时变化引起的奇怪行为。
您还可以考虑修复服务器代码,以便它正确地将 Z 附加到其时间戳值,以指示该值实际上是 UTC 时间。
示例 fiddle 显示所有四种设置。
我从服务器收到一个 json,带有 UTC 格式的时间戳:
{
"foo": "2017-11-05T08:30:00"
}
并使用 Json.Deserialize
将其转换为 .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”完全缺少 time zone designator,或者“2017-11-05T08:30:00Z”表示 UTC 或“2017-11-05T08:30:00-07:00”表示您当地的时区。 IE。你关于你的时间戳是 UTC 格式 的说法是错误的。
发生这种情况时,Json.NET 将值解析为 DateTime
和 DateTime.Kind == DateTimeKind.Unspecified
(which makes sense, since the time zone is, in fact, unspecified in the JSON). Later on, some other code interpreted that to mean local time but since daylight savings time did in fact expire around the time you asked this question in the location (Washington, DC, United States) listed in your profile, things became confused, since DateTime
doesn't remember its time zone offset, only whether or not it is in the machine's local time zone. (For more on this limitation see this documentation page as well as What's wrong with DateTime anyway?,作者 Jon Skeet 特别提到 .Net 日期和时间类型的某些错误只能发生在夏令时更改期间。)如果夏令时在反序列化时间戳和随后处理时间戳之间过期,您将完全得到您所看到的错误。
话虽这么说,您问了,我如何在反序列化级别修复它,以便每个实例都可以正确转换为有效的 UTC DateTime 实例? 这可以通过以下方式完成在反序列化期间设置 JsonSerializerSettings.DateTimeZoneHandling == DateTimeZoneHandling.Utc
:
var settings = new JsonSerializerSettings
{
DateTimeZoneHandling = DateTimeZoneHandling.Utc,
};
var root = JsonConvert.DeserializeObject<RootObject>(json, settings);
解释 DateTimeZoneHandling
的可能值 here:
Local: Treat as local time. If the DateTime object represents a Coordinated Universal Time (UTC), it is converted to the local time.
Utc: Treat as a UTC. If the DateTime object represents a local time, it is converted to a UTC.
Unspecified: Treat as a local time if a DateTime is being converted to a string. If a string is being converted to DateTime, convert to a local time if a time zone is specified.
RoundtripKind: Time zone information should be preserved when converting.
通过使用 DateTimeZoneHandling.Utc
,时间戳将从一开始就被假定为 UTC,因此不应发生由于夏令时变化引起的奇怪行为。
您还可以考虑修复服务器代码,以便它正确地将 Z 附加到其时间戳值,以指示该值实际上是 UTC 时间。
示例 fiddle 显示所有四种设置。