DateTime.Now vs. DateTime.UtcNow

225

Fiquei me perguntando quais são exatamente os princípios de como as duas propriedades funcionam. Sei que o segundo é universal e basicamente não lida com fusos horários, mas alguém pode explicar em detalhes como eles funcionam e qual deve ser usado em que cenário?

Slavo
fonte
1
pode ser tarde demais, mas quero apontar para este blog: blog.angeloflogic.com/2013/10/…
Kai Wang
pequenos-marcação de bancada rextester.com/QRDR82396
Daniel B

Respostas:

346

DateTime.UtcNow informa a data e a hora como seria no Horário Universal Coordenado, também chamado de fuso horário médio de Greenwich - basicamente como seria se você estivesse em Londres na Inglaterra, mas não durante o verão. DateTime.Now fornece a data e a hora como apareceriam para alguém no seu local atual.

Eu recomendaria o uso DateTime.Nowsempre que você exibir uma data para um ser humano - assim, eles se sintam confortáveis ​​com o valor que vêem - é algo que eles podem comparar facilmente com o que vêem no relógio ou no relógio. Use DateTime.UtcNowquando desejar armazenar datas ou utilizá-las para cálculos posteriores. Dessa forma (em um modelo cliente-servidor), seus cálculos não serão confundidos por clientes em fusos horários diferentes do servidor ou entre si.

Blair Conrad
fonte
84
um ponto excelente - ao armazenar datas em um banco de dados ou arquivo, armazene-as definitivamente no UTC!
Jeff Atwood
15
Você deve observar que, quando deseja armazenar datas no UTC no banco de dados, é necessário garantir que o banco de dados não adicione seu próprio fuso horário às datas que não fornecem fusos horários explícitos. Observe que o DateTime sempre usará o fuso horário atual quando solicitado.
Omer van Kloeten 15/09/08
@OmervanKloeten dá uma opinião muito boa. Gostaria de saber se existe uma solução elegante e completa para isso, para armazenar e receber datas corretamente sempre, mesmo que o servidor IIS e SQL estejam em fusos horários diferentes.
TheGeekZn
1
@ JoshYates1980 Sim, você acabou de fazer DateTime.UtcNow.AddYears (1)
CathalMF 30/15/15
3
Use NodaTime - que vai forçá-lo pensar sobre o tempo de uma forma mais útil e evitar tais problemas
aateeque
86

É realmente muito simples, então eu acho que depende do que é seu público e de onde ele mora.

Se você não usa Utc, deve conhecer o fuso horário da pessoa para a qual está exibindo datas e horários - caso contrário, você dirá que algo aconteceu às 15h no horário do sistema ou do servidor, quando realmente aconteceu às 17h onde eles vivem.

Usamos DateTime.UtcNowporque temos uma audiência global na Web e porque eu preferiria não incomodar todos os usuários para preencher um formulário indicando em que fuso horário eles moram.

Também exibimos tempos relativos (2 horas atrás, 1 dia atrás, etc.) até a postagem envelhecer o suficiente para que o tempo seja "o mesmo", não importa onde você mora na Terra.

Jeff Atwood
fonte
Também quero que o armazenamento de DateTime.UtcNow também seja necessário apenas quando o cálculo com 2 datas for feito para obter as horas corretas. Quando eu apenas tenho que exibir uma Data RegisterAt, então Datetime. Agora é o suficiente.
Elisabeth
36

Observe também a diferença de desempenho; DateTime.UtcNowé cerca de 30 vezes mais rápida DateTime.Now, porque internamente DateTime.Nowestá fazendo muitos ajustes de fuso horário (você pode verificar isso facilmente com o Reflector).

Portanto, NÃO use DateTime.Nowpara medições de tempo relativo.

Magnus Krisell
fonte
Levei uma viagem dolorosa só sei UtcNow tem melhor desempenho e que simplesmente salvar as datas em mysql e assumindo que é UTC e comparando data é exibida dependentes com UtcNow simplifica este problemas de fuso horário globais
din
29

