关于.net:DateTime.Now与DateTime.UtcNow

关于.net:DateTime.Now与DateTime.UtcNow

DateTime.Now vs. DateTime.UtcNow

我一直想知道这两个属性的工作原理到底是什么。 我知道第二个是通用的,基本上不涉及时区,但是有人可以详细解释它们的工作原理以及在哪种情况下应使用哪个?


DateTime.UtcNow告诉您日期和时间,与协调世界时一致,也称为格林威治标准时区-基本上就像您在英国伦敦一样,但不在夏季。 DateTime.Now给出日期和时间,就像在您当前语言环境中的某个人所看到的那样。

我建议您在向人类显示日期时使用DateTime.Now-这样他们就可以轻松地与自己看到的值相吻合-这是他们可以轻松将其与手表或时钟上看到的东西进行比较的东西。当您要存储日期或将其用于以后的计算时(在客户端-服务器模型中),请使用DateTime.UtcNow,以使您的计算不会被服务器或彼此不同时区的客户端混淆。


这确实非常简单,所以我认为这取决于您的受众群体和居住地。

如果您不使用Utc,则必须知道要向其显示日期和时间的人员所在的时区-否则,您将告诉他们系统或服务器时间在下午3点发生了什么,而实际上是在下午5点发生了什么,他们碰巧活着。

我们之所以使用DateTime.UtcNow是因为我们拥有全球的网络受众,并且因为我不希望每个用户都填写表格来表明他们所居住的时区。

我们还会显示相对时间(2小时前,1天前等),直到帖子老化为止,无论您居住在地球上的哪个地方,时间都是"相同的"。


还要注意性能差异; DateTime.UtcNow比DateTime.Now快30倍左右,因为内部DateTime.Now进行了大量的时区调整(您可以使用Reflector轻松地进行验证)。

因此,请勿将DateTime.Now用于相对时间测量。


在.NET中要理解的一个主要概念是,无论您处于哪个时区,现在都已遍及全球。因此,如果使用DateTime.NowDateTime.UtcNow加载变量,则分配是相同的。*您的< x5>对象会知道您所在的时区,并且不管分配如何都将其考虑在内。

在跨夏时制时间边界计算日期时,DateTime.UtcNow的有用之处就派上用场了。也就是说,在参与夏时制的地方,有时从第二天的中午到第二天的中午有25个小时,有时在第二天的中午到中午之间有23个小时。如果要正确确定从时间A和时间B开始的小时数,则需要先将每个小时转换为它们的UTC等效时间,然后再计算TimeSpan

我写的博客文章对此进行了介绍,该博客文章进一步解释了TimeSpan,并包括指向该主题的更广泛的MS文章的链接。

*说明:任何一项分配都会存储当前时间。如果要通过DateTime.Now()加载两个变量,而通过DateTime.UtcNow()加载另一个变量,则两个变量之间的TimeSpan差将是毫秒,而不是小时,前提是您所在的时区距离GMT时数小时。如下所述,打印出它们的String值将显示不同的字符串。


这是一个很好的问题。我正在恢复它,以提供更多有关.Net在不同的Kind值下的行为的详细信息。正如@Jan Zich指出的那样,它实际上是至关重要的属性,并且根据您使用Now还是UtcNow进行不同的设置。

在内部,日期存储为Ticks,具体取决于您使用的是Now还是UtcNow(与@Carl Camera的答案相反)。

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

DateTime.Now会将Ticks值更改为GMT时区中的一天中的时间。还将Kind设置为Local

如果您(GMT-6)比格林尼治标准时间(GMT-6)晚6个小时,那么您将获得格林尼治标准时间(GMT)6个小时前的时间。 .Net实际上会忽略Kind并将此时间视为6个小时前,即使它应该是"现在"。如果创建DateTime实例,然后更改时区并尝试使用它,则此中断会更大。

具有不同"种类"值的DateTime实例不兼容。

让我们看一些代码...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    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应该差不多是一个小时,但是应该差不多是6。" utc

您还可以看到"解决方法",它可以简单地将Kind不相同的任何地方转换为通用时间。

我对问题的直接回答与接受答案有关何时使用每个人的建议相一致。除了在I / O(显示和解析)期间,您应该始终尝试使用具有Kind=UtcDateTime对象。这意味着您几乎应该一直使用DateTime.UtcNow,除非您创建对象只是为了显示它并立即丢弃它。


DateTime不知道什么时区。它始终假定您在本地时间。 UtcNow仅表示"从时间中减去我的时区"。

如果要使用可识别时区的日期,请使用DateTimeOffset,它表示带有时区的日期/时间。我必须努力学习。


该问题的"简单"答案是:

DateTime.Now返回一个DateTime值,该值表示当前系统时间(在系统运行的任何时区中)。 DateTime.Kind属性将为DateTimeKind.Local

DateTime.UtcNow返回一个DateTime值,该值表示当前的通用协调时间(又称UTC),无论系统时区如何,该时间都相同。 DateTime.Kind属性将为DateTimeKind.Utc


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


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

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

在不同时区存储和显示日期和时间的建议


DateTime.UtcNow是一种通用时标,省略了夏令时。因此,UTC永远不会因为DST而改变。

但是,DateTime.Now不是连续的或单值的,因为它会根据DST进行更改。这意味着DateTime.Now,同一时间值可能出现两次,使客户处于混乱状态。


DateTime.UtcNow是连续的单值时间标度,而DateTime.Now不是连续的或单值的时标。主要原因是夏令时,不适用于UTC。因此,UTC永远不会向前或向后跳一个小时,而本地时间(DateTime.Now)会跳。当它向后跳时,同一时间值出现两次。


最大的区别是:)是SharePoint Workflow不支持DateTime.Now,您必须使用DateTime.UtcNow


当您需要在本地运行计算机时(例如,欧洲的CEST),请使用Now。如果您想要一个通用时间-UtcNow。只是您的喜好问题-可能制作一个您想使用用户时间的本地网站/独立应用程序-因此受其时区设置-DateTime.Now的影响。

请记住,对于网站而言,这是服务器的时区设置。因此,如果要为用户显示时间,请获取其首选的时区并更改时间(只需将Utc时间保存到数据库中,然后进行修改即可)或指定其为UTC。如果您忘记这样做,则用户会看到类似的内容:3分钟前发布,然后在将来某个时间发布:)


推荐阅读