DateTime。Now和DateTime。UtcNow

我一直在想,这两个属性的工作原理究竟是什么。我知道第二个是通用的,基本上不涉及时区,但谁能详细解释一下它们是如何工作的,以及在什么情况下应该使用哪个?

250826 次浏览

DateTime。UtcNow告诉你的日期和时间是在协调世界时,也被称为格林威治标准时间时区-基本上就像如果你在英国伦敦,但不是在夏天。DateTime。现在给出日期和时间,因为它将显示在您当前地区的某人。

我建议使用DateTime.Now每当你显示一个日期给一个人-这样他们对他们看到的值感到舒服-这是他们可以很容易地比较他们在手表或时钟上看到的东西。当你想要存储日期或在以后的计算中使用它们时,使用DateTime.UtcNow,这样(在客户机-服务器模型中)你的计算不会被位于不同时区的客户机与服务器或彼此混淆。

这真的很简单,所以我认为这取决于你的受众是什么以及他们生活在哪里。

如果你不使用Utc,你必须知道你要显示日期和时间的对象的时区——否则你会告诉他们系统时间或服务器时间下午3点发生的事情,而实际上发生在他们碰巧居住的下午5点。

我们使用DateTime.UtcNow,因为我们有一个全球网络受众,因为我不想唠叨每个用户填写一个表格,表明他们生活在哪个时区。

我们还显示相对时间(2小时前,1天前,等等),直到帖子年龄足够大,无论你住在地球上的哪个地方,时间都是“相同的”。

当您需要应用程序运行的机器的本地时间(例如欧洲的CEST时间)时,请使用Now。如果你想要一个通用时间- UtcNow。这只是你的喜好的问题-可能做一个本地网站/独立的应用程序,你想使用的时间用户有-所以受他/她的时区设置- DateTime.Now。

记住,对于一个网站来说,它是服务器的时区设置。因此,如果您正在为用户显示时间,要么获取他的首选时区并移动时间(只需将Utc时间保存到数据库并修改它),要么指定它为Utc。如果你忘记这样做,用户可以看到类似3分钟前发布的的东西,然后在它附近的未来时间:)

DateTime不知道时区是什么。它总是假设你在当地时间。UtcNow只表示“从时间中减去我的时区”。

如果你想使用能识别时区的日期,可以使用DateTimeOffset,它表示一个带时区的日期/时间。这是我吃了不少苦头才明白的。

在. net中需要理解的一个主要概念是,无论你在哪个时区,现在在地球上都是现在。因此,如果你用DateTime.NowDateTime.UtcNow加载一个变量——赋值是相同的。*你的DateTime对象知道你所在的时区,并且不管赋值如何都会考虑到这一点。

在计算跨越夏令时边界的日期时,DateTime.UtcNow的有用性非常方便。即在参加夏令时的地方,有时从中午到第二天中午有25个小时,有时从中午到第二天中午有23个小时。如果你想正确地确定时间A和时间B的小时数,你需要在计算TimeSpan之前,先将它们转换为对应的UTC时间。

这由我写的博客所涵盖,它进一步解释了TimeSpan,并包括一个链接到关于该主题的更广泛的MS文章。

*澄清:任何赋值都将存储当前时间。如果你要加载两个变量,一个是通过DateTime.Now()加载,另一个是通过DateTime.UtcNow()加载,这两个变量之间的TimeSpan差异将是毫秒,而不是小时,假设你所在的时区与GMT时间不同。如下所述,打印出它们的String值将显示不同的字符串。

还要注意性能差异;DateTime.UtcNowDateTime.Now快大约30.倍,因为在内部DateTime.Now做了很多时区调整(你可以很容易地用Reflector验证这一点)。

所以不要使用DateTime.Now进行相对时间测量。

只是对上述观点的一点补充:DateTime结构体还包含一个鲜为人知的名为种类的字段(至少,我很长时间都不知道它)。它基本上只是一个标志,指示时间是本地时间还是UTC时间;它不指定本地时间与UTC的实际偏移量。除了表明构造结构的意图之外,它还影响方法ToUniversalTime ()ToLocalTime ()的工作方式。

