DateTime.Now与DateTime.UtcNow

时间:2008-09-15 10:57:42

标签: .net language-features date

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

13 个答案:

答案 0 :(得分:305)

DateTime.UtcNow告诉你协调世界时的日期和时间,它也被称为格林威治标准时间时区 - 基本上就像你在英国伦敦一样,但不是在夏季。 DateTime.Now提供当前区域设置中某人所看到的日期和时间。

我建议您在向人类展示日期时使用DateTime.Now - 这样他们对自己看到的价值感到满意 - 这是他们可以轻松地与他们在手表或时钟。如果要存储日期或使用DateTime.UtcNow进行以后的计算(在客户端 - 服务器模型中),您的计算不会被服务器或彼此不同时区的客户端混淆,请使用{{1}}。 / p>

答案 1 :(得分:80)

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

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

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

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

答案 2 :(得分:29)

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

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

答案 3 :(得分:26)

在.NET中要理解的一个主要概念是,现在在全球范围内现在,无论您在哪个时区。所以如果您加载一个变量DateTime.NowDateTime.UtcNow - 分配相同。*您的DateTime对象知道您所在的时区,并将其考虑在内,无论分配如何。

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

blog post i wrote涵盖了这一点,进一步解释了TimeSpan,其中包含指向该主题的更为广泛的MS文章的链接。

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

答案 4 :(得分:14)

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

在内部,日期存储为Ticks(与@Carl相机的答案相反),具体取决于您使用的是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个。&#34; utc&lt;现在&#34;应该是真的(我甚至加了一个小时来确定),但仍然是假的。

您还可以看到&#39;解决问题&#39;这只是在Kind不同的任何地方转换为通用时间。

我对该问题的直接回答与已接受的答案有关何时使用每个答案的建议一致。除了在i / o(显示和解析)期间,您应始终尝试使用DateTime Kind=UtcDateTime.UtcNow对象。这意味着您应该几乎总是使用 DataTable dtDestination = new DataTable(); DataTable dtSource = new DataTable(); dtSource.Columns.Add("Str1"); dtSource.Columns.Add("Str2"); dtDestination.Columns.Add("Str0"); dtDestination.Columns.Add("Str1"); dtDestination.Columns.Add("Str2"); dtSource.Rows.Add("Foo", "Bar"); dtSource.Rows.Add("Bob", "Smith"); foreach (DataRow drSrc in dtSource.Rows) { DataRow drNew = dtDestination.NewRow(); var array = new object[drSrc.ItemArray.Length]; array[0] = "My"; Array.Copy(drSrc.ItemArray, 0, array, 1, drSrc.ItemArray.Length); drNew.ItemArray = array; dtDestination.Rows.Add(drNew); } ,除非您创建对象只是为了显示它,并立即丢弃它。

答案 5 :(得分:6)

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

如果您想使用时区感知日期,请使用 DateTimeOffset ,它表示带有时区的日期/时间。我必须从困难的方式学习。

答案 6 :(得分:4)

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

答案 7 :(得分:4)

问题的“简单”答案是:

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

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

答案 8 :(得分:2)

答案 9 :(得分:1)

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

答案 10 :(得分:1)

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

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

答案 11 :(得分:0)

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

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

答案 12 :(得分:0)

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