64

从标准DateTime格式转换为 UTC 是如何工作的?

更具体地说,如果我DateTime在一个时区创建一个对象,然后切换到另一个时区并在其上运行ToUniversalTime(),它如何知道转换是否正确完成并且时间仍然准确表示?

4

4 回答 4

75

没有附加到DateTime对象的隐式时区。如果您ToUniversalTime()在其上运行,它将使用代码运行所在的上下文的时区。

例如,如果我从 1970 年 1 月 1DateTime日的时代创建一个,DateTime无论我身在何处,它都会给我相同的对象。

如果我ToUniversalTime()在格林威治运行代码时运行它,那么我会得到相同的时间。如果我住在温哥华时这样做,那么我会得到一个DateTime-8 小时的偏移对象。

这就是为什么当您需要进行任何类型的日期转换或本地化时,将与时间相关的信息作为 UTC 时间存储在数据库中很重要的原因。考虑一下您的代码库是否已移至另一个时区的服务器设施;)

编辑:来自 Joel 的答案的注释 -DateTime默认情况下,对象的类型为DateTimeKind.Local. 如果您解析日期并将其设置为DateTimeKind.Utc,则不ToUniversalTime()执行任何转换。

这是一篇关于“使用日期时间编码的最佳实践”的文章,以及一篇关于使用 .Net 转换日期时间的文章。

于 2009-07-29T16:13:22.307 回答
35

首先,它检查Kind的是否DateTime已知为 UTC。如果是这样,它返回相同的值。

否则,它被假定为本地时间 - 这是运行它的计算机的本地时间,特别是在某些私有属性首次延迟初始化时计算机使用的时区。这意味着如果您在应用程序启动更改时区,它很有可能仍会使用旧时区。

时区包含足够的信息,可以将本地时间转换为 UTC 时间,反之亦然,尽管有时会出现模棱两可或无效的情况。(有出现两次的当地时间,以及由于夏令时而从未出现过的当地时间。)处理这些情况的规则在文档中指定:

如果日期和时间实例值是不明确的时间,则此方法假定它是标准时间。(模糊时间可以映射到标准时间或本地时区的夏令时)如果日期和时间实例值是无效时间,此方法只需从本地时区减去本地时间返回 UTC 的 UTC 偏移量。(无效时间是由于应用了夏令时调整规则而不存在的时间。)

返回的值将具有Kindof DateTimeKind.Utc,因此如果您调用ToUniveralTime它,它将不会再次应用偏移量。(这是对 .NET 1.1 的巨大改进!)

如果你想要一个非本地时区,你应该使用TimeZoneInfo.NET 3.5 中引入的那个(早期版本有一些 hacky 解决方案,但它们并不好)。要表示一个瞬间,您应该考虑使用DateTimeOffset.NET 2.0SP1、.NET3.0SP1 和 .NET 3.5 中引入的。但是,它仍然没有与之关联的实际时区 - 只是与 UTC 的偏移量。这意味着您不知道一小时后的当地时间,例如 - DST 规则可能因时区而异,而时区恰好在该特定时刻使用相同的偏移量。TimeZoneInfo旨在考虑历史和未来的规则,而不是TimeZone过于简单化。

基本上 .NET 3.5 中的支持比以前好很多,但对于正确的日历算术仍然有一些不足之处。有人喜欢将Joda Time移植到 .NET 吗?;)

于 2009-07-29T16:21:47.797 回答
7

@womp 说了什么,此外它还会检查 DateTime 的 Kind 属性以查看它是否可能已经是 UTC 日期。

于 2009-07-29T16:16:35.547 回答
4

DateTime.ToUniversalTime 删除本地时区的时区偏移量以将 DateTime 标准化为 UTC。如果您随后在另一个时区的规范化值上使用 DateTime.ToLocalTime,则该时区的时区偏移量将添加到规范化值中,以便在该时区正确表示。

于 2009-07-29T16:19:31.797 回答