Um conceito principal de entender em .NET é que agora é agora toda a terra, não importa o fuso horário você está em Portanto, se você carregar uma variável com. DateTime.Now, Ou DateTime.UtcNow-. A atribuição é idêntica * O seu DateTimeobjeto sabe o fuso horário você está em e leva isso em consideração, independentemente da atribuição.

A utilidade disso DateTime.UtcNowé útil ao calcular datas nos limites do horário de verão. Ou seja, em locais que participam do horário de verão, às vezes há 25 horas do meio-dia ao meio-dia do dia seguinte e às vezes há 23 horas entre o meio-dia e o meio-dia do dia seguinte. Se você deseja determinar corretamente o número de horas entre o horário A e o horário B, primeiro é necessário converter cada um deles para seus equivalentes UTC antes de calcular o TimeSpan.

Isso é coberto por uma postagem de blog que escrevi que explica mais detalhadamente TimeSpane inclui um link para um artigo da MS ainda mais extenso sobre o assunto.

* Esclarecimento: Qualquer tarefa armazenará a hora atual. Se você fosse para carregar duas variáveis uma via DateTime.Now()e o outro via DateTime.UtcNow()a TimeSpandiferença entre os dois seria milissegundos, não em horas supondo que você está em um fuso horário horas de distância de GMT. Conforme observado abaixo, a impressão de seus Stringvalores exibirá diferentes strings.

Carl Camera
fonte
1
Em relação a "carregar uma variável com DateTime.Now ou DateTime.UtcNow - a atribuição é idêntica": Isso pode precisar ser esclarecido? Enquanto me sento aqui no fuso horário da EDT (UTC -4), designei duas variáveis ​​para DateTime.UtcNow e DateTime.Now, respectivamente, e depois imprimi seus valores com ToString (). Os valores exibidos foram separados por 4 horas - não "idênticos".
Jon Schneider
2
@ JonSchneider, acredito que você esteja correto. A afirmação: "a atribuição é idêntica" não é verdadeira. ToString () provavelmente não é a melhor maneira de testar isso, porque pode exibir datas iguais de maneira diferente (como Java faz). As funções de comparação são um teste melhor e mostram que de fato não são iguais.
Ted Bigham
Esclarecimento sobre minha declaração "idêntica": Carregue uma variável via DateTime.Now e outra com DateTime.UtcNow e imprima a diferença TimeSpan. A diferença será milissegundos e não horas, desde que você esteja a horas de GMT.
Carl Camera
18

Essa é uma boa pergunta. Estou revivendo para dar um pouco mais de detalhes sobre como o .Net se comporta com Kindvalores diferentes . Como @Jan Zich salienta, é realmente uma propriedade extremamente importante e é definida de maneira diferente, dependendo de você usar Nowou nãoUtcNow .

Internamente, a data é armazenada como diferente Ticks(ao contrário da resposta da @Carl Camera), dependendo de você usar NowouUtcNow .

DateTime.UtcNowcomporta-se como outras línguas. Ele define Ticksum valor baseado em GMT. Também define KindcomoUtc .

DateTime.Nowaltera o Ticksvalor para o que seria se fosse a sua hora do dia no fuso horário GMT . Também define KindcomoLocal .

Se você estiver com seis horas de atraso (GMT-6), receberá o horário GMT de seis horas atrás. O .Net na verdade ignora Kinde trata esse momento como se fosse 6 horas atrás, mesmo que devesse ser "agora". Isso quebra ainda mais se você criar umDateTime instância, alterar seu fuso horário e tentar usá-lo.

Instâncias de DateTime com diferentes valores 'Kind' NÃO são compatíveis.

Vamos dar uma olhada em algum código ...

    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

Como você pode ver aqui, comparações e funções matemáticas não são convertidas automaticamente em horários compatíveis. oTimespan deveria ter sido quase uma hora, mas em vez disso era quase 6. "UTC <agora" deve ter sido verdade (eu mesmo adicionado uma hora para ter certeza), mas ainda era falsa.

