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


当前回答

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

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

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

其他回答

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

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

DateTime。UtcNow的行为与其他语言相似。它将tick设置为基于GMT的值。它还将Kind设置为Utc。

DateTime。现在将Ticks值更改为如果它是您在GMT时区中的一天时间。它还将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

正如您在这里看到的,比较和数学函数不会自动转换为兼容时间。时间间隔应该是将近一个小时,但实际上是将近6个小时。"utc < now"应该是真的(我甚至添加了一个小时来确保),但仍然是假的。

你也可以看到“周围的工作”,这是简单地转换为世界时的任何地方,Kind是不一样的。

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

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

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

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

如果您想使用支持时区的日期,请使用DateTimeOffset,它表示带有时区的日期/时间。这是我吃了不少苦头才明白的。

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

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

在。net中需要理解的一个主要概念是,现在是全世界的现在,无论你在哪个时区。如果你用DateTime加载一个变量。现在或日期时间。UtcNow——任务是一样的。您的DateTime对象知道您所在的时区,并将其考虑进来,而不考虑分配。

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

我写了一篇博客文章,进一步解释了TimeSpan,并包含了一个链接到关于该主题的更广泛的MS文章。

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