DateTime.ToUniversalTime() 如何工作?
如何从标准 DateTime
格式转换为 UTC?
更具体地说,如果我在一个时区创建一个 DateTime
对象,然后切换到另一个时区并对其运行 ToUniversalTime()
,它如何知道转换已完成正确并且时间仍能准确表示?
How does the conversion to UTC from the standard DateTime
format work?
More specifically, if I create a DateTime
object in one time zone and then switch to another time zone and run ToUniversalTime()
on it, how does it know the conversion was done correctly and that the time is still accurately represented?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
DateTime
对象没有附加隐式时区。 如果您对其运行ToUniversalTime()
,它将使用代码运行所在上下文的时区。例如,如果我从 1 纪元创建一个
DateTime
/1/1970,无论我在世界的哪个地方,它都会给我相同的DateTime
对象。如果我在格林威治运行代码时对其运行
ToUniversalTime()
,那么我会得到相同的时间。 如果我住在温哥华时这样做,那么我会得到 -8 小时的偏移DateTime
对象。这就是为什么当您需要进行任何类型的日期转换或本地化时,在数据库中将时间相关信息存储为 UTC 时间非常重要。 考虑一下您的代码库是否已移动到另一个时区的服务器设施;)
编辑:Joel 答案中的注释 - 默认情况下
DateTime
对象的类型为DateTimeKind.Local
。 如果您解析日期并将其设置为DateTimeKind.Utc
,则ToUniversalTime()
不执行任何转换。这里有一篇关于“使用日期时间编码的最佳实践”的文章,以及关于使用 .Net 转换日期时间的文章。
There is no implicit timezone attached to a
DateTime
object. If you runToUniversalTime()
on it, it uses the timezone of the context that the code is running in.For example, if I create a
DateTime
from the epoch of 1/1/1970, it gives me the sameDateTime
object no matter where in the world I am.If I run
ToUniversalTime()
on it when I'm running the code in Greenwich, then I get the same time. If I do it while I live in Vancouver, then I get an offsetDateTime
object of -8 hours.This is why it's important to store time related information in your database as UTC times when you need to do any kind of date conversion or localization. Consider if your codebase got moved to a server facility in another timezone ;)
Edit: note from Joel's answer -
DateTime
objects by default are typed asDateTimeKind.Local
. If you parse a date and set it asDateTimeKind.Utc
, thenToUniversalTime()
performs no conversion.And here's an article on "Best Practices Coding with Date Times", and an article on Converting DateTimes with .Net.
首先,它检查
DateTime
的Kind
是否已知为 UTC。 如果是,则返回相同的值。否则,它被假定为本地时间 - 这是运行它的计算机的本地时间,特别是在首次延迟初始化某些私有属性时计算机所使用的时区。 这意味着,如果您在应用程序启动后更改时区,它很可能仍会使用旧时区。
时区包含足够的信息,可将本地时间转换为 UTC 时间,反之亦然,尽管有时这些信息不明确或无效。 (有些本地时间出现了两次,有些本地时间由于夏令时而从未出现过。)处理这些情况的规则在 文档:
返回的值的
Kind
为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 吗? ;)
Firstly, it checks whether the
Kind
of theDateTime
is known to be UTC already. If so, it returns the same value.Otherwise, it's assumed to be a local time - that's local to the computer it's running on, and in particular in the time zone that the computer was using when some private property was first lazily initialized. That means if you change the time zone after your application was started, there's a good chance it will still be using the old one.
The time zone contains enough information to convert a local time to a UTC time or vice versa, although there are times that that's ambiguous or invalid. (There are local times which occur twice, and local times which never occur due to daylight saving time.) The rules for handling these cases are specified in the documentation:
The returned value will have a
Kind
ofDateTimeKind.Utc
, so if you callToUniveralTime
on that it won't apply the offset again. (This is a vast improvement over .NET 1.1!)If you want a non-local time zone, you should use
TimeZoneInfo
which was introduced in .NET 3.5 (there are hacky solutions for earlier versions, but they're not nice). To represent an instant in time, you should consider usingDateTimeOffset
which was introduced in .NET 2.0SP1, .NET3.0SP1 and .NET 3.5. However, that still doesn't have an actual time zone associated with it - just an offset from UTC. That means you don't know what local time will be one hour later, for example - the DST rules can vary between time zones which happened to use the same offset for that particular instant.TimeZoneInfo
is designed to take historical and future rules into account, as opposed toTimeZone
which is somewhat simplistic.Basically the support in .NET 3.5 is a lot better than it was, but still leaves something to be desired for proper calendar arithmetic. Anyone fancy porting Joda Time to .NET? ;)
@womp 所说的,此外它还会检查 DateTime 的 Kind 属性,看看它是否已经 em> 是 UTC 日期。
What @womp said, with the addition that it checks the DateTime's Kind property to see if it might already be a UTC date.
DateTime.ToUniversalTime 删除本地时区的时区偏移量,以将 DateTime 规范化为 UTC。 如果您随后对另一个时区的标准化值使用 DateTime.ToLocalTime,则该时区的时区偏移量将添加到标准化值中,以便在该时区中正确表示。
DateTime.ToUniversalTime removes the timezone offset of the local timezone to normalize a DateTime to UTC. If you then use DateTime.ToLocalTime on the normalized value in another timezone, the timezone offset of that timezone will be added to the normalized value for correct representation in that timezone.