Você também pode ver a 'solução alternativa', que é simplesmente converter para o tempo universal em qualquer lugar que Kind não seja o mesmo.

Minha resposta direta à pergunta concorda com a recomendação da resposta aceita sobre quando usar cada uma. Você deveria sempre tentar trabalhar com DateTimeobjetos que tenham Kind=Utc, exceto durante a E / S (exibição e análise). Isso significa que você quase sempre deve estar usando DateTime.UtcNow, exceto nos casos em que está criando o objeto apenas para exibi-lo e descartá-lo imediatamente.

Ted Bigham
fonte
7

DateTime não tem idéia de quais são os fusos horários. Sempre assume que você está no seu horário local. UtcNow significa apenas "Subtrair meu fuso horário do momento".

Se você deseja usar datas com reconhecimento de fuso horário, use DateTimeOffset , que representa uma data / hora com um fuso horário. Eu tive que aprender isso da maneira mais difícil.

Omer van Kloeten
fonte
9
Para ser totalmente preciso (e evitar que as pessoas usem o Now over UtcNow por razões de desempenho), é o contrário: agora adiciona o fuso horário ao UtcNow e é de fato uma magnitude mais lenta.
mafu
5

A resposta "simples" para a pergunta é:

DateTime.Now retorna um valor DateTime que representa a hora atual do sistema (em qualquer fuso horário em que o sistema esteja sendo executado). A propriedade DateTime.Kind será DateTimeKind.Local

DateTime.UtcNow retorna um valor DateTime que representa o horário universal coordenado atual (também conhecido como UTC), que será o mesmo, independentemente do fuso horário do sistema. A propriedade DateTime.Kind será DateTimeKind.Utc

PapillonUK
fonte
4

Apenas uma pequena adição aos pontos mencionados acima: a estrutura DateTime também contém um campo pouco conhecido chamado Kind (pelo menos, eu não sabia disso há muito tempo). É basicamente apenas uma bandeira indicando se a hora é local ou UTC; ele não especifica o deslocamento real do UTC para os horários locais. Além de indicar com quais intenções a estrutura foi construída, também influencia a maneira como os métodos ToUniversalTime () e ToLocalTime () funcionam.

Jan Zich
fonte
1

DateTime.UtcNow é uma escala de tempo contínua e com valor único, enquanto DateTime.Now não é contínua ou com valor único. O principal motivo é o horário de verão, que não se aplica ao UTC. Portanto, o UTC nunca avança ou recua uma hora, enquanto o horário local (DateTime.Now) o faz. E quando salta para trás, o mesmo valor de tempo ocorre duas vezes.

user1315023
fonte
1

DateTime.UtcNow é uma escala de horário universal que omite o horário de verão. Portanto, o UTC nunca muda devido ao horário de verão.

Mas, DateTime.Now não é contínuo ou de valor único porque é alterado de acordo com o horário de verão. O que significa DateTime.Now, o mesmo valor de tempo pode ocorrer duas vezes, deixando os clientes em um estado confuso.

ChaiVan
fonte
0

Quando você precisar de um horário local para a máquina em que seu aplicativo é executado (como o CEST para a Europa), use Agora. Se você quer um tempo universal - UtcNow. É apenas uma questão de suas preferências - provavelmente criando um site local / aplicativo independente que você deseja usar o tempo que o usuário tem - tão afetado pela configuração de seu fuso horário - DateTime.Now.

Lembre-se, para um site, é a configuração de fuso horário do servidor. Portanto, se você estiver exibindo a hora para o usuário, obtenha o fuso horário preferido e mude a hora (basta salvar a hora Utc no banco de dados e modificá-la) ou especifique se é UTC. Se você esquecer de fazê-lo, o usuário poderá ver algo como: postou 3 min atrás e depois uma hora no futuro próximo :)

kender
fonte
0

A grande diferença :) é que DateTime.Now não é suportado no SharePoint Workflow, você deve usar DateTime.UtcNow

Michel LAPLANE
fonte