DateTime.Now与DateTime.UtcNow

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

DateTime.UtcNow告诉你date和时间,因为它会在协调世界时,这也被称为格林威治标准时间的时区 – 基本上,如果你是在英国伦敦,而不是在夏天。 DateTime.Now给出了当前语言环境中的某个人显示的date和时间。

我build议使用DateTime.Now无论何时向人显示一个date – 这样他们就会对他们看到的价值感到满意 – 这是他们可以轻松地比较他们在他们的手表或钟表上看到的东西。 使用DateTime.UtcNow当你想存储date或者将它们用于以后的计算(在一个客户端 – 服务器模型中)时,你的计算不会被来自服务器的不同时区的客户端或者彼此混淆。

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

如果你不使用Utc,你必须知道你正在显示的date和时间的人的时区 – 否则你会告诉他们在下午3点在系统或服务器时间发生的事情,当它真的发生在下午5点他们碰巧住。

我们使用DateTime.UtcNow因为我们有一个全球性的networking用户,而且我不希望每个用户都填写一个表格来指明他们居住在哪个时区。

我们还会显示相对时间(2小时前,1天前等),直到时间足够长,无论您居住在哪个地方,时间都是“相同的”。

在.NET中理解的一个主要概念是, 现在无论您在什么时区, 现在都遍布全球。因此,如果您使用DateTime.Now或DateTime.UtcNow加载variables – 赋值是相同的。*您的DateTime对象知道你在什么时区,并把它考虑在内,而不pipe分配。

计算日光节约时间边界时,DateTime.UtcNow的用处非常方便。 也就是说,在参加夏令时的地方,有时从中午到中午有25个小时,有时在中午到中午之间有23个小时。 如果要正确确定时间A和时间B的小时数,则在计算TimeSpan之前,需要首先将其转换为UTC的当量。

这篇文章由我撰写的一篇博客文章所覆盖,这个文章进一步解释了TimeSpan,并且包含了关于该主题的更多MS文章的链接。

*澄清:分配将存储当前时间。 如果要通过DateTime.Now()加载两个variables,而通过DateTime.UtcNow()加载另一个variables,那么两者之间的TimeSpan差异将是毫秒,而不是几小时,假定您在距GMT的时区数小时。 如下所述,打印出它们的string值将显示不同的string。

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

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

这是一个很好的问题。 我正在重振它,以更详细地介绍.Net如何以不同的“Kind”值运行。 正如@Jan Zich指出的那样,这实际上是一个非常重要的属性,根据您使用Now还是UtcNow而设置不同。

在内部,date存储为“滴答”(与@Carl Camera的答案相反)根据使用Now或UtcNow而不同。

DateTime.UtcNow的行为像其他语言。 它将Ticks设置为基于GMT的值。 它也把“Kind”设置为“Utc”。

DateTime.Now将Ticks值更改为GMT时区内的date 。 它也把'Kind'设置为'Local'。

如果你落后了6个小时(GMT-6),你将从6小时前获得GMT时间。 .Net实际上忽略了'Kind',把这个时间看作是6个小时以前,即使它应该是“现在”。 如果你创build一个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 

正如你在这里看到的,比较和math函数不会自动转换为兼容的时间。 时间跨度应该是差不多一个小时,而差不多是六个。“utc <now”应该是真实的(我甚至增加了一个小时),但仍然是错误的。

你也可以看到“变通”,就是在“种类”不一样的地方简单地转换为世界时。

我对这个问题的直接回答与已接受答案的build议是一致的,即何时使用每个问题。 除了在I / O(显示和parsing)期间,您应该总是尝试使用Kind = Utc的DateTime对象。 这意味着你应该几乎总是使用DateTime.UtcNow,除了创build对象的情况只是为了显示它,并立即丢弃它。

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

如果要使用时区感知date,请使用DateTimeOffset ,它表示具有时区的date/时间。 我必须学习这个艰难的方法。

除了以上几点之外,DateTime结构还包含一个名为Kind的小字段(至less,我不知道这个字段很长时间)。 它基本上只是一个标志,指示时间是本地还是UTC; 它没有指定当地时间UTC的实际偏移量。 除了这个事实,它表明了这个构造的意图是什么,它也影响了ToUniversalTime()和ToLocalTime()方法的工作方式。

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

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

存储和显示不同时区的date和时间的build议

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

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

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

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

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

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