C# Datas e Horas

Quando vence o boleto? Quantos dias faltam para o Natal? Quanto tempo durou o filme? Que horas são em Lisboa? Datas aparecem em quase todo programa, e fazer essas contas "na mão" é difícil: os meses têm tamanhos diferentes, há anos bissextos e fusos horários. O C# tem tipos prontos para tudo isso. Nesta aula você vai usar o DateTime (data e hora), o TimeSpan (um intervalo de tempo), o DateOnly e o TimeOnly (só a data, só a hora), e vai calcular a multa da biblioteca da Ana.

Você vai aprender
  • Pegar a data e a hora de agora (DateTime.Now, Today, UtcNow) e criar uma data qualquer.
  • Ler as partes: Year, Month, Day, Hour, DayOfWeek.
  • Formatar em português: "d", "D", "dd/MM/yyyy", "HH:mm", "dddd".
  • Somar e subtrair: AddDays, AddMonths, e o TimeSpan que sai de uma subtração.
  • Usar DateOnly e TimeOnly quando só a data ou só a hora importa.
  • Transformar texto em data: Parse, ParseExact e TryParse.
  • Fusos horários com TimeZoneInfo e DateTimeOffset.

Os programas rodam com dotnet run no computador da Ana, que está em português do Brasil e no fuso de São Paulo (UTC−3). As datas e os nomes de dias e meses aparecem como no Brasil. A aula Cultura mostra como isso muda em outros países.


A ideia: o calendário e o cronômetro

Pense em duas coisas da sua casa. O calendário com relógio marca um momento: "sábado, 17 de outubro de 2026, às 14h30". Isso é um DateTime. O cronômetro mede uma duração: "2 horas e 15 minutos", sem dizer quando começou. Isso é um TimeSpan.

As contas entre os dois são as do dia a dia: um momento mais uma duração dá outro momento ("o filme começa às 19h e dura 2h15, então acaba às 21h15"). Um momento menos outro dá uma duração ("do dia 17 de outubro ao Natal são 69 dias").

TipoGuardaExemplo
DateTimeData e hora17/10/2026 14:30:00
DateOnly .NET 6Só a dataUm aniversário: 08/03/1997
TimeOnly .NET 6Só a hora do diaA loja abre às 08:00
TimeSpanUma duração02:15:00 (2 horas e 15 minutos)
DateTimeOffsetData, hora e o fuso17/10/2026 14:30:00 −03:00

Todos são structs do namespace System, que já vem incluído.


1. Agora: DateTime.Now

DateTime agora = DateTime.Now;
Console.WriteLine(agora);
Console.WriteLine(DateTime.Today);
Console.WriteLine(DateTime.UtcNow);
$ date
sáb 17 out 2026 12:57:03 -03
$ dotnet run agora.cs
17/10/2026 12:57:07
17/10/2026 00:00:00
17/10/2026 15:57:07
DateTime.Now
"Agora": a data e a hora do relógio do computador, no fuso dele. Cada vez que você roda, sai um valor diferente.
DateTime.Today
"Hoje": a data de hoje, com a hora zerada (meia-noite).
DateTime.UtcNow
Agora em UTC, o horário de referência do mundo (o de Greenwich, em Londres, sem horário de verão). São Paulo está 3 horas atrás: 12h57 aqui são 15h57 em UTC.
Console.WriteLine(agora)
Mostra no formato do Brasil, dia/mês/ano e hora com 24 horas, porque o computador está em pt-BR.
Teste com datas fixas

Um programa que usa DateTime.Now dá um resultado diferente a cada dia, o que dificulta conferir se ele está certo. Nos exemplos e nas missões desta aula, a data de "hoje" é fixa (new DateTime(2026, 10, 17)). Nos seus programas, troque pela DateTime.Today quando estiver tudo funcionando.


2. Uma data qualquer, e as partes dela

DateTime prova = new DateTime(2026, 10, 17, 14, 30, 0);
Console.WriteLine(prova);
Console.WriteLine(prova.Year);
Console.WriteLine(prova.Month);
Console.WriteLine(prova.Day);
Console.WriteLine(prova.Hour);
Console.WriteLine(prova.DayOfWeek);
Console.WriteLine(prova.DayOfYear);
$ dotnet run data.cs
17/10/2026 14:30:00
2026
10
17
14
Saturday
290
new DateTime(2026, 10, 17, 14, 30, 0)
Ano, mês, dia, hora, minuto e segundo, nessa ordem (do maior para o menor, nunca dia/mês/ano). Sem a hora, new DateTime(2026, 10, 17) é meia-noite.
Year, Month, Day, Hour, Minute, Second
As partes, como números int.
DayOfWeek
O dia da semana, que é um enum, e por isso aparece com o nome em inglês: Saturday (sábado). Serve para comparar: prova.DayOfWeek == DayOfWeek.Saturday. Para mostrar em português, use o formato "dddd" (seção 3).
DayOfYear
Que dia do ano é: 17 de outubro é o 290º dia de 2026.

3. Formatar: ToString com códigos

O ToString de uma data aceita um texto com o formato, igual aos números da aula Formatar Números. Existem formatos prontos de uma letra e formatos "montados" com códigos:

DateTime prova = new DateTime(2026, 10, 17, 14, 30, 0);
Console.WriteLine(prova.ToString("d"));
Console.WriteLine(prova.ToString("D"));
Console.WriteLine(prova.ToString("t"));
Console.WriteLine(prova.ToString("F"));
Console.WriteLine(prova.ToString("dd/MM/yyyy HH:mm"));
Console.WriteLine(prova.ToString("dddd"));
Console.WriteLine(prova.ToString("MMMM"));
Console.WriteLine(prova.ToString("ddd, dd 'de' MMM"));
Console.WriteLine(prova.ToString("yyyy-MM-dd"));
Console.WriteLine($"Prova: {prova:dd/MM}");
$ dotnet run formatos.cs
17/10/2026
sábado, 17 de outubro de 2026
14:30
sábado, 17 de outubro de 2026 14:30:00
17/10/2026 14:30
sábado
outubro
sáb., 17 de out.
2026-10-17
Prova: 17/10
CódigoSignificaExemplo
d (sozinho)Data curta17/10/2026
D (sozinho)Data longasábado, 17 de outubro de 2026
t / T (sozinhos)Hora curta / com segundos14:30 / 14:30:00
F (sozinho)Data longa e horasábado, 17 de outubro de 2026 14:30:00
dd / ddd / ddddDia com 2 dígitos / dia da semana curto / longo17 / sáb. / sábado
MM / MMM / MMMMMês com 2 dígitos / nome curto / longo10 / out. / outubro
yyyyAno com 4 dígitos2026
HH / hhHora de 0 a 23 / de 1 a 1214 / 02
mm / ssMinutos / segundos30 / 00
'texto'Texto escrito como está'de' → de

Atenção às maiúsculas: MM é mês e mm é minuto (veja "Quando dá errado"). O formato yyyy-MM-dd é o padrão internacional ISO 8601: ele não depende do país, e os arquivos ordenados pelo nome ficam em ordem de data. Use-o em nomes de arquivos e em dados que outros programas vão ler.


4. Somar e subtrair: Add e TimeSpan

DateTime hoje = new DateTime(2026, 10, 17);
Console.WriteLine(hoje.AddDays(14).ToString("d"));
Console.WriteLine(hoje.AddDays(-1).ToString("d"));
Console.WriteLine(hoje.AddMonths(3).ToString("d"));
Console.WriteLine(new DateTime(2026, 1, 31).AddMonths(1).ToString("d"));
Console.WriteLine(hoje.AddHours(36));

