.Net框架内置了一个单向隐式转换,允许您将 DateTime 传递给任何 DateTimeOffset 参数或变量 . 这样做的时候, the .Kind matters . 如果您传递UTC类型,它将携带零偏移,但如果您传递 .Local 或 .Unspecified ,它将假定为 local . 该框架基本上是在说,"Well, you asked me to convert calendar time to instantaneous time, but I have no idea where this came from, so I'm just going to use the local calendar."如果您在具有不同时区的计算机上加载未指定的 DateTime ,这是一个巨大的问题 . (恕我直言 - 这应该抛出异常 - 但事实并非如此 . )
Shameless Plug:
许多人与我分享他们发现这个类比非常有 Value ,所以我把它包含在我的Pluralsight课程中,Date and Time Fundamentals . 您将在 Headers 为"Calendar Time vs. Instantaneous Time"的剪辑中找到第二个模块"Context Matters"中相机类比的逐步演练 .
// Find difference between Date.Now and Date.UtcNow
date1 = DateTime.Now;
date2 = DateTime.UtcNow;
difference = date1 - date2;
Console.WriteLine("{0} - {1} = {2}", date1, date2, difference);
// Find difference between Now and UtcNow using DateTimeOffset
dateOffset1 = DateTimeOffset.Now;
dateOffset2 = DateTimeOffset.UtcNow;
difference = dateOffset1 - dateOffset2;
Console.WriteLine("{0} - {1} = {2}",
dateOffset1, dateOffset2, difference);
// If run in the Pacific Standard time zone on 4/2/2007, the example
// displays the following output to the console:
// 4/2/2007 7:23:57 PM - 4/3/2007 2:23:57 AM = -07:00:00
// 4/2/2007 7:23:57 PM -07:00 - 4/3/2007 2:23:57 AM +00:00 = 00:00:00
9 回答
DateTimeOffset
表示瞬时时间(也称为绝对时间) . 通过这个,我的意思是每个人都普遍的时刻(不考虑leap seconds,或time dilation的相对论效应) . 另一种表示瞬时时间的方法是DateTime
,其中.Kind
是DateTimeKind.Utc
.这与日历时间(也称为民用时间)不同,后者是某人日历上的一个位置,全球有许多不同的日历 . 我们称这些日历为时区 . 日历时间由
DateTime
表示,其中.Kind
是DateTimeKind.Unspecified
或DateTimeKind.Local
. 并且.Local
仅在您隐含了解使用结果的计算机所在位置的情况下才有意义 . (例如,用户的工作站)那么,为什么
DateTimeOffset
而不是UTCDateTime
? It's all about perspective. 让's use an analogy - we'假装成为摄影师 .想象一下,您正站在日历时间轴上,将摄像机对准在您面前的瞬时时间线上的人 . 您根据时区规则排列相机 - 由于夏令时,或由于您所在时区的法律定义的其他更改而定期更改 . (你没有稳定的手,所以你的相机不稳定 . )
站在照片中的人会看到相机来自的角度 . 如果其他人正在拍照,他们可能是从不同的角度来看 . 这就是
DateTimeOffset
的Offset
部分代表的内容 .因此,如果您将相机标记为“东部时间”,有时您指向-5,有时您指向-4 . 世界各地都有摄像机,所有摄像机都标有不同的东西,并且从不同角度指向同一瞬时时间轴 . 它们中的一些紧挨着(或在彼此之上),因此只知道偏移量不足以确定时间与哪个时区相关 .
那么UTC呢?嗯,这是一台相机,保证有稳定的手 . 它在三脚架上,牢固地固定在地面上 . 它不会去任何地方 . 我们将其视角称为零偏移 .
那么 - 这个类比告诉我们什么?它提供了一些直观的指导 .
如果您特别表示相对于某个地方的时间,请使用
DateTime
在日历时间内表示 . 请确保您不会将一个日历与另一个日历混淆 .Unspecified
应该是你的假设 .Local
仅对来自DateTime.Now
有用 . 例如,我可能会得到DateTime.Now
并将其保存在数据库中 - 但是当我检索它时,我必须假设它是Unspecified
. 我不能相信我的本地日历与最初的日历相同 .如果您必须始终确定时刻,请确保您正在表示瞬时时间 . 使用
DateTimeOffset
强制执行,或按惯例使用UTCDateTime
.如果你需要追踪瞬间的瞬间,但你想知道"What time did the user think it was on their local calendar?" - 那么你必须使用
DateTimeOffset
. 这对于计时系统非常重要,例如 - 无论是技术问题还是法律问题 .如果您需要修改以前记录的
DateTimeOffset
- 仅在偏移中没有足够的信息以确保新偏移仍然与用户相关 . 您还必须存储时区标识符(想想 - 我需要该摄像机的名称,这样即使位置发生变化,我也可以拍摄新照片) .还应该指出Noda Time有一个名为
ZonedDateTime
的表示,而.Net基类库没有任何类似的东西 . 您需要存储DateTimeOffset
和TimeZoneInfo.Id
值 .这里有一些关于
DateTimeOffset
的其他一点点备份这个类比,以及一些保持它的提示:如果比较两个
DateTimeOffset
值,它们首先被标准化为零偏移量比较 . 换句话说,2012-01-01T00:00:00+00:00
和2012-01-01T02:00:00+02:00
指的是相同的瞬时时刻,因此是等价的 .如果您正在进行任何单元测试并且需要确定偏移量,请分别测试
DateTimeOffset
值和.Offset
属性 ..Net框架内置了一个单向隐式转换,允许您将
DateTime
传递给任何DateTimeOffset
参数或变量 . 这样做的时候, the .Kind matters . 如果您传递UTC类型,它将携带零偏移,但如果您传递.Local
或.Unspecified
,它将假定为 local . 该框架基本上是在说,"Well, you asked me to convert calendar time to instantaneous time, but I have no idea where this came from, so I'm just going to use the local calendar."如果您在具有不同时区的计算机上加载未指定的DateTime
,这是一个巨大的问题 . (恕我直言 - 这应该抛出异常 - 但事实并非如此 . )Shameless Plug:
许多人与我分享他们发现这个类比非常有 Value ,所以我把它包含在我的Pluralsight课程中,Date and Time Fundamentals . 您将在 Headers 为"Calendar Time vs. Instantaneous Time"的剪辑中找到第二个模块"Context Matters"中相机类比的逐步演练 .
来自微软:
来源:“在DateTime,DateTimeOffset,TimeSpan和TimeZoneInfo之间选择”,MSDN
我们使用
DateTimeOffset
几乎所有内容,因为我们的应用程序处理特定时间点(例如,创建/更新记录时) . 另外,我们在SQL Server 2008中也使用DATETIMEOFFSET
.我认为
DateTime
在您只想处理日期,仅处理时间或处理一般意义上的处理时非常有用 . 例如,如果你有一个警报要在每天早上7点起飞,你可以使用DateTimeKind
Unspecified
将其保存在DateTime
中,因为你希望它在早上7点关闭,而不管DST . 但是如果要表示报警发生的历史记录,可以使用DateTimeOffset
.使用
DateTimeOffset
和DateTime
的混合时要特别小心,尤其是在分配和比较类型时 . 此外,仅比较DateTimeKind
相同的DateTime
实例,因为DateTime
在比较时忽略时区偏移 .DateTime只能存储两个不同的时间,即本地时间和UTC . Kind属性表示哪个 .
DateTimeOffset通过能够从世界上任何地方存储本地时间来扩展此功能 . 它还存储本地时间和UTC之间的偏移量 . 请注意DateTime不能这样做,除非您在类中添加一个额外的成员来存储该UTC偏移量 . 或者只使用UTC . 这本身就是一个好主意btw .
有几个地方
DateTimeOffset
有意义 . 一个是当你说我想设置闹钟每天早上9点起飞 . 如果我使用"store as UTC, display as local time"规则,那么当夏令时生效时,闹钟将在不同时间关闭 .可能还有其他的,但上面的例子实际上是我过去遇到的一个(这是在向BCL添加
DateTimeOffset
之前 - 我当时的解决方案是明确地将时间存储在本地时区,以及保存时区信息:基本上DateTimeOffset
在内部做什么 .最重要的区别是DateTime不存储时区信息,而DateTimeOffset则存储时区信息 .
尽管DateTime区分UTC和Local,但绝对没有与之关联的显式时区偏移 . 如果进行任何类型的序列化或转换,将使用服务器的时区 . 即使您通过添加分钟来手动创建本地时间来抵消UTC时间,您仍然可以在序列化步骤中获得位,因为(由于DateTime中没有任何显式偏移),它将使用服务器的时区偏移量 .
例如,如果使用Json.Net和ISO日期格式序列化Kind = Local的DateTime值,您将获得类似
2015-08-05T07:00:00-04
的字符串 . 请注意,最后一部分(-04)与您的DateTime或您用于计算它的任何偏移无关......它是's just purely the server'的时区偏移 .同时,DateTimeOffset显式包含偏移量 . 它可能不包含时区的名称,但至少它包含偏移量,如果序列化它,您将获得值中显式包含的偏移量,而不是服务器的本地时间 .
大多数答案都很好,但我想添加一些MSDN链接以获取更多信息
A brief History of DateTime - By Anthony Moore by BCL team
Choosing between Datetime and DateTime Offset - by MSDN
Do not forget SQL server 2008 onwards has a new Datatype as DateTimeOffset
.NET Framework包含 DateTime , DateTimeOffset 和 TimeZoneInfo 类型,所有这些类型都可用于构建使用日期和时间的应用程序 .
Performing Arithmetic Operations with Dates and Times-MSDN
一个主要区别是
DateTimeOffset
可以与TimeZoneInfo
一起使用,以转换为当前时区以外的时区 .这在服务器上很有用用户在不同时区访问的应用程序(例如ASP.NET) .
我看到DateTimeOffset的唯一不利方面是微软“忘记”(按设计)在XmlSerializer类中支持它 . 但它已被添加到XmlConvert实用程序类中 .
XmlConvert.ToDateTimeOffset
XmlConvert.ToString
我说继续使用DateTimeOffset和TimeZoneInfo因为所有的好处,只要注意创建将要或可能序列化为XML的实体(然后是所有业务对象) .
这段来自Microsoft的代码解释了一切: