我一直想知道这两个属性如何工作的原理到底是什么。我知道第二个是通用的,基本上不涉及时区,但是有人可以详细解释它们是如何工作的,在什么情况下应该使用哪个?
13 回答
DateTime.UtcNow告诉您日期和时间,就像协调世界时一样,也称为格林威治标准时区 - 基本上就像您在英国伦敦时一样,但不是在夏季。DateTime.Now给出日期和时间,就像您当前区域设置中的某个人看到的那样。
我建议DateTime.Now
您在向人类显示日期时使用 - 这样他们就会对他们看到的价值感到满意 - 他们可以轻松地将其与他们在手表或时钟上看到的内容进行比较。当您想存储日期或将它们用于以后的计算时使用DateTime.UtcNow
(在客户端-服务器模型中),您的计算不会被来自服务器或彼此不同时区的客户端混淆。
这真的很简单,所以我认为这取决于你的观众是什么以及他们住在哪里。
如果您不使用 Utc,则必须知道要向其显示日期和时间的人的时区 - 否则您会告诉他们某些事情发生在系统或服务器时间下午 3 点,而实际上发生在下午 5 点他们碰巧活着。
我们使用DateTime.UtcNow
是因为我们拥有全球网络受众,并且因为我不想唠叨每个用户填写一份表明他们居住在哪个时区的表格。
我们还显示相对时间(2 小时前、1 天前等),直到帖子的时间足够长,以至于无论您住在地球上的哪个地方,时间都是“相同的”。
还要注意性能差异;DateTime.UtcNow
then大约快30倍DateTime.Now
,因为内部DateTime.Now
正在进行大量的时区调整(您可以使用 Reflector 轻松验证这一点)。
所以不要DateTime.Now
用于相对时间测量。
在 .NET 中要理解的一个主要概念是,无论您在哪个时区,现在都遍布全球。因此,如果您使用or加载变量- 分配是相同的。*您的对象知道您所在的时区并考虑到这一点,无论分配如何。DateTime.Now
DateTime.UtcNow
DateTime
DateTime.UtcNow
在计算夏令时边界的日期时,的用处会派上用场。即在参与夏令时的地方,有时从中午到次日中午有25小时,有时从中午到次日中午有23小时。如果要正确确定从时间 A 到时间 B 的小时数,则需要先将每个时间转换为它们的 UTC 等效值,然后再计算TimeSpan
.
我写的一篇博文对此进行了进一步解释TimeSpan
,并包含一个链接,指向关于该主题的更广泛的 MS 文章。
*澄清:任一项分配都将存储当前时间。如果您要加载两个变量,一个通过DateTime.Now()
,另一个通过DateTime.UtcNow()
,TimeSpan
两者之间的差异将是毫秒,而不是几个小时,假设您在距离 GMT 几个小时的时区。如下所述,打印出它们的String
值将显示不同的字符串。
这是一个很好的问题。我正在恢复它,以更详细地说明 .Net 在不同Kind
值下的行为方式。正如@Jan Zich 指出的那样,它实际上是一个非常重要的属性,并且根据您使用Now
或UtcNow
.
在内部,日期存储为Ticks
哪个(与@Carl Camera 的答案相反)取决于您是否使用Now
或UtcNow
。
DateTime.UtcNow
表现得像其他语言。它设置Ticks
为基于 GMT 的值。它也设置Kind
为Utc
。
DateTime.Now
Ticks
将值更改为如果它是您在 GMT 时区中的一天中的时间。它也设置Kind
为Local
。
如果您落后 6 小时 (GMT-6),您将获得 6 小时前的 GMT 时间。.Net 实际上忽略Kind
并将这个时间视为 6 小时前,即使它应该是“现在”。如果您创建一个DateTime
实例然后更改您的时区并尝试使用它,那么这会更糟。
具有不同“种类”值的 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
,除了您创建对象只是为了显示它并立即丢弃它的情况。
DateTime 不知道时区是什么。它始终假定您在当地时间。UtcNow仅表示“从时间中减去我的时区”。
如果要使用时区感知日期,请使用DateTimeOffset,它表示带有时区的日期/时间。我不得不以艰难的方式学习这一点。
这个问题的“简单”答案是:
DateTime.Now返回一个代表当前系统时间的DateTime值(在系统运行的任何时区)。DateTime.Kind属性将为DateTimeKind.Local
DateTime.UtcNow返回一个代表当前通用协调时间(又名 UTC)的DateTime值,无论系统的时区如何,该值都是相同的。DateTime.Kind属性将为DateTimeKind.Utc
只是对上述几点的补充:DateTime 结构还包含一个鲜为人知的字段,称为Kind(至少,我很长一段时间都不知道它)。它基本上只是一个指示时间是本地时间还是 UTC 的标志;它没有指定当地时间与 UTC 的实际偏移量。除了表明构造结构的意图之外,它还影响ToUniversalTime()和ToLocalTime()方法的工作方式。
DateTime.UtcNow 是一个省略夏令时的通用时间刻度。因此,UTC 永远不会因为 DST 而改变。
但是, DateTime.Now 不是连续的或单值的,因为它会根据 DST 变化。这意味着 DateTime.Now,相同的时间值可能会出现两次,使客户处于困惑状态。
当您需要运行应用程序的机器的本地时间时(例如欧洲的 CEST),请使用 Now。如果您想要一个通用时间 - UtcNow。这只是您的偏好问题 - 可能制作一个本地网站/独立应用程序,您想要使用用户拥有的时间 - 因此受他/她的时区设置 - DateTime.Now 的影响。
请记住,对于网站,它是服务器的时区设置。因此,如果您要为用户显示时间,请获取他的首选时区并更改时间(只需将 Utc 时间保存到数据库中,然后对其进行修改)或指定其为 UTC。如果您忘记这样做,用户可能会看到类似的内容:在 3 个减号前发布,然后在未来某个时间附近发布 :)
DateTime.UtcNow 是一个连续的单值时间刻度,而 DateTime.Now 不是连续的或单值的。主要原因是夏令时,它不适用于 UTC。所以 UTC 永远不会向前或向后跳一个小时,而本地时间 (DateTime.Now) 会。而当它向后跳时,相同的时间值会出现两次。
最大的区别 :) 是 SharePoint 工作流不支持 DateTime.Now,您必须使用 DateTime.UtcNow