DateTime natal = new DateTime(2026, 12, 25);
TimeSpan falta = natal - hoje;
Console.WriteLine(falta);
Console.WriteLine(falta.Days);
Console.WriteLine(falta.TotalHours);
Console.WriteLine(natal > hoje);
$ dotnet run contas.cs
31/10/2026
16/10/2026
17/01/2027
28/02/2026
18/10/2026 12:00:00
69.00:00:00
69
1656
True
hoje.AddDays(14)
"Somar dias": devolve uma data nova, 14 dias depois. A hoje não muda: um DateTime nunca muda depois de criado. Por isso é preciso guardar o resultado (DateTime prazo = hoje.AddDays(14);).
AddDays(-1)
Com número negativo, volta no tempo.
AddMonths(3)
Três meses depois, virando o ano se precisar. Também existem AddYears, AddHours, AddMinutes, AddSeconds.
31/01 + 1 mês = 28/02
Fevereiro de 2026 não tem dia 31, então o AddMonths usa o último dia do mês. Fazer essa conta somando 30 dias daria errado.
natal - hoje
Uma data menos outra dá um TimeSpan. Ele aparece como dias.horas:minutos:segundos: 69.00:00:00 são 69 dias e zero horas.
falta.Days e falta.TotalHours
Days é a parte dos dias (int). TotalHours é a duração inteira convertida em horas (double): 69 × 24 = 1656. Existem Hours/TotalHours, Minutes/TotalMinutes e assim por diante.
natal > hoje
Datas se comparam com <, > e ==, como números: a mais tarde é a "maior".

Missão: a frase saiu Faltam 69.00:00:00 para o Natal. Use a propriedade Days do TimeSpan para a saída ficar Faltam 69 dias para o Natal.

DateTime hoje = new DateTime(2026, 10, 17);
DateTime natal = new DateTime(2026, 12, 25);
TimeSpan falta = natal - hoje;
Console.WriteLine($"Faltam {falta} para o Natal");
DateTime hoje = new DateTime(2026, 10, 17);
DateTime natal = new DateTime(2026, 12, 25);
TimeSpan falta = natal - hoje;
Console.WriteLine($"Faltam {falta.Days} dias para o Natal");

Durações: TimeSpan

Um TimeSpan também pode ser criado direto, para somar a uma data ou a outro TimeSpan:

TimeSpan filme = new TimeSpan(2, 15, 0);
TimeSpan aula = TimeSpan.FromMinutes(90);
Console.WriteLine(filme);
Console.WriteLine(filme.TotalMinutes);
Console.WriteLine(aula);
Console.WriteLine(filme + aula);

DateTime inicio = new DateTime(2026, 10, 17, 19, 0, 0);
Console.WriteLine($"O filme acaba às {(inicio + filme):t}");
Console.WriteLine($"{filme.Hours}h{filme.Minutes:00}");
$ dotnet run filme.cs
02:15:00
135
01:30:00
03:45:00
O filme acaba às 21:15
2h15
new TimeSpan(2, 15, 0)
Horas, minutos e segundos. Com quatro números, o primeiro são os dias: new TimeSpan(1, 2, 0, 0) é 1 dia e 2 horas.
TimeSpan.FromMinutes(90)
Uma duração a partir de uma quantidade: FromDays, FromHours, FromMinutes, FromSeconds. 90 minutos viram 01:30:00.
filme + aula
Durações se somam: 2h15 + 1h30 = 3h45.
inicio + filme
Momento mais duração dá um momento: 19h00 + 2h15 = 21h15. Os parênteses em {(inicio + filme):t} são necessários para a conta ser feita antes do formato.
{filme.Minutes:00}
O formato 00 garante dois dígitos: 5 sairia 05.

5. Só a data, só a hora: DateOnly e TimeOnly

Um aniversário não tem hora. O horário de abertura da loja não tem data. Guardar esses valores num DateTime funciona, mas leva junto uma parte que não significa nada (a "meia-noite" do aniversário). Desde o .NET 6, existem tipos só para isso:

DateOnly nascimento = new DateOnly(1997, 3, 8);
DateOnly hoje = new DateOnly(2026, 10, 17);
Console.WriteLine(nascimento);
Console.WriteLine(nascimento.ToString("D"));

int idade = hoje.Year - nascimento.Year;
if (hoje < nascimento.AddYears(idade))
{
    idade--;
}
Console.WriteLine($"Idade: {idade}");
Console.WriteLine($"Dias de vida: {hoje.DayNumber - nascimento.DayNumber}");

