Menu

DateTime e TimeSpan em C#: Now, UtcNow, somar, subtrair, comparar e Parse

Trabalhando com datas e horas em C#: criar valores DateTime, Now vs UtcNow vs Today, somar dias e meses, subtrair para obter um TimeSpan, TotalHours vs Hours, comparar datas, DayOfWeek, converter com ParseExact e TryParse, DateTimeOffset e DateOnly.

Esta página tem editores executáveis - edite, execute e veja a saída na hora.

System.DateTime representa uma data e uma hora do dia, do ano 1 ao ano 9999, com precisão de 100 nanossegundos (um "tick"). System.TimeSpan representa uma duração: a diferença entre dois valores DateTime. Os dois são tipos de valor imutáveis (structs), então toda operação retorna um valor novo.

Saída:

2026-09-24 00:00:00
2026-09-24 14:30:00
14:30:05.250
2026 9 24
14:30
Thursday
267
2026-09-24 00:00
14:30:00

Todos os exemplos desta página imprimem datas com uma string de formato explícita. O ToString() padrão segue a cultura atual (9/24/2026 2:30:00 PM nos EUA, 24.09.2026 14:30:00 na Alemanha), então a saída depende da máquina. Os códigos de formato estão em formato de DateTime.

Uma data inválida lança exceção: new DateTime(2026, 2, 30) dispara uma ArgumentOutOfRangeException, assim como o mês 13 ou a hora 24.

Now, UtcNow e Today

Três propriedades static leem o relógio:

Exemplo de saída:

Now:    2026-09-24 18:20:41 (Local)
UtcNow: 2026-09-24 16:20:41 (Utc)
Today:  2026-09-24 00:00:00

Neste exemplo o fuso horário local está duas horas à frente do UTC, então as duas primeiras linhas diferem em duas horas; em uma máquina configurada em UTC elas são iguais. A propriedade Kind registra se um valor é Local, Utc ou Unspecified (o padrão para datas que você mesmo constrói). Use DateTime.UtcNow para tudo o que você guarda, registra, compara ou envia a outro sistema: ele não pula quando o horário de verão começa ou termina, e significa o mesmo momento em qualquer servidor. Converta para a hora local só ao mostrar um valor a uma pessoa.

Para medir quanto tempo um código leva, use System.Diagnostics.Stopwatch em vez de subtrair dois valores de DateTime.Now; ele tem resolução muito mais fina e não é afetado por ajustes do relógio.

Somando e subtraindo tempo

AddDays, AddHours, AddMinutes, AddSeconds, AddMonths e AddYears retornam um DateTime novo. Passe um número negativo para voltar no tempo. Como DateTime é imutável, o resultado precisa ser atribuído:

Saída:

2026-01-31
2026-02-03 09:00
2026-01-30 21:00
2026-02-28
2027-01-31
10:30
29
True

AddMonths fica no último dia do mês quando o dia não existe: 31 de janeiro mais um mês é 28 de fevereiro (ou 29 em ano bissexto), não 3 de março. Somar um mês duas vezes e somar dois meses, portanto, podem dar datas diferentes.

Subtraindo datas: TimeSpan

Subtrair um DateTime de outro dá um TimeSpan:

Saída:

3.20:30:00
Days: 3, Hours: 20, Minutes: 30
TotalDays: 3.85
TotalHours: 92.5
TotalMinutes: 5550
Nights: 4

Esta é a parte da API que as pessoas mais erram. Days, Hours, Minutes e Seconds são os componentes do intervalo (3 dias, 20 horas, 30 minutos). TotalDays, TotalHours e TotalMinutes são a duração inteira em uma unidade, como double. "Quantas horas o hóspede ficou?" é TotalHours (92.5), não Hours (20).

A última linha mostra um ponto relacionado: passaram 3,85 dias, mas o hóspede ficou 4 noites. Comparar as partes .Date conta dias de calendário, que normalmente é o que cobranças e contagens de "dias até" querem.

Criando e formatando valores TimeSpan

Saída:

02:15:00
01:30:00
1.12:00:00
True
03:45:00
True
02:15
36h 0m
00:00:00

TimeSpan aceita +, -, comparações, Duration() (valor absoluto) e Negate(). Formatos personalizados como @"hh\:mm" precisam de uma barra invertida antes dos caracteres literais, e hh ali mostra só o componente de horas (0 a 23), então para durações maiores que um dia monte o texto a partir de TotalHours, como na penúltima linha.

Comparando datas

DateTime aceita ==, !=, <, >, <= e >=, além de CompareTo e DateTime.Compare. Para comparar só a data e ignorar a hora, compare as propriedades .Date:

Saída:

True
True
1
True
2026-09-01

Para "este timestamp está dentro de 30 de setembro?", compare com o início do dia seguinte usando <, como acima. Escrever check <= end excluiria tudo depois da meia-noite do último dia, porque end é 2026-09-30 00:00:00.

As comparações só olham os ticks, não o Kind: um valor Local e um valor Utc que são impressos iguais são considerados iguais, mesmo sendo momentos diferentes. Mais um motivo para guardar os horários em UTC.

Dia da semana e início da semana

DayOfWeek é um enum de Sunday (0) a Saturday (6). A aritmética com ele encontra dias úteis e os limites da semana:

Saída:

Thursday
4
Weekend: False
Week starts 2026-09-21 (Monday)
Next Friday: 2026-09-25
2026-09-01 to 2026-09-30

Os nomes de dias impressos por DayOfWeek.ToString() estão sempre em inglês. Para um nome localizado, formate a data com "dddd" e uma cultura.

Convertendo datas a partir de strings

Quando você conhece o formato da entrada, use ParseExact ou TryParseExact com CultureInfo.InvariantCulture. A string de formato usa os mesmos códigos da formatação:

