104

我只是在进行一些单元测试时遇到了 DateTime.UtcNow 的一些意外行为。看来,当您快速连续调用 DateTime.Now/UtcNow 时,它似乎会在比预期更长的时间间隔内返回相同的值,而不是捕获更精确的毫秒增量。

我知道有一个更适合进行精确时间测量的 Stopwatch 类,但我很好奇是否有人可以在 DateTime 中解释这种行为?是否记录了 DateTime.Now 的官方精度(例如,精确到 50 毫秒?)?为什么 DateTime.Now 的精度低于大多数 CPU 时钟可以处理的精度?也许它只是为最低公分母 CPU 设计的?

public static void Main(string[] args)
{
    var stopwatch = new Stopwatch();
    stopwatch.Start();
    for (int i=0; i<1000; i++)
    {
        var now = DateTime.Now;
        Console.WriteLine(string.Format(
            "Ticks: {0}\tMilliseconds: {1}", now.Ticks, now.Millisecond));
    }

    stopwatch.Stop();
    Console.WriteLine("Stopwatch.ElapsedMilliseconds: {0}",
        stopwatch.ElapsedMilliseconds);

    Console.ReadLine();
}
4

7 回答 7

203

为什么 DateTime.Now 的精度低于大多数 CPU 时钟可以处理的精度?

一个好的时钟应该既精确准确;那些是不同的。正如老笑话所说,停止的时钟一天准确两次,慢一分钟的时钟在任何时候都不准确。但是慢一分钟的时钟总是精确到最近的分钟,而停止的时钟根本没有有用的精度。

当 DateTime 不可能精确到微秒时,为什么要精确到微秒?大多数人没有任何精确到微秒的官方时间信号来源。因此,给出小数点后六位的精度,最后五位是垃圾,那就是说谎

请记住, DateTime 的目的是表示日期和时间。高精度计时根本不是 DateTime 的目的。正如您所注意到的,这就是 StopWatch 的目的。DateTime 的目的是表示日期和时间,用于向用户显示当前时间、计算距离下周二的天数等。

简而言之,“现在几点了?” “这需要多长时间?” 是完全不同的问题;不要使用旨在回答一个问题的工具来回答另一个问题。

感谢您的提问;这将是一篇很好的博客文章!:-)

于 2010-01-27T00:36:30.623 回答
18

DateTime 的精度在某种程度上特定于它正在运行的系统。精度与上下文切换的速度有关,通常在 15 或 16 毫秒左右。(在我的系统上,我的测试实际上大约需要 14 毫秒,但我见过一些笔记本电脑的准确度接近 35-40 毫秒。)

Peter Bromberg 写了一篇关于C# 中高精度代码时序的文章,其中讨论了这一点。

于 2010-01-26T22:28:33.600 回答
12

我想要一个精确的 Datetime.Now :),所以我做了这个:

public class PreciseDatetime
{
    // using DateTime.Now resulted in many many log events with the same timestamp.
    // use static variables in case there are many instances of this class in use in the same program
    // (that way they will all be in sync)
    private static readonly Stopwatch myStopwatch = new Stopwatch();
    private static System.DateTime myStopwatchStartTime;

    static PreciseDatetime()
    {
        Reset();

        try
        {
            // In case the system clock gets updated
            SystemEvents.TimeChanged += SystemEvents_TimeChanged;
        }
        catch (Exception)
        {                
        }
    }

    static void SystemEvents_TimeChanged(object sender, EventArgs e)
    {
        Reset();
    }

    // SystemEvents.TimeChanged can be slow to fire (3 secs), so allow forcing of reset
    static public void Reset()
    {
        myStopwatchStartTime = System.DateTime.Now;
        myStopwatch.Restart();
    }

    public System.DateTime Now { get { return myStopwatchStartTime.Add(myStopwatch.Elapsed); } }
}
于 2013-02-21T17:42:51.217 回答
6

对于它的价值,除了实际检查 .NET 源代码之外,Eric Lippert对这个 SO 问题提供了评论,说 DateTime 仅精确到大约 30 毫秒。用他的话来说,不精确到纳秒的原因是它“不需要”。

于 2010-01-26T22:28:09.530 回答
6

MSDN你会发现它在所有 NT 操作系统上DateTime.Now的分辨率大约为 10 毫秒。

实际精度取决于硬件。使用 可以获得更好的精度QueryPerformanceCounter

于 2010-01-26T22:28:50.257 回答
3

从 MSDN 文档

此属性的分辨率取决于系统计时器。

他们还声称 Windows NT 3.5 及更高版本的近似分辨率为 10 毫秒 :)

于 2010-01-26T22:28:09.837 回答
1

此属性的分辨率取决于系统计时器,而系统计时器取决于底层操作系统。它往往在 0.5 到 15 毫秒之间。

因此,在很短的时间间隔内(例如在循环中)重复调用 Now 属性可能会返回相同的值。

MSDN 链接

于 2019-02-04T11:37:31.223 回答