Точность С# DateTime.Now

Я просто столкнулся с каким-то неожиданным поведением с DateTime.UtcNow, выполняя некоторые модульные тесты. Похоже, что когда вы вызываете DateTime.Now/UtcNow с быстрой последовательностью, похоже, вы возвращаете то же значение для более длительного, чем ожидалось, времени, а не для получения более точных миллисекундных приращений.

Я знаю, что есть класс секундомера, который лучше подходит для выполнения точных измерений времени, но мне было любопытно, может ли кто-нибудь объяснить это поведение в DateTime? Есть ли официальная точность, документированная для DateTime.Now(например, с точностью до 50 мкс?)? Почему DateTime.Now будет менее точной, чем то, что может обрабатывать большинство процессорных часов? Может быть, он просто предназначен для самого низкого общего процессора знаменателей?

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();
}

Ответ 1

Почему DateTime.Now будет менее точной, чем то, что может обрабатывать большинство процессорных часов?

Хорошие часы должны быть точными и точными; они разные. Как говорится в старой шутке, остановленные часы точно точны два раза в день, часы в минуту медленные никогда не точны в любое время. Но часы в минуту медленные всегда точны до ближайшей минуты, тогда как остановленные часы не имеют никакой полезной точности вообще.

Почему DateTime должен быть точным, скажем, микросекундой, когда он не может быть точным до микросекунды? У большинства людей нет источников официальных сигналов времени, которые точны до микросекунды. Поэтому давая шесть цифр после десятичной точки точности, последние пять из которых будут мусором, будут лгать.

Помните, что целью DateTime является представление даты и времени. Высокоточные тайминги вовсе не являются целью DateTime; как вы заметили, что цель StopWatch. Цель DateTime - представлять дату и время для таких целей, как отображение текущего времени пользователю, вычисление количества дней до следующего вторника и т.д.

Короче говоря, "в какое время?" и "как долго это продолжалось?" - совершенно разные вопросы; не используйте инструмент, предназначенный для ответа на один вопрос, чтобы ответить другому.

Спасибо за вопрос; это сделает хорошую статью в блоге!: -)

Ответ 2

Точность DateTime в некоторой степени зависит от системы, на которой он работает. Точность связана со скоростью переключения контекста, которая обычно составляет около 15 или 16 мс. (В моей системе это на самом деле около 14 мс от моего тестирования, но я видел некоторые ноутбуки, где точность приближалась к 35-40 мс.)

Питер Бромберг написал статью о высокоточной синхронизации кода в С#, в которой обсуждается это.

Ответ 3

Я хотел бы получить точное 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); } }
}

Ответ 4

Для того, что стоит, если не проверить подлинность источника .NET, Эрик Липперт предоставил комментарий к этому SO-вопросу, в котором говорилось, что DateTime имеет точность только приблизительно 30 мс, Причиной того, что он не является наносекундным, по его словам, является то, что ему "не нужно быть".

Ответ 5

Из MSDN вы обнаружите, что DateTime.Now имеет приблизительное разрешение 10 миллисекунд во всех операционных системах NT.

Фактическая точность зависит от оборудования. Лучшая точность может быть достигнута с помощью QueryPerformanceCounter.

Ответ 6

Из документации MSDN:

Разрешение этого свойства зависит от системного таймера.

Они также утверждают, что приблизительное разрешение для Windows NT 3.5 и более поздних версий составляет 10 мкс:)

Ответ 7

Разрешение этого свойства зависит от системного таймера, который зависит от базовой операционной системы. Обычно она составляет от 0,5 до 15 миллисекунд.

В результате повторные вызовы свойства Now за короткий промежуток времени, например в цикле, могут возвращать одно и то же значение.

MSDN Link