Saída:

2026-09-24 00:00
2026-09-24 18:05
'2026-02-28' -> Saturday, February 28
'2026-02-30' -> invalid
'28.02.2026' -> invalid
'' -> invalid
2026-02-28
2026-09-24 10:00 Utc

DateTime.Parse(text) sem formato tenta adivinhar usando a cultura atual. "03/04/2026" é 4 de março em uma máquina dos EUA e 3 de abril em uma britânica, e uma data que é convertida no seu notebook pode lançar uma FormatException em um servidor. Deixe o Parse para entradas digitadas por um usuário local; use ParseExact com a cultura invariante para arquivos, APIs e bancos de dados. ParseExact lança FormatException quando o texto não corresponde; TryParseExact retorna false no lugar.

Calculando uma idade

Subtrair datas de nascimento e dividir por 365 dá errado perto dos aniversários e dos anos bissextos. Compare os anos e corrija se o aniversário deste ano ainda não aconteceu:

Saída:

36
35
18
70 days to go

DateTimeOffset

Um DateTime não registra em que fuso horário está, além da vaga flag Kind. DateTimeOffset guarda o valor junto com o deslocamento em relação ao UTC, então sempre identifica um momento exato:

Saída:

2026-09-24 14:00 +02:00
2026-09-24 12:00
2026-09-24 12:30
00:30:00
21:00 +09:00

Use DateTimeOffset (ou valores DateTime em UTC) para timestamps: quando um pedido foi feito, quando uma mensagem foi enviada. Bancos de dados e serializadores JSON lidam bem com ele. Para converter entre fusos horários com nome e regras de horário de verão, use TimeZoneInfo.ConvertTime; os IDs de fuso diferem por sistema operacional em versões antigas do .NET ("Europe/Paris" no Linux, "Romance Standard Time" no Windows), e o .NET 6 em diante aceita os dois.

DateOnly e TimeOnly (.NET 6 em diante)

Muitos valores são uma data sem hora (um aniversário, uma data de vencimento) ou uma hora sem data (horário de funcionamento). O .NET 6 adicionou dois tipos para eles:

// .NET 6 and later
DateOnly birthday = new DateOnly(1990, 9, 24);
DateOnly due = DateOnly.FromDateTime(DateTime.Today).AddDays(14);
int daysLeft = due.DayNumber - DateOnly.FromDateTime(DateTime.Today).DayNumber;

TimeOnly opens = new TimeOnly(9, 0);
TimeOnly closes = new TimeOnly(17, 30);
bool isOpen = TimeOnly.FromDateTime(DateTime.Now).IsBetween(opens, closes);

Eles eliminam uma classe de bugs em que uma hora ou um fuso horário perdido desloca uma data em um dia. Código mais antigo, e código para .NET Framework ou Unity, usa DateTime com a hora deixada em meia-noite.

Erros comuns

  • Descartar o resultado de AddDays. DateTime é imutável; atribua o valor retornado.
  • Usar Hours em vez de TotalHours. Componentes versus duração total.
  • Guardar DateTime.Now. Guarde em UTC e converta para exibir.
  • Chamar ToString() sem formato em logs, arquivos ou testes, em que a saída depende da cultura da máquina.
  • Converter dados de máquina com DateTime.Parse. Use ParseExact e a cultura invariante.
  • Confundir mm e MM em strings de formato (minutos e meses). Veja formato de DateTime.

Perguntas frequentes

Qual a diferença entre DateTime.Now e DateTime.UtcNow?

DateTime.Now é a hora atual no fuso horário local do computador, com Kind igual a Local. DateTime.UtcNow é a hora atual em UTC, com Kind igual a Utc, e também é mais rápido porque pula a conversão de fuso horário. Guarde e compare timestamps em UTC, e converta para a hora local só para exibir.

Como obter a diferença entre duas datas em C#?

Subtraia uma da outra: TimeSpan gap = end - start;. Depois leia gap.TotalDays, gap.TotalHours ou gap.TotalMinutes para a duração inteira como double, ou gap.Days para a parte de dias inteiros. Para meses ou anos de calendário não existe propriedade embutida, porque os meses têm tamanhos diferentes; compare você mesmo os campos de ano e mês.

Qual a diferença entre TimeSpan.Hours e TotalHours?

Hours é só o componente de horas, de 0 a 23, depois que os dias inteiros são tirados. TotalHours é a duração inteira expressa em horas, como double. Para um intervalo de 1 dia e 3 horas, Hours é 3 e TotalHours é 27. Usar Hours onde se queria TotalHours é um bug muito comum.

Como converter uma string de data em C#?

Quando você conhece o formato, use DateTime.ParseExact(text, "yyyy-MM-dd", CultureInfo.InvariantCulture), ou DateTime.TryParseExact para receber false em vez de uma FormatException em uma entrada inválida. DateTime.Parse adivinha o formato pela cultura atual, então 03/04/2026 é 4 de março nos EUA e 3 de abril no Reino Unido e no Brasil.

Por que o AddDays não muda meu DateTime?

DateTime é um tipo de valor imutável. AddDays, AddHours e os outros métodos retornam um DateTime novo e deixam o original sem mudança, então você precisa atribuir o resultado: due = due.AddDays(7);.

Quando usar DateTimeOffset em vez de DateTime?

Use DateTimeOffset em timestamps que precisam identificar um momento exato, como quando um pedido foi feito ou uma entrada de log foi gravada, principalmente se os dados passam entre servidores e fusos horários. Ele guarda o deslocamento em relação ao UTC junto com o valor. DateTime serve para timestamps só em UTC e para datas sem um fuso horário relevante.

Coddy programming languages illustration

Aprenda a programar com o Coddy

COMEÇAR