TimeOnly abre = new TimeOnly(8, 0);
TimeOnly fecha = new TimeOnly(18, 30);
TimeOnly agora = new TimeOnly(19, 15);
Console.WriteLine($"Aberta das {abre} às {fecha}: {fecha - abre} por dia");
Console.WriteLine($"Aberta às {agora}? {agora.IsBetween(abre, fecha)}");
$ dotnet run aniversario.cs
08/03/1997
sábado, 8 de março de 1997
Idade: 29
Dias de vida: 10815
Aberta das 08:00 às 18:30: 10:30:00 por dia
Aberta às 19:15? False
new DateOnly(1997, 3, 8)
Ano, mês e dia. Mostra só a data, sem 00:00:00.
a conta da idade
Primeiro, a diferença dos anos (2026 − 1997 = 29). Depois, se o aniversário deste ano ainda não chegou (hoje < nascimento.AddYears(idade)), tira um. A Ana fez aniversário em março, então tem 29.
DayNumber
O número do dia contado desde 1º de janeiro do ano 1. A diferença entre dois DayNumber é a quantidade de dias entre as datas. (O DateOnly não tem o operador -; veja "Quando dá errado".)
new TimeOnly(8, 0)
Hora e minuto. A diferença entre dois TimeOnly é um TimeSpan.
agora.IsBetween(abre, fecha)
"Está entre?": True se a hora está no intervalo. 19h15 está fora.

Para converter: DateOnly.FromDateTime(umDateTime) pega só a data, e umDateOnly.ToDateTime(umTimeOnly) junta uma data e uma hora num DateTime.


6. Texto → data: Parse, ParseExact e TryParse

Datas digitadas pelo usuário ou lidas de um arquivo chegam como texto. Como os números da aula Parse e TryParse, elas precisam ser convertidas:

using System.Globalization;

DateTime d1 = DateTime.Parse("17/10/2026");
Console.WriteLine(d1.ToString("D"));

DateTime d2 = DateTime.Parse("2026-10-17 14:30");
Console.WriteLine(d2);

DateTime d3 = DateTime.ParseExact("10/17/2026", "MM/dd/yyyy", CultureInfo.InvariantCulture);
Console.WriteLine(d3.ToString("d"));

if (DateOnly.TryParseExact("08/03/1997", "dd/MM/yyyy", out DateOnly nasc))
{
    Console.WriteLine($"Nasceu no dia da semana: {nasc:dddd}");
}
if (!DateOnly.TryParse("31/02/2026", out DateOnly ruim))
{
    Console.WriteLine("Data inválida");
}
$ dotnet run parse.cs
sábado, 17 de outubro de 2026
17/10/2026 14:30:00
17/10/2026
Nasceu no dia da semana: sábado
Data inválida
DateTime.Parse("17/10/2026")
Entende o texto no formato do país do computador: em pt-BR, dia/mês/ano. O formato ISO (2026-10-17) é aceito em qualquer país.
DateTime.ParseExact(texto, "MM/dd/yyyy", CultureInfo.InvariantCulture)
"Converter exatamente": você diz o formato, com os códigos da seção 3. Aqui, uma data no estilo dos Estados Unidos, mês primeiro. O CultureInfo.InvariantCulture (aula Cultura) diz que o texto não depende do país.
DateOnly.TryParseExact(texto, "dd/MM/yyyy", out DateOnly nasc)
A versão segura: devolve true e põe a data em nasc se deu certo, ou false sem exceção. Use sempre o TryParse com texto digitado pelo usuário.
"31/02/2026"
Fevereiro não tem dia 31: o TryParse devolve false.

7. Fusos horários

Quando é 14h30 em São Paulo, é 18h30 em Lisboa e 13h30 em Manaus. O TimeZoneInfo ("informação de fuso") conhece os fusos do mundo e converte entre eles. No Linux, cada fuso tem um nome do tipo Continente/Cidade:

DateTime aqui = new DateTime(2026, 10, 17, 14, 30, 0, DateTimeKind.Local);
Console.WriteLine(TimeZoneInfo.Local.Id);
Console.WriteLine(TimeZoneInfo.Local.GetUtcOffset(aqui));
Console.WriteLine($"UTC: {aqui.ToUniversalTime()}");

