Precisão do C # DateTime.Now

Acabei de me deparar com algum comportamento inesperado com o DateTime.UtcNow enquanto fazia alguns testes de unidade. Parece que quando você chama DateTime.Now/UtcNow em sucessão rápida, parece dar-lhe de volta o mesmo valor para um intervalo de tempo maior que o esperado, em vez de capturar incrementos de milissegundos mais precisos.

Eu sei que há uma class de cronômetro que seria mais adequada para fazer medições de tempo precisas, mas eu estava curioso para saber se alguém poderia explicar esse comportamento em DateTime? Existe uma precisão oficial documentada para DateTime.Now (por exemplo, precisa dentro de 50 ms?)? Por que DateTime.Now seria menos preciso do que a maioria dos clocks de CPU poderia suportar? Talvez seja apenas projetado para o menor CPU do denominador comum?

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

Por que DateTime.Now seria menos preciso do que a maioria dos clocks de CPU poderia suportar?

Um bom relógio deve ser preciso e exato ; esses são diferentes. Como diz a velha piada, um relógio parado é exatamente exato duas vezes por dia, um relógio um minuto devagar nunca é preciso a qualquer momento. Mas o relógio um minuto lento é sempre preciso ao minuto mais próximo, enquanto um relógio parado não tem precisão útil.

Por que o DateTime deve ser preciso , digamos, um microssegundo quando não pode ser preciso para o microsegundo? A maioria das pessoas não possui nenhuma fonte de sinais de tempo oficiais precisos para o microssegundo. Portanto, dando seis dígitos após a casa decimal de precisão , os cinco últimos dos quais são lixo estaria mentindo .

Lembre-se, o objective do DateTime é representar uma data e hora . Tempos de alta precisão não são de todo o propósito do DateTime; como você nota, esse é o propósito do StopWatch. O objective do DateTime é representar uma data e hora para fins como exibir a hora atual para o usuário, calcular o número de dias até a próxima terça-feira e assim por diante.

Em resumo, “que horas são?” e “quanto tempo isso levou?” são questões completamente diferentes; Não use uma ferramenta projetada para responder a uma pergunta para responder a outra.

Obrigado pela pergunta; isso vai fazer um bom artigo no blog! 🙂

A precisão do DateTime é um pouco específica para o sistema em que está sendo executado. A precisão está relacionada à velocidade de um switch de contexto, que tende a ser em torno de 15 ou 16 ms. (No meu sistema, na verdade, é cerca de 14 ms do meu teste, mas eu vi alguns laptops onde ele está mais próximo da precisão de 35-40 ms.)

Peter Bromberg escreveu um artigo sobre temporização de código de alta precisão em C #, que discute isso.

Eu gostaria de um Datetime.Now preciso :), então eu cozinhei isso:

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

Por que vale a pena, na verdade, na verdade, checando a fonte do .NET, Eric Lippert fez um comentário sobre essa questão, dizendo que o DateTime só tem precisão de aproximadamente 30 ms. O raciocínio para não ser nanossegundo exato, em suas palavras, é que “não precisa ser”.

Do MSDN você encontrará que DateTime.Now tem uma resolução aproximada de 10 milissegundos em todos os sistemas operacionais NT.

A precisão real é dependente de hardware. Melhor precisão pode ser obtida usando QueryPerformanceCounter .

Da documentação do MSDN :

A resolução desta propriedade depende do timer do sistema.

Eles também afirmam que a resolução aproximada no Windows NT 3.5 e posterior é de 10 ms 🙂