DateTimeOffset
é uma representação do tempo instantâneo (também conhecido como tempo absoluto ). Com isso, quero dizer um momento no tempo que é universal para todos (sem levar em conta os segundos bissextos ou os efeitos relativísticos da dilatação do tempo ). Outra maneira de representar o tempo instantâneo é com um DateTime
onde .Kind
está DateTimeKind.Utc
.
Isso é diferente do horário do calendário (também conhecido como horário civil ), que é uma posição no calendário de alguém, e existem muitos calendários diferentes em todo o mundo. Chamamos esses fusos horários de calendários . A hora do calendário é representada por um DateTime
onde .Kind
é DateTimeKind.Unspecified
ou DateTimeKind.Local
. E .Local
só é significativo nos cenários em que você tem uma compreensão implícita de onde o computador que está usando o resultado está posicionado. (Por exemplo, a estação de trabalho de um usuário)
Então, por que em DateTimeOffset
vez de um UTC DateTime
? É tudo sobre perspectiva. Vamos usar uma analogia - fingiremos ser fotógrafos.
Imagine que você está na linha do tempo de um calendário, apontando uma câmera para uma pessoa na linha do tempo instantânea definida à sua frente. Você alinha sua câmera de acordo com as regras do seu fuso horário - que mudam periodicamente devido ao horário de verão ou devido a outras alterações na definição legal do seu fuso horário. (Você não tem uma mão firme, então sua câmera está trêmula.)
A pessoa parada na foto veria o ângulo em que sua câmera veio. Se outros estavam tirando fotos, eles poderiam ser de diferentes ângulos. Isto é o que a Offset
parte do DateTimeOffset
representa.
Portanto, se você rotular sua câmera como "Hora do Leste", algumas vezes estará apontando para -5 e outras para -4. Existem câmeras em todo o mundo, todas rotuladas de coisas diferentes e todas apontando para a mesma linha do tempo instantânea de diferentes ângulos. Alguns deles estão próximos um do outro (ou por cima deles), portanto, apenas conhecer o deslocamento não é suficiente para determinar a qual fuso horário o horário está relacionado.
E o UTC? Bem, é a única câmera por aí que garante uma mão firme. Está em um tripé, firmemente ancorado no chão. Não vai a lugar nenhum. Chamamos seu ângulo de perspectiva de deslocamento zero.
Então - o que essa analogia nos diz? Ele fornece algumas diretrizes intuitivas -
Se você estiver representando um horário em relação a algum lugar em particular, represente-o no horário do calendário com a DateTime
. Só não se esqueça de nunca confundir um calendário com outro. Unspecified
deve ser sua suposição. Local
só é útil vindo DateTime.Now
. Por exemplo, eu posso obtê DateTime.Now
-lo e salvá-lo em um banco de dados - mas quando o recupero, devo assumir que é Unspecified
. Não posso confiar que meu calendário local seja o mesmo de onde foi originalmente retirado.
Se você sempre deve ter certeza do momento, verifique se está representando um tempo instantâneo. Use DateTimeOffset
para aplicá-lo ou use o UTC DateTime
por convenção.
Se você precisar acompanhar um momento instantâneo, mas também quiser saber "A que horas o usuário achou que estava no calendário local?" - então você deve usar a DateTimeOffset
. Isso é muito importante para os sistemas de cronometragem, por exemplo - tanto por questões técnicas quanto jurídicas.
Se você precisar modificar um gravado anteriormente DateTimeOffset
- você não possui informações suficientes apenas no deslocamento para garantir que o novo deslocamento ainda seja relevante para o usuário. Você também deve armazenar um identificador de fuso horário (pense: preciso do nome dessa câmera para poder tirar uma nova foto, mesmo que a posição tenha mudado).
Também deve ser destacado que o Noda Time tem uma representação chamada ZonedDateTime
para isso, enquanto a biblioteca de classes base .Net não possui nada parecido. Você precisaria armazenar a DateTimeOffset
e um TimeZoneInfo.Id
valor.
Ocasionalmente, você desejará representar um horário do calendário local para "quem estiver olhando para ele". Por exemplo, ao definir o que hoje significa. Hoje é sempre meia-noite a meia-noite, mas estes representam um número quase infinito de intervalos sobrepostos na linha do tempo instantânea. (Na prática, temos um número finito de fusos horários, mas você pode expressar compensações até o ponto). Portanto, nessas situações, certifique-se de entender como limitar o "quem está perguntando?" questione em um único fuso horário ou lembre-se de convertê-los novamente para o horário instantâneo, conforme apropriado.
Aqui estão alguns outros pequenos detalhes sobre DateTimeOffset
essa analogia e algumas dicas para mantê-lo reto:
Se você comparar dois DateTimeOffset
valores, eles serão normalizados primeiro com o deslocamento zero antes da comparação. Em outras palavras, 2012-01-01T00:00:00+00:00
e se 2012-01-01T02:00:00+02:00
referem ao mesmo momento instantâneo e, portanto, são equivalentes.
Se você estiver fazendo qualquer teste de unidade e necessidade de ter certeza do offset, teste tanto o DateTimeOffset
valor, ea .Offset
propriedade separadamente.
Há uma conversão implícita unidirecional incorporada à estrutura .Net que permite passar a DateTime
para qualquer DateTimeOffset
parâmetro ou variável. Ao fazer isso, os .Kind
assuntos . Se você passar um tipo UTC, ele será transferido com um deslocamento zero, mas se você passar um .Local
ou .Unspecified
, será assumido como local . A estrutura está basicamente dizendo: "Bem, você me pediu para converter a hora do calendário em hora instantânea, mas não tenho ideia de onde isso veio, então vou usar o calendário local". Essa é uma grande dificuldade se você carregar um não especificado DateTime
em um computador com um fuso horário diferente. (IMHO - isso deve gerar uma exceção - mas não gera).
Plug Shameless:
Muitas pessoas compartilharam comigo que acham essa analogia extremamente valiosa, por isso a incluí no meu curso Pluralsight, Fundamentos de data e hora . Você encontrará uma explicação passo a passo da analogia da câmera no segundo módulo, "Assuntos de contexto", no clipe intitulado "Horário do calendário versus horário instantâneo".