Pergunta

Acabei de encontrar um comportamento inesperado com DateTime.UtcNow ao fazer alguns testes de unidade.Parece que quando você chama DateTime.Now/UtcNow em rápida sucessão, parece retornar o mesmo valor por um intervalo de tempo maior que o esperado, em vez de capturar incrementos de milissegundos mais precisos.

Eu sei que existe uma classe Stopwatch que seria mais adequada para fazer medições precisas de tempo, mas fiquei curioso para saber se alguém poderia explicar esse comportamento em DateTime.Existe uma precisão oficial documentada para DateTime.Now (por exemplo, com precisão de 50 ms?)?Por que DateTime.Now seria menos preciso do que a maioria dos relógios de CPU poderia suportar?Talvez tenha sido projetado apenas para a CPU de menor 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();
}
Foi útil?

Solução

Por que o DateTime. agora seria menos preciso do que a maioria dos relógios da CPU poderia suportar?

Um bom relógio deve ser ambos preciso e exato; esses são diferentes. À medida que a piada antiga passa, um relógio parado é exatamente preciso duas vezes por dia, um relógio um minuto lento nunca é preciso a qualquer momento. Mas o relógio um minuto lento é sempre preciso para o minuto mais próximo, enquanto um relógio parado não tem precisão útil.

Por que o DateTime deve ser preciso para dizer um microssegundo quando não pode ser exato para o microssegundo? A maioria das pessoas não possui nenhuma fonte para sinais de tempo oficiais precisos para o microssegundo. Portanto, dando seis dígitos após o lugar decimal de precisão, os últimos cinco são lixo seria deitado.

Lembre -se, o objetivo do DateTime é Representar uma data e hora. Os horários de alta precisão não têm todo o objetivo do DateTime; Como você observa, esse é o objetivo do StopWatch. O objetivo do DateTime é representar uma data e hora para fins, como exibir o horário atual para o usuário, calcular o número de dias até a próxima terça -feira e assim por diante.

Em suma, "que horas são?" e "Quanto tempo isso demorou?" são questões completamente diferentes; Não use uma ferramenta projetada para responder a uma pergunta para responder ao outro.

Obrigado pela pergunta; Isso fará um bom artigo do blog! :-)

Outras dicas

A precisão do DateTime é um tanto específica para o sistema em que está sendo executado.A precisão está relacionada à velocidade de uma troca de contexto, que tende a ficar em torno de 15 ou 16 ms.(No meu sistema, na verdade, são cerca de 14 ms dos meus testes, mas vi alguns laptops em que a precisão está mais próxima de 35 a 40 ms.)

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

Eu gostaria de um dateTETime preciso: :), então 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); } }
}

A partir de Msdn Você encontrará isso DateTime.Now tem um aproximado Resolução de 10 milissegundos em todos os sistemas operacionais do NT.

A precisão real depende do hardware. Melhor precisão pode ser obtida usando QueryPerformanceCounter.

Pelo que vale a pena, com falta de verificação da fonte .NET, Eric Lippert forneceu um comentário sobre isso é tão pergunta Dizer que o DateTime é preciso apenas para aproximadamente 30 ms. O raciocínio por não ser nanossegundo preciso, em suas palavras, é que "não precisa ser".

Da documentação do MSDN:

A resolução dessa propriedade depende do cronômetro do sistema.

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

A resolução dessa propriedade depende do cronômetro do sistema, que depende do sistema operacional subjacente. Tende a ser entre 0,5 e 15 milissegundos.

Como resultado, chamadas repetidas para a propriedade agora em um curto intervalo de tempo, como em um loop, podem retornar o mesmo valor.

Link msdn

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top