有点晚了,但我发现这两个链接(4guysfromrolla)非常有用:

使用协调世界时(UTC)存储日期/时间值

跨时区存储和显示日期和时间的建议

这个问题的“简单”答案是:

DateTime。现在返回一个DateTime值,表示当前系统时间(无论系统运行在哪个时区)。DateTime。种类属性将是DateTimeKind。当地的

DateTime。UtcNow返回一个表示当前通用协调时间(UTC)的DateTime值,该值与系统的时区无关。DateTime。种类属性将是DateTimeKind。Utc

DateTime。UtcNow是一个连续的单值时间刻度,而DateTime。Now不是连续的或单值的。主要原因是日光节约时间,它不适用于协调世界时。因此UTC不会向前或向后跳一个小时,而本地时间(DateTime.Now)则会。当它向后跳转时,相同的时间值出现两次。

这是个好问题。我正在恢复它,以更详细地说明. net如何处理不同的Kind值。正如@Jan Zich指出的那样,它实际上是一个非常重要的属性,并且根据你是使用Now还是UtcNow而设置不同。

在内部,日期存储为Ticks(与@Carl Camera的答案相反),这取决于您是否使用NowUtcNow

DateTime.UtcNow的行为类似于其他语言。它将Ticks设置为基于GMT的值。它还将Kind设置为Utc

DateTime.NowTicks值更改为如果这是你在格林尼治时区的时间,会是多少。它还将Kind设置为Local

如果你晚了6小时(GMT-6),你将得到6小时前的GMT时间。. net实际上忽略Kind,并将此时间视为6小时前的时间,即使它应该是“现在”。如果你创建了一个DateTime实例,然后改变你的时区并尝试使用它,这会破坏得更严重。

具有不同“Kind”值的DateTime实例不兼容。

让我们看一些代码……

    DateTime utc = DateTime.UtcNow;
DateTime now = DateTime.Now;
Debug.Log (utc + " " + utc.Kind);  // 05/20/2015 17:19:27 Utc
Debug.Log (now + " " + now.Kind);  // 05/20/2015 10:19:27 Local


Debug.Log (utc.Ticks);  // 635677391678617830
Debug.Log (now.Ticks);  // 635677139678617840


now = now.AddHours(1);
TimeSpan diff = utc - now;
Debug.Log (diff);  // 05:59:59.9999990


Debug.Log (utc <  now);  // false
Debug.Log (utc == now);  // false
Debug.Log (utc >  now);  // true


Debug.Log (utc.ToUniversalTime() <  now.ToUniversalTime());  // true
Debug.Log (utc.ToUniversalTime() == now.ToUniversalTime());  // false
Debug.Log (utc.ToUniversalTime() >  now.ToUniversalTime());  // false
Debug.Log (utc.ToUniversalTime() -  now.ToUniversalTime());  // -01:00:00.0000010

正如您在这里看到的,比较和数学函数不会自动转换为兼容时间。Timespan应该是近1小时,但实际上是近6小时。“utc & lt;“现在”应该是正确的(我甚至加了一个小时来确定),但仍然是错误的。

你还可以看到“work around”,即在Kind不相同的地方简单地转换为世界时。

我对这个问题的直接回答与公认答案中关于何时使用每种语言的建议一致。你应该总是试一试来处理具有Kind=UtcDateTime对象,除非在i/o期间(显示和解析)。这意味着你应该总是使用DateTime.UtcNow,除非你创建对象只是为了显示它,然后立即丢弃它。

DateTime。UtcNow是省略日光节约时间的通用时间刻度。所以UTC时间不会因为夏令时而改变。

但是,DateTime。Now不是连续的或单值的,因为它根据DST变化。也就是DateTime。现在,相同的时间值可能会出现两次,让客户处于困惑的状态。

最大的区别:)是DateTime。现在SharePoint工作流不支持,您必须使用DateTime。UtcNow