Datas
Manipular datas e horas é uma das tarefas mais comuns e, surpreendentemente, uma das mais complexas na programação. Um simples carimbo de data pode esconder armadilhas relacionadas a fusos horários, formatação e performance.
Este guia vai além do básico do DateTime e apresenta as ferramentas e práticas recomendadas para manipular datas e horas em C# de forma profissional e robusta.
A Família de Tipos de Data e Hora
O .NET oferece uma família de tipos para trabalhar com datas e horas. É crucial escolher a ferramenta certa para cada trabalho.
Tipo | Descrição | Quando Usar |
|---|---|---|
| Representa um ponto no tempo, geralmente expresso como uma data e hora do dia. | Usado para necessidades simples, mas pode ser ambíguo em relação ao fuso horário. |
| Representa um ponto no tempo, incluindo um deslocamento (offset) do Tempo Universal Coordenado (UTC). | Recomendado para a maioria dos casos, especialmente em APIs e bancos de dados, pois não é ambíguo. |
| Representa uma duração ou intervalo de tempo. | Para medir o tempo entre dois pontos ou representar uma quantidade de tempo (ex: 24 horas). |
| (.NET 6+) Representa apenas a parte da data, sem a hora. | Quando você só precisa do dia, mês e ano (ex: data de nascimento). |
| (.NET 6+) Representa apenas a hora do dia, sem a data. | Quando você só precisa da hora (ex: horário de funcionamento de uma loja). |
| Representa um fuso horário. | Para converter datas e horas entre diferentes fusos horários. |
O DateTime e sua Armadilha: DateTime.Kind
O DateTime parece simples, mas ele carrega uma propriedade traiçoeira chamada Kind. Ela define como o valor da data deve ser interpretado em relação ao fuso horário e pode ser de três tipos:
DateTimeKind.Utc: A data e hora são expressas em Tempo Universal Coordenado. É um padrão global, o mesmo em todo o mundo.DateTimeKind.Local: A data e hora estão no fuso horário local da máquina onde o código está rodando. Isso pode variar de servidor para servidor.DateTimeKind.Unspecified: O fuso horário não foi especificado. Este é o padrão para datas criadas manualmente e a principal fonte de bugs.
Exemplo de Bug com DateTimeKind.Unspecified
Imagine que um usuário no Brasil (UTC-3) agenda uma tarefa para as 14:00. Você salva isso no banco de dados como new DateTime(2025, 10, 20, 14, 0, 0). O Kind será Unspecified.
Um serviço rodando em um servidor na Europa (UTC+1) lê essa data. Ao tentar converter para a hora local, o .NET pode assumir que 14:00 era a hora local do servidor, e não do usuário. A tarefa que deveria rodar às 14:00 no Brasil acaba rodando em um horário completamente diferente.
A Solução Profissional: DateTimeOffset
Para evitar a ambiguidade do DateTime.Kind, use DateTimeOffset. Ele armazena a mesma informação que o DateTime, mas também inclui o offset, que é a diferença de tempo em relação ao UTC. Isso torna o momento no tempo absoluto e inequívoco.
Um offset de -03:00 significa "três horas a menos que o UTC".
Com DateTimeOffset, o momento 16/08/2025 15:00:00 -03:00 é sempre o mesmo, não importa se o servidor que processa essa informação está no Brasil, no Japão ou na Lua.
Os Especialistas: DateOnly e TimeOnly
Introduzidos no .NET 6, esses tipos resolvem um problema antigo: a necessidade de carregar uma data e hora completas quando você só precisa de uma parte. Eles são mais eficientes (usam menos memória) e deixam a intenção do seu código mais clara.
DateOnly
Use para representar uma data de calendário. Mapeia perfeitamente para o tipo date em SQL.
TimeOnly
Use para representar uma hora do dia. Mapeia para o tipo time em SQL.
Convertendo Texto em Datas (Parse)
Receber datas como strings é muito comum. Para convertê-las em objetos, use os métodos Parse ou TryParse. A melhor prática é ser o mais explícito possível sobre o formato esperado.
A Forma Mais Segura: TryParseExact
Para evitar exceções (try-catch), que podem impactar a performance, e garantir que apenas um formato específico seja aceito, use TryParseExact. Ele retorna true se a conversão for bem-sucedida e false caso contrário.
Boas Práticas para Manipulação de Datas
Prefira
DateTimeOffsetaDateTime. Use-o como padrão para APIs, bancos de dados e logs. Ele elimina a ambiguidade de fuso horário e torna seu sistema mais robusto.Use
DateTime.UtcNowpara Timestamps. Ao registrar quando um evento ocorreu (ex: data de criação de um registro), use sempreDateTime.UtcNow(ouDateTimeOffset.UtcNow). O tempo do servidor local é irrelevante e pode mudar com o horário de verão ou com a localização do servidor.Use
DateOnlyeTimeOnlyquando a informação de hora ou data for irrelevante. Isso torna seu modelo de dados mais claro, eficiente e evita bugs relacionados a partes da data que deveriam ser ignoradas.Seja Explícito ao Fazer
Parsede Strings. Sempre useTryParseExact. Para datas de máquina para máquina (ex: JSON, XML), useCultureInfo.InvariantCulturee um formato bem definido (como o padrão ISO 8601:yyyy-MM-ddTHH:mm:ssZ). Para datas inseridas por usuários, use a cultura específica deles (new CultureInfo("pt-BR")).Armazene Datas em UTC e Converta na Apresentação. A regra de ouro: seu back-end e seu banco de dados devem viver em UTC. A conversão para o fuso horário do usuário deve ser a última etapa, realizada pela interface do usuário (UI).