Dav*_*eis 669 .net c# timezone datetime datetimeoffset
目前,我们有一种以TimeZone感知方式处理.net DateTimes的标准方法:每当我们生成一个DateTime
UTC时(例如使用DateTime.UtcNow
),每当我们显示一个时,我们就会从UTC转换回用户的本地时间.
这工作正常,但我一直在阅读DateTimeOffset
它如何捕获对象本身的本地和UTC时间.所以问题是,使用DateTimeOffset
vs我们已经做的事情有什么好处?
Mat*_*int 1088
DateTimeOffset
是瞬时时间(也称为绝对时间)的表示.通过这种方式,我的意思是对每个人都是普遍的时刻(不考虑闰秒,或时间膨胀的相对论效应).代表瞬时间的另一种方法是用DateTime
哪里.Kind
是DateTimeKind.Utc
.
这与日历时间(也称为民用时间)不同,后者是某人日历上的位置,全球有许多不同的日历.我们将这些日历称为时区.日历时间由a表示DateTime
,其中.Kind
是DateTimeKind.Unspecified
或DateTimeKind.Local
.并且.Local
仅在您隐含了解使用结果的计算机的位置的情况下才有意义.(例如,用户的工作站)
那么,为什么DateTimeOffset
而不是UTC DateTime
呢? 这完全取决于观点. 让我们用一个类比 - 我们假装是摄影师.
想象一下,您正站在日历时间轴上,将摄像机对准在您面前的瞬时时间线上的人.您根据时区规则排列相机 - 由于夏令时,或由于您所在时区的法律定义的其他更改而定期更改.(你没有稳定的手,所以你的相机不稳定.)
站在照片中的人会看到相机来自的角度.如果其他人正在拍照,他们可能来自不同的角度.这就是代表的Offset
部分DateTimeOffset
.
因此,如果您将相机标记为"东部时间",有时您指向-5,有时您指向-4.世界各地都有摄像机,所有摄像机都标有不同的东西,并且从不同角度指向同一瞬时时间轴.其中一些是紧挨着(或在彼此之上),因此只知道偏移量不足以确定时间与哪个时区相关.
UTC怎么样?嗯,这是一台相机,保证有稳定的手.它在三脚架上,牢固地固定在地面上.它不会去任何地方.我们将其视角称为零偏移.
那么 - 这个类比告诉我们什么?它提供了一些直观的指导.
如果您特别表示相对于某个地方的时间,请在日历时间内用a表示DateTime
.请确保您不会将一个日历与另一个日历混淆. Unspecified
应该是你的假设. Local
只是有用来自DateTime.Now
.例如,我可能DateTime.Now
会将其保存并保存在数据库中 - 但是当我检索它时,我必须假设它是Unspecified
.我不能相信我的本地日历与最初拍摄的日历相同.
如果您必须始终确定当下,请确保您正在表示瞬时时间.使用DateTimeOffset
强制执行,或者使用UTC DateTime
通过约定.
如果您需要跟踪瞬时时刻,但您还想知道"用户在当地日历上的时间是什么时候?" - 那你必须用一个DateTimeOffset
.这对于计时系统非常重要,例如 - 无论是技术问题还是法律问题.
如果您需要修改以前记录的内容DateTimeOffset
- 仅在偏移量中没有足够的信息以确保新偏移量仍然与用户相关.您还必须存储时区标识符(想想 - 我需要该摄像机的名称,这样即使位置发生变化,我也可以拍摄新照片).
还应该指出,Noda Time有一个这样的表示ZonedDateTime
,而.Net基类库没有任何类似的东西.您需要同时存储a DateTimeOffset
和TimeZoneInfo.Id
值.
有时,您会希望表示"任何人正在查看它"的本地日历时间.例如,在定义今天的意义时.今天总是午夜到午夜,但这些代表了瞬时时间轴上几乎无限数量的重叠范围.(实际上我们有一个有限数量的时区,但是你可以将偏移量表示为勾号)所以在这些情况下,请确保你理解如何限制"谁在问?" 向下一个时区提问,或者处理将它们转换回适当的瞬时时间.
以下是关于DateTimeOffset
这个类比的一些其他一点点,以及保持它的一些提示:
如果比较两个DateTimeOffset
值,则在比较之前首先将它们标准化为零偏移.换句话说,2012-01-01T00:00:00+00:00
并2012-01-01T02:00:00+02:00
指代相同的瞬时时刻,因此是等价的.
如果你正在做的任何单元测试和需要肯定的偏移量,测试的两个的DateTimeOffset
值,和.Offset
财产分开.
.Net框架内置了一个单向隐式转换,允许您将DateTime
任何DateTimeOffset
参数或变量传递给它.这样做的.Kind
事情.如果你传递一个UTC一种,它将搭载与零偏移,但如果你通过两种.Local
或.Unspecified
,就会认为是本地.该框架基本上是在说:"嗯,你让我把日历时间转换为瞬间时间,但我不知道它来自哪里,所以我只想使用本地日历." 如果您DateTime
在具有不同时区的计算机上加载未指定的内容,则这是一个巨大的问题.(恕我直言 - 这应该抛出异常 - 但事实并非如此.)
无耻插头:
许多人与我分享他们发现这个类比非常有价值,所以我把它包括在我的Pluralsight课程,日期和时间基础.您将在标题为"日历时间与瞬时时间"的剪辑中找到第二个模块"上下文事项"中相机类比的逐步演练.
Cla*_*lay 290
来自微软:
DateTimeOffset值的这些用法比DateTime值的用法更常见.因此,应将DateTimeOffset视为应用程序开发的默认日期和时间类型.
来源:"在DateTime,DateTimeOffset,TimeSpan和TimeZoneInfo之间选择",MSDN
DateTimeOffset
当我们的应用程序处理特定时间点时(例如,创建/更新记录时),我们几乎可以使用所有内容.另外,我们DATETIMEOFFSET
也在SQL Server 2008中使用它.
DateTime
当你想要只处理日期,只处理时间或者在一般意义上处理时,我认为它是有用的.例如,如果你有一个警报,你想要每天早上7点起飞,你可以将其存储在DateTime
利用a中DateTimeKind
,Unspecified
因为你希望它在早上7点关闭,而不管DST.但是如果你想表示报警发生的历史,你会使用DateTimeOffset
.
使用混合时要特别小心DateTimeOffset
,DateTime
特别是在分配和比较类型时.此外,仅比较DateTime
相同的实例,DateTimeKind
因为DateTime
在比较时忽略时区偏移.
Han*_*ant 68
DateTime只能存储两个不同的时间,即本地时间和UTC.该种类属性表示.
DateTimeOffset通过能够从世界上任何地方存储本地时间来扩展此功能.它还存储本地时间和UTC之间的偏移量.请注意除非您向类中添加额外成员以存储该UTC偏移量,否则DateTime无法执行此操作.或者只使用UTC.这本身就是一个好主意btw.
Tes*_*act 48
DateTime.Now
12 月 21 日星期五 18:40:11
DateTimeOffset.Now
12 月 21 日星期五 18:40:11 +02:00
因此,DateTimeOffset
存储有关时间与 UTC(基本上是时区)如何关联的信息。
Dea*_*ing 33
有几个地方DateTimeOffset
有意义.一个是当你处理经常性事件和夏令时时.假设我想在每天上午9点设置闹钟.如果我使用"以UTC存储,显示为本地时间"规则,那么当夏令时生效时,闹钟将在不同的时间关闭.
可能还有其他的,但上面的例子实际上是我过去遇到的一个(这是在添加DateTimeOffset
到BCL之前 - 我当时的解决方案是明确地将时间存储在本地时区,并保存时区信息旁边:基本上是什么DateTimeOffset
内部).
Tri*_*nko 21
最重要的区别是DateTime不存储时区信息,而DateTimeOffset则存储时区信息.
尽管DateTime区分UTC和Local,但绝对没有与之关联的显式时区偏移.如果进行任何类型的序列化或转换,将使用服务器的时区.即使您通过添加分钟来手动创建本地时间来抵消UTC时间,您仍然可以在序列化步骤中获得位,因为(由于DateTime中没有任何显式偏移),它将使用服务器的时区偏移量.
例如,如果使用Json.Net和ISO日期格式序列化Kind = Local的DateTime值,您将获得类似的字符串2015-08-05T07:00:00-04
.请注意,最后一部分(-04)与您的DateTime或您用于计算它的任何偏移无关......它只是服务器的时区偏移量.
同时,DateTimeOffset显式包含偏移量.它可能不包括时区的名称,但至少它包含偏移量,如果序列化它,您将获得值中明确包含的偏移量,而不是服务器的本地时间.
Blu*_*ell 11
如果您不想阅读所有这些很棒的答案,请使用TLDR :-)
显式:
使用DateTimeOffset
是因为时区强制为 UTC+0。
隐式:
使用DateTime
您希望每个人都遵守时区始终为 UTC+0 的不成文规则的地方。
(开发人员的旁注:显式总是比隐式更好!)
(Java 开发人员的旁注,C# DateTimeOffset
== Java OffsetDateTime
,请阅读:https : //www.baeldung.com/java-zoneddatetime-offsetdatetime)
大多数答案都很好,但我想添加一些MSDN链接以获取更多信息
Microsoft的这段代码解释了所有内容:
// 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
Run Code Online (Sandbox Code Playgroud)
一个主要的区别是DateTimeOffset
可以与TimeZoneInfo
当前时间区域之外的时区转换为本地时间.
这在用户在不同时区访问的服务器应用程序(例如ASP.NET)上很有用.
归档时间: |
|
查看次数: |
187801 次 |
最近记录: |