it-swarm.cn

DateTime.Now与DateTime.UtcNow

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

192
Slavo

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

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

304
Blair Conrad

这真的很简单,所以我认为这取决于你的观众和他们的居住地。

如果您不使用Utc,您 必须 知道您显示日期和时间的人的时区 - 否则您将告诉他们在系统或服务器中3 PM发生的事情时间,当它真正发生在5 PM时,他们碰巧住了。

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

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

80
Jeff Atwood

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

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

29
Magnus Krisell

在.NET中理解的一个主要概念是 now is now 无论你在什么时区都在地球上。所以如果你用DateTime.NowDateTime.UtcNow加载一个变量 - 赋值是相同的。*您的DateTime对象知道您所在的时区,并将其考虑在内,无论分配如何。

在计算夏令时时间边界的日期时,DateTime.UtcNow的用处非常有用。也就是说,在参与夏令时的地方,有时从第二天中午到中午有25个小时,有时在第二天中午和中午之间有23个小时。如果要正确确定从时间A和时间B开始的小时数,则需要先计算每个等效时间,然后再计算TimeSpan

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

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

26
Carl Camera

这是一个很好的问题。我正在恢复它以更详细地介绍.Net如何使用不同的Kind值进行操作。正如@Jan Zich指出的那样,它实际上是一个至关重要的属性,根据你是否使用NowUtcNow而设置不同。

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

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

DateTime.NowTicks值改为 如果是你在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

正如您在此处看到的,比较和数学函数不会自动转换为兼容时间。 Timespan应该差不多一个小时,但差不多是6.“utc <now”应该是真的(我甚至还加了一个小时),但仍然是假的。

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

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

14
Ted Bigham

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

如果要使用时区感知日期,请使用 DateTimeOffset ,它表示带有时区的日期/时间。我不得不学习那种艰难的方式。

6
Omer van Kloeten

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

DateTime.Now 返回一个 DateTime 表示当前系统时间的值(在系统运行的任何时区)。 DateTime.Kind property将是 DateTimeKind.Local

DateTime.UtcNow 返回 DateTime 表示当前通用协调时间(也称为UTC)的值,无论系统的时区如何,它都是相同的。 DateTime.Kind property将是 DateTimeKind.Utc

4
PapillonUK

只是对上面提到的点的一点补充:DateTime结构还包含一个名为 Kind 的一个小的已知字段(至少,我很长时间都不知道它)。它基本上只是一个标志,表明时间是本地还是UTC;它没有为本地时间指定UTC的实际偏移量。除了它表明结构构造的意图,它还影响方法的方式 ToUniversalTime()ToLocalTime() work。

4
Jan Zich

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

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

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

2
Sorin Comanescu

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

1
user1315023

DateTime.UtcNow是省略夏令时的通用时间刻度。所以UTC永远不会因DST而改变。

但是,DateTime.Now不是连续的或单值的,因为它根据DST而变化。这意味着DateTime.Now,同一时间值可能会发生两次,使客户处于困惑状态。

1
ChaiVan

如果您的应用程序需要本地时间(例如欧洲的CEST),请立即使用。如果你想要一个普遍的时间 - UtcNow。这只是你的偏好问题 - 可能是你想要使用用户所用时间的本地网站/独立应用程序 - 受他/她的时区设置影响 - DateTime.Now。

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

0
kender