Introdução: Por que você sofre com datas?
Se você já escreveu código em C# e precisou enviar uma data e hora entre um servidor em Moscou e um cliente em Nova York, certamente encontrou bugs estranhos: "Por que está amanhã?", "De onde vieram essas 3 horas?". Situação familiar?
No .NET, existem duas ferramentas principais para trabalhar com datas: DateTime e DateTimeOffset. À primeira vista, elas são parecidas — ambas armazenam data e hora. Mas a diferença entre elas é crucial, e a escolha errada pode levar a erros catastróficos na lógica de negócios.
Neste tutorial, vamos analisar DateTime vs DateTimeOffset com exemplos reais, entender quando usar cada um e esquecer de vez a confusão com fusos horários. Vamos lá!
O que é DateTime? (E por que é uma armadilha)
DateTime é uma estrutura que armazena data e hora. Ela existe no .NET desde a primeira versão. Mas tem uma peculiaridade: não armazena informações sobre o fuso horário. Na verdade, armazena, mas apenas como um sinalizador Kind:
DateTimeKind.Unspecified— fuso não especificado (padrão).DateTimeKind.Utc— hora UTC.DateTimeKind.Local— hora local do sistema.
O problema é que esse sinalizador é apenas uma informação. Ele não converte a hora automaticamente. Imagine que você salva no banco de dados um DateTime com Kind = Local em um servidor em Moscou. Depois, você lê essa data em um servidor em Vladivostok. O que acontece? Isso mesmo — o programa vê que Kind = Local e assume que é a hora local de Vladivostok. Mas na verdade é Moscou. Um desastre absoluto.
// Exemplo do problema com DateTimeDateTime moscowTime = new DateTime(2025, 3, 15, 14, 0, 0, DateTimeKind.Local);Console.WriteLine(moscowTime); // 15.03.2025 14:00:00 (assumindo que é MSK)
// Se este código for executado em um servidor com fuso horário UTC+10 (Vladivostok)// O DateTime será interpretado como hora local de Vladivostok!// O que resultará em um erro de 7 horas.O que é DateTimeOffset? (O salvador dos desenvolvedores)
DateTimeOffset é uma estrutura mais inteligente, introduzida no .NET Framework 3.5. Ela armazena data, hora e o deslocamento em relação ao UTC (Offset). O deslocamento é o número de horas e minutos que sua hora local difere do UTC.
Por exemplo: 2025-03-15 14:00:00 +03:00 — é a hora em Moscou (UTC+3). Se você enviar esse valor para um servidor em Vladivostok (UTC+10), o .NET entenderá: "Ah, é +03, então UTC = 11:00. Agora posso recalcular facilmente para a hora local: 21:00". Sem mágica — matemática pura.
// Exemplo com DateTimeOffsetDateTimeOffset moscowOffset = new DateTimeOffset(2025, 3, 15, 14, 0, 0, TimeSpan.FromHours(3));Console.WriteLine(moscowOffset); // 15.03.2025 14:00:00 +03:00
// Agora, mesmo em um servidor em Vladivostok, sabemos o deslocamento exato// e podemos exibir a hora corretamente para o usuárioDiferenças principais: DateTime vs DateTimeOffset
Vamos resumir tudo em uma tabela clara. Isso ajudará você a decidir rapidamente o que escolher em cada situação.
1. Armazenamento de informações sobre fuso horário
- DateTime: Armazena apenas o sinalizador Kind (Unspecified, Utc, Local). Não armazena o deslocamento em si.
- DateTimeOffset: Armazena o deslocamento exato em relação ao UTC (ex.: +03:00, -05:00).
2. Comparação de valores
- DateTime: Compara pelo valor "bruto". Se você tem 10:00 UTC e 10:00 MSK (UTC+3), o
DateTime.Equals()dirá que são iguais. Embora, na verdade, sejam momentos diferentes no tempo. - DateTimeOffset: Compara pelo momento no tempo (UTC). 10:00 UTC e 13:00 MSK serão