TimeZoneInfo lisboa = TimeZoneInfo.FindSystemTimeZoneById("Europe/Lisbon");
TimeZoneInfo manaus = TimeZoneInfo.FindSystemTimeZoneById("America/Manaus");
Console.WriteLine($"Lisboa: {TimeZoneInfo.ConvertTime(aqui, lisboa)}");
Console.WriteLine($"Manaus: {TimeZoneInfo.ConvertTime(aqui, manaus)}");

DateTimeOffset reuniao = new DateTimeOffset(2026, 10, 17, 14, 30, 0, TimeSpan.FromHours(-3));
Console.WriteLine(reuniao);
Console.WriteLine(reuniao.ToUniversalTime());
$ dotnet run fuso.cs
America/Sao_Paulo
-03:00:00
UTC: 17/10/2026 17:30:00
Lisboa: 17/10/2026 18:30:00
Manaus: 17/10/2026 13:30:00
17/10/2026 14:30:00 -03:00
17/10/2026 17:30:00 +00:00
DateTimeKind.Local
O último argumento diz de que fuso é a data: Local (o do computador), Utc ou Unspecified (não se sabe, o padrão do new DateTime). A propriedade Kind guarda isso.
TimeZoneInfo.Local
O fuso do computador: America/Sao_Paulo, 3 horas atrás do UTC (-03:00:00).
ToUniversalTime()
A mesma hora, em UTC.
TimeZoneInfo.FindSystemTimeZoneById("Europe/Lisbon")
Procura um fuso pelo nome. ConvertTime mostra a mesma hora no relógio de lá, já com o horário de verão de cada lugar.
DateTimeOffset
Um momento com a diferença para o UTC junto (-03:00). Não há dúvida sobre de que fuso ele é. Prefira-o para guardar quando algo aconteceu (uma compra, um login), principalmente num sistema usado em vários lugares.

Qual tipo usar

Você quer guardar…Use
Um aniversário, um feriado, um vencimentoDateOnly
Um horário que se repete (abre às 8h)TimeOnly
Uma duração (2h15, 14 dias)TimeSpan
Um compromisso no seu fusoDateTime
Quando algo aconteceu, num sistema com usuários em vários fusosDateTimeOffset ou DateTime.UtcNow
Data num arquivo ou para outro programaTexto no formato ISO: ToString("yyyy-MM-dd") ou ToString("o")

Quando dá errado

