DateTimea和 a 有什么区别,什么DateTimeOffset时候应该使用?
DateTime
DateTimeOffset
目前,我们有一种以 TimeZone-aware 方式处理 .NETDateTime的标准方法:每当我们生成 a时,DateTime我们都会使用 UTC(例如使用DateTime.UtcNow),并且每当我们显示时,我们都会从 UTC 转换回用户的本地时间.
DateTime.UtcNow
这很好用,但我一直在阅读DateTimeOffset以及它如何在对象本身中捕获本地和 UTC 时间。
DateTimeOffset是 瞬时时间 (也称为 绝对时间 )的表示。我的意思是每个人都通用的时间点(不考虑闰秒,或时间膨胀的相对论效应)。另一种表示瞬时时间的方法是使用DateTimewhere .Kindis DateTimeKind.Utc。
.Kind
DateTimeKind.Utc
这与 日历时间 (也称为 民用时间 )不同,后者是某人日历上的一个位置,全球有许多不同的日历。我们称这些日历 为时区 。日历时间由DateTimewhere .KindisDateTimeKind.Unspecified或表示DateTimeKind.Local。并且.Local仅在您对使用结果的计算机的位置有隐含理解的情况下才有意义。(例如,用户的工作站)
DateTimeKind.Unspecified
DateTimeKind.Local
.Local
那么,为什么DateTimeOffset不是 UTCDateTime呢? 这都是关于视角的。 让我们打个比方——我们会假装自己是摄影师。
想象一下,您站在日历时间线上,将相机对准摆在您面前的瞬时时间线上的一个人。您根据您的时区规则排列您的相机 - 由于夏令时或您的时区法律定义的其他更改,这些规则会定期更改。(你的手不稳,所以你的相机会摇晃。)
站在照片中的人会看到你的相机来自的角度。如果其他人在拍照,他们可能从不同的角度。这就是代表的Offset部分DateTimeOffset。
Offset
因此,如果您将相机标记为“东部时间”,则有时您从-5 指向,有时您从-4 指向。世界各地都有摄像机,它们都标记了不同的事物,并且都从不同的角度指向同一个瞬时时间线。其中一些彼此相邻(或重叠),因此仅知道偏移量不足以确定时间与哪个时区相关。
那么UTC呢?好吧,这是保证手部稳定的唯一相机。它在三脚架上,牢固地固定在地面上。它不会去任何地方。我们将其视角称为零偏移。
那么 - 这个类比告诉我们什么?它提供了一些直观的指导方针——
如果您要表示相对于某个特定地点的时间,请在日历时间中使用DateTime. 请确保您永远不会将一个日历与另一个日历混淆。 Unspecified应该是你的假设。 Local只对来自 有用DateTime.Now。例如,我可能会获取DateTime.Now它并将其保存在数据库中 - 但是当我检索它时,我必须假设它是Unspecified. 我不能相信我的本地日历与最初的日历相同。
Unspecified
Local
DateTime.Now
如果您必须始终确定时刻,请确保您代表的是瞬时时间。用于DateTimeOffset强制执行,或DateTime按惯例使用 UTC。
如果您需要跟踪瞬时时间,但您还想知道“用户认为这是他们本地日历上的什么时间?” - 那么你 必须 使用DateTimeOffset. 这对于计时系统非常重要,例如,对于技术和法律问题。
如果您需要修改以前记录的DateTimeOffset- 您在偏移量中没有足够的信息来确保新的偏移量仍然与用户相关。您 还 必须存储一个时区标识符(想想 - 我需要该相机的名称,这样即使位置发生了变化,我也可以拍摄新照片)。
还应该指出的是,Noda Time对此有一个表示ZonedDateTime,而 .Net 基类库没有类似的东西。您需要同时存储 aDateTimeOffset和 aTimeZoneInfo.Id值。
ZonedDateTime
TimeZoneInfo.Id
这里有一些关于DateTimeOffset支持这个类比的其他一些小细节,以及一些保持它直截了当的技巧:
如果您比较两个DateTimeOffset值,在比较之前它们首先被归一化为零偏移。换句话说,2012-01-01T00:00:00+00:00和2012-01-01T02:00:00+02:00指的是同一瞬间,因此是等价的。
2012-01-01T00:00:00+00:00
2012-01-01T02:00:00+02:00
如果您正在进行任何单元测试并且需要确定偏移量,请分别测试值 和DateTimeOffset属性.Offset。
.Offset
.Net 框架内置了一种单向隐式转换,可让您将 a 传递给DateTime任何DateTimeOffset参数或变量。这样做时 ,.Kind事情。如果您传递 UTC 类型,它将以零偏移量传入,但如果您传递.Localor .Unspecified,它将假定为 local 。该框架基本上是在说,“好吧,你让我将日历时间转换为瞬时时间,但我不知道这是从哪里来的,所以我打算使用本地日历。” DateTime如果您在具有不同时区的计算机上加载未指定的文件,这将是一个巨大的问题。(恕我直言 - 这应该抛出一个异常 - 但它没有。)
.Unspecified
无耻的插头:
许多人与我分享他们发现这个类比非常有价值,因此我将它包含在我的 Pluralsight 课程“日期和时间基础”中。您将在标题为“日历时间与瞬时时间”的剪辑的第二个模块“上下文很重要”中找到相机类比的逐步演练。