DateTime.ToUniversalTime()如何工作?
题
如何从标准 DateTime
格式转换为UTC?
更具体地说,如果我在一个时区创建 DateTime
对象,然后切换到另一个时区并在其上运行 ToUniversalTime()
,它是如何知道的转换是否正确完成,时间仍然准确表示?
解决方案
DateTime
对象没有附加隐式时区。如果在其上运行 ToUniversalTime()
,它将使用运行代码的上下文的时区。
例如,如果我从1970年1月1日的纪元创建 DateTime
,无论我在世界的哪个地方,它都会给我相同的 DateTime
对象
如果我在格林威治运行代码时运行 ToUniversalTime()
,那么我会得到相同的时间。如果我在温哥华住的时候这样做,那么我得到一个-8小时的偏移 DateTime
对象。
这就是为什么在您需要进行任何类型的日期转换或本地化时,将时间相关信息作为UTC时间存储在数据库中的重要性。考虑您的代码库是否已移至另一个时区的服务器设施;)
编辑:来自Joel答案的注释 - DateTime
对象默认情况下输入为 DateTimeKind.Local
。如果您解析日期并将其设置为 DateTimeKind.Utc
,则 ToUniversalTime()
不会执行任何转换。
这是一篇关于“带日期时间的最佳实践编码”的文章,以及有关使用.Net转换日期时间的文章。
其他提示
首先,它检查 DateTime
的 Kind
是否已知为UTC。如果是这样,它将返回相同的值。
否则,它被假定为本地时间 - 它在运行的计算机的本地时间,特别是在某个私有财产首次被初始化时计算机正在使用的时区。这意味着如果您在应用程序启动后更改时区,那么它很可能仍然会使用旧的。
时区包含足够的信息,可以将本地时间转换为UTC时间,反之亦然,但有时会出现模糊或无效的情况。 (当地时间出现两次,当地时间从未因夏令时而发生。)处理这些情况的规则在文档:
如果日期和时间实例值是 一个模糊的时间,这种方法假设 这是一个标准时间。 (一个 模棱两可的时间是可以映射的时间 无论是标准时间还是标准时间 当地时间的夏令时 zone)如果是日期和时间实例 value是一个无效的时间,这个方法 只需减去当地时间 本地时区的UTC偏移量为 返回UTC。 (无效时间是一个 由于这个原因而不存在 应用夏令时 调整规则。)
返回的值将具有 KindTimeKind.Utc
的 Kind
,因此如果您调用 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吗? ;)
@womp说,另外还检查DateTime的Kind属性以查看它是否可能已经是UTC日期。
DateTime.ToUniversalTime删除本地时区的时区偏移量,以将DateTime规范化为UTC。如果然后对另一个时区中的规范化值使用DateTime.ToLocalTime,则该时区的时区偏移量将被添加到规范化值中,以便在该时区中进行正确表示。