FormatException: a data no formato de outro país
DateTime d = DateTime.Parse("10/17/2026");
Console.WriteLine(d);
$ dotnet run erro1.cs
Unhandled exception. System.FormatException: String '10/17/2026' was not recognized as a valid DateTime.
   at System.DateTimeParse.Parse(ReadOnlySpan`1 s, DateTimeFormatInfo dtfi, DateTimeStyles styles)
   at Program.<Main>$(String[] args) in /home/ana/cs/erro1.cs:line 1

O que aconteceu: "O texto não foi reconhecido como uma data válida". Em pt-BR, o Parse lê dia/mês/ano, e não existe mês 17. Pior ainda é "05/10/2026", que dá certo nos dois países, mas é 5 de outubro aqui e 10 de maio nos Estados Unidos: sem erro, com a data errada.

Como resolver: se você sabe o formato do texto, diga qual é: DateTime.ParseExact("10/17/2026", "MM/dd/yyyy", CultureInfo.InvariantCulture). Com texto digitado, TryParse ou TryParseExact. Nos seus arquivos, grave no formato ISO, yyyy-MM-dd, que não tem ambiguidade.

ArgumentOutOfRangeException: 30 de fevereiro
DateTime d = new DateTime(2026, 2, 30);
$ dotnet run erro2.cs
Unhandled exception. System.ArgumentOutOfRangeException: Year, Month, and Day parameters describe an un-representable DateTime.
   at System.DateTime..ctor(Int32 year, Int32 month, Int32 day)
   at Program.<Main>$(String[] args) in /home/ana/cs/erro2.cs:line 1

O que aconteceu: "Ano, mês e dia descrevem uma data que não pode existir". O mesmo acontece com o mês 13, a hora 24 ou, muito comum, com a ordem trocada: new DateTime(17, 10, 2026) tenta o ano 17, mês 10, dia 2026.

Como resolver: ano, mês, dia, sempre nessa ordem. Para saber quantos dias um mês tem, DateTime.DaysInMonth(2026, 2) devolve 28. Para "o mesmo dia no mês que vem", use AddMonths(1), que já ajusta o fim do mês.

A data saiu 17/05/2026: mm no lugar de MM
DateTime d = new DateTime(2026, 10, 17, 14, 5, 0);
Console.WriteLine(d.ToString("dd/mm/yyyy"));
Console.WriteLine(d.ToString("hh:mm"));
Console.WriteLine(d.ToString("HH:mm"));
$ dotnet run mm.cs
17/05/2026
02:05
14:05

O que aconteceu: nenhum erro, só o resultado errado. Em dd/mm/yyyy, o mm são os minutos (5), e não o mês. E em hh:mm, o hh é a hora de 12 horas: 14h05 virou 02:05, sem dizer se é da manhã ou da tarde.

Como resolver: MM maiúsculo para o mês, HH maiúsculo para a hora de 0 a 23: dd/MM/yyyy HH:mm.

CS0019 e CS0029: contas que o tipo não faz
$ cat menos.cs
DateOnly a = new DateOnly(2026, 10, 17);
DateOnly b = new DateOnly(2026, 12, 25);
Console.WriteLine(b - a);
$ dotnet run menos.cs
/home/ana/cs/menos.cs(3,19): error CS0019: O operador "-" não pode ser aplicado a operandos dos tipos "DateOnly" e "DateOnly"

Ocorreu uma falha no build. Corrija os erros de build e execute novamente.
$ cat dias.cs
DateTime a = new DateTime(2026, 10, 17);
DateTime b = new DateTime(2026, 12, 25);
int dias = b - a;
$ dotnet run dias.cs
/home/ana/cs/dias.cs(3,12): error CS0029: Não é possível converter implicitamente tipo "System.TimeSpan" em "int"

Ocorreu uma falha no build. Corrija os erros de build e execute novamente.

O que aconteceu: o DateOnly não sabe subtrair outro DateOnly (em inglês, Operator '-' cannot be applied to operands of type 'DateOnly' and 'DateOnly'). E a subtração de dois DateTime dá um TimeSpan, que não é um int.

Como resolver: com DateOnly, b.DayNumber - a.DayNumber. Com DateTime, int dias = (b - a).Days;.

Saturday em vez de sábado

O que aconteceu: Console.WriteLine(d.DayOfWeek) mostra o nome do valor do enum, que é sempre em inglês, em qualquer país.

Como resolver: para mostrar, d.ToString("dddd"), que segue a língua do computador (sábado). Para decidir, compare com o enum: if (d.DayOfWeek == DayOfWeek.Saturday || d.DayOfWeek == DayOfWeek.Sunday) é "fim de semana".


Referência rápida

CódigoO que faz
DateTime.Now / DateTime.Today / DateTime.UtcNowAgora / hoje à meia-noite / agora em UTC
new DateTime(ano, mês, dia, h, min, s)Uma data e hora
d.Year, Month, Day, Hour, Minute, DayOfWeek, DayOfYearAs partes
d.ToString("dd/MM/yyyy HH:mm"), "d", "D", "dddd"Formatar
d.AddDays(n), AddMonths, AddYears, AddHours, AddMinutesUma data nova, depois (ou antes, com negativo)
b - aA diferença, como TimeSpan
t.Days, t.Hours / t.TotalDays, t.TotalHoursUma parte / a duração inteira na unidade
new TimeSpan(h, min, s), TimeSpan.FromMinutes(n)Uma duração
new DateOnly(a, m, d), new TimeOnly(h, min)Só a data / só a hora
DateOnly.FromDateTime(d), x.DayNumberConverter / dias entre datas
DateTime.Parse(t), ParseExact(t, formato, cultura), TryParse(t, out d)Texto → data
DateTime.DaysInMonth(ano, mês)Quantos dias o mês tem
TimeZoneInfo.FindSystemTimeZoneById("Europe/Lisbon"), TimeZoneInfo.ConvertTime(d, fuso)Fusos
new DateTimeOffset(…, TimeSpan.FromHours(-3))Data e hora com o fuso junto

Exercícios

1. Daqui a uma semana

Complete para calcular a data 7 dias depois de hoje:

DateTime semanaQueVem = hoje.;

2. O formato brasileiro

Complete o formato para a data aparecer como 05/03/2026 (dia, mês e ano com 4 dígitos):

d.ToString("")

3. Só os dias

A variável falta é um TimeSpan. Complete para pegar a quantidade de dias como int:

int dias = falta.;

4. O que new DateTime(2026, 1, 31).AddMonths(1) devolve?

5. Qual tipo é o melhor para guardar o aniversário de alguém?

6. Um programa mostra d.ToString("dd/mm/yyyy") e a data sai com um "mês" estranho, como 17/42/2026. Por quê?

Missão final: a multa da biblioteca

Missão: a biblioteca da escola empresta livros por 14 dias e cobra R$ 1,50 por dia de atraso. A Ana pegou um livro em 17/10/2026 e devolveu em 05/11/2026. Complete o programa:

  1. calcule o prazo com emprestimo.AddDays(14) e mostre Devolver até: com o formato dddd, dd/MM/yyyy;
  2. calcule o atraso em dias com DayNumber (devolução menos prazo);
  3. se houver atraso, mostre Atraso: N dias e Multa: R$ com o valor em F2; se não, Devolvido no prazo.

A saída deve ser:

Devolver até: sábado, 31/10/2026
Atraso: 5 dias
Multa: R$ 7,50
DateOnly emprestimo = new DateOnly(2026, 10, 17);
DateOnly devolucao = new DateOnly(2026, 11, 5);
decimal multaPorDia = 1.50m;

Console.WriteLine($"Emprestado em: {emprestimo:dddd, dd/MM/yyyy}");
// 1. o prazo (14 dias depois do empréstimo)
// 2. o atraso, em dias
// 3. a multa
DateOnly emprestimo = new DateOnly(2026, 10, 17);
DateOnly devolucao = new DateOnly(2026, 11, 5);
decimal multaPorDia = 1.50m;

Console.WriteLine($"Emprestado em: {emprestimo:dddd, dd/MM/yyyy}");
DateOnly prazo = emprestimo.AddDays(14);
Console.WriteLine($"Devolver até: {prazo:dddd, dd/MM/yyyy}");

int atraso = devolucao.DayNumber - prazo.DayNumber;
if (atraso > 0)
{
    Console.WriteLine($"Atraso: {atraso} dias");
    Console.WriteLine($"Multa: R$ {atraso * multaPorDia:F2}");
}
else
{
    Console.WriteLine("Devolvido no prazo");
}

Depois de cumprir a missão, troque a devolução para new DateOnly(2026, 10, 30) e veja o Devolvido no prazo. Se quiser ir além: a biblioteca não abre aos domingos; se o prazo cair num domingo, passe para segunda (if (prazo.DayOfWeek == DayOfWeek.Sunday)).


Resumo

  • DateTime é um momento (data e hora); TimeSpan é uma duração. Momento − momento = duração; momento + duração = momento.
  • DateTime.Now muda a cada execução: para testar, use datas fixas com new DateTime(ano, mês, dia).
  • AddDays, AddMonths e companhia devolvem uma data nova e cuidam dos meses de tamanhos diferentes.
  • Formate com ToString: dd/MM/yyyy HH:mm (MM = mês, mm = minuto, HH = 24 horas), dddd e MMMM em português, yyyy-MM-dd para arquivos.
  • DateOnly e TimeOnly guardam só a data ou só a hora; dias entre DateOnly com DayNumber.
  • Texto → data: TryParse com texto do usuário, ParseExact quando você sabe o formato. Fusos: TimeZoneInfo e DateTimeOffset.