✅ Artigo atualizado em Setembro 2026: fusos horários agora com o
zoneinfoda biblioteca padrão (opytzficou como alternativa legada), saídas de exemplo corrigidas e aviso de quetimedeltanão soma meses nem anos. Também ganhou tabela de códigos de formato, erros comuns com a mensagem real e 8 exercícios resolvidos.
Resposta rápida
Para trabalhar com datas no Python, use o módulo datetime da biblioteca padrão: datetime.now() pega a data e hora atuais, strftime("%d/%m/%Y") transforma a data em texto no formato brasileiro, strptime(texto, "%d/%m/%Y") faz o caminho inverso e timedelta soma ou subtrai dias.
1
2
3
4
5
6
from datetime import datetime, date, timedelta
# saídas de 27/09/2026
print(datetime.now().strftime("%d/%m/%Y %H:%M")) # 27/09/2026 10:54
natal = datetime.strptime("25/12/2026", "%d/%m/%Y").date() # texto -> date
print((natal - date.today()).days) # 89 (dias até o Natal)
print(date.today() + timedelta(days=30)) # 2026-10-27
Resumo em 30 segundos:
-
dateguarda só a data,datetimeguarda data e hora,timedeltaguarda uma duração. -
strftime= data -> texto (format);strptime= texto -> data (parse). O formato precisa bater exatamente com o texto. - Subtrair duas datas devolve um
timedelta;.daysdá o número de dias. -
timedeltanão soma meses nem anos: para isso userelativedelta(python-dateutil). - Para fusos horários, use
zoneinfo(Python 3.9+) e nunca misturedatetimecom e sem fuso.
Salve salve Pythonista ![]()
Trabalhar com datas e horários é essencial em muitas aplicações Python.
Entender como manipular datas facilita tarefas como agendamentos, logs e análises temporais.
Neste artigo, abordaremos o módulo datetime do Python, explorando desde operações básicas até manipulações avançadas de datas e horários.
Com este conhecimento, você poderá gerenciar datas de forma eficiente em seus projetos Python.
Vá Direto ao Assunto…
- Introdução ao Módulo
datetime - Trabalhando com Datas e Horas
- Como pegar a data atual no Python
- Formatando Datas
- Convertendo Datas para Strings
- Convertendo Strings para Datas
- Códigos de formato do strftime e strptime (tabela)
- Calculando Diferença entre Datas
- Trabalhando com Timezones
- Trabalhando com
timedelta - Trabalhando com Datas em Diferentes Formatos
- Trabalhando com Datas em Diferentes Idiomas
- Qual usar: date, datetime, time, timedelta ou relativedelta?
- Casos Práticos Reais
- Erros comuns
- Exercícios resolvidos
Introdução ao Módulo datetime
O módulo datetime é a ferramenta padrão do Python para trabalhar com datas e horários.
Ele fornece classes para manipular datas, horários e intervalos de tempo.
Além disso, permite realizar operações como formatação, conversão e cálculo entre diferentes unidades de tempo.
Para começar, é necessário importar o módulo datetime:
1
import datetime
Ele tem quatro classes principais: date (data), time (horário), datetime (data e hora juntas) e timedelta (duração). A referência completa está na documentação oficial do módulo datetime.
Atenção à importação: com
import datetimevocê escrevedatetime.datetime.now()edatetime.date.today(), como nos exemplos das próximas seções. Comfrom datetime import datetime, date, escreve sódatetime.now()edate.today(). Misturar os dois estilos é um dos erros mais comuns (veja Erros comuns).
Trabalhando com Datas e Horas
Com o módulo datetime, podemos criar objetos que representam datas e horários específicos.
Vamos criar um objeto que representa a data atual:
1
2
data_atual = datetime.date.today()
print(data_atual)
Explicação do código:
-
Importação: Importamos o módulo
datetime. -
Objeto de Data Atual: Usamos
datetime.date.today()para obter a data de hoje. -
Exibição: Imprimimos a data atual no formato
YYYY-MM-DD.
A saída será:
1
2025-02-25
Criando um Objeto de Horário
Além de datas, podemos criar objetos que representam horários:
1
2
hora_atual = datetime.datetime.now().time()
print(hora_atual)
Explicação do código:
-
Método
now():datetime.datetime.now()retorna a data e hora atuais. -
Extração de Hora: Usamos
.time()para obter apenas o componente de horário. -
Exibição: Imprimimos a hora atual no formato
HH:MM:SS.microsegundos.
A saída será:
1
09:27:09.484035
Como pegar a data atual no Python
Existem quatro jeitos de pegar “agora” no Python, e a escolha depende do que você precisa:
1
2
3
4
5
6
7
from datetime import datetime, date, timezone
from zoneinfo import ZoneInfo
print(date.today()) # só a data
print(datetime.now()) # data e hora locais, sem fuso
print(datetime.now(ZoneInfo("America/Sao_Paulo"))) # data e hora com fuso
print(datetime.now(timezone.utc)) # data e hora em UTC
Em 27/09/2026, às 10:54 de Brasília, a saída será algo como:
1
2
3
4
2026-09-27
2026-09-27 10:54:05.097672
2026-09-27 10:54:05.097672-03:00
2026-09-27 13:54:05.097672+00:00
Evite
datetime.utcnow(): ele devolve umdatetimesem fuso (que parece local, mas é UTC) e está obsoleto desde o Python 3.12. Prefiradatetime.now(timezone.utc).
Com o objeto em mãos, você acessa cada parte por atributo e ainda pode formatar direto numa f-string, colocando o formato depois dos dois-pontos:
1
2
3
4
5
6
7
8
9
from datetime import datetime
agora = datetime(2026, 9, 27, 10, 54, 5) # use datetime.now() no seu código
print(agora.day, agora.month, agora.year)
print(agora.hour, agora.minute)
print(agora.weekday()) # 0 = segunda ... 6 = domingo
print(f"{agora:%d/%m/%Y}") # formato brasileiro
print(agora.isoformat(timespec="seconds"))
A saída será:
1
2
3
4
5
27 9 2026
10 54
6
27/09/2026
2026-09-27T10:54:05
O 6 indica domingo: 27/09/2026 cai num domingo.
Formatando Datas
Formatar datas é útil para exibir informações de maneira legível ou específica.
Usando strftime
A função strftime permite formatar objetos de data e hora:
1
2
3
data_atual = datetime.date.today()
data_formatada = data_atual.strftime("%d/%m/%Y")
print(data_formatada)
Explicação do código:
-
Formato Personalizado:
%drepresenta o dia,%mo mês e%Yo ano. -
Formatação: Convertendo
data_atualpara o formatoDD/MM/AAAA. - Exibição: Imprimimos a data formatada.
E a saída será:
1
25/02/2025
Exemplo de Formatação Completa
1
2
3
hora_atual = datetime.datetime.now().time()
hora_formatada = hora_atual.strftime("%H:%M:%S")
print("Hora:", hora_formatada)
Explicação do código:
-
Formato de Hora:
%Hpara horas,%Mpara minutos e%Spara segundos. -
Formatação: Convertendo
hora_atualpara o formatoHH:MM:SS. - Exibição: Imprimimos a hora formatada.
A saída será:
1
Hora: 09:29:09
Convertendo Datas para Strings
Converter objetos de data para strings é útil para salvar ou exibir informações.
Usando str()
A função str() converte objetos de data para strings em um formato padrão:
1
2
3
data_atual = datetime.date.today()
data_str = str(data_atual)
print(data_str)
Explicação do código:
-
Conversão: Usamos
str(data_atual)para converter o objeto de data em uma string. -
Exibição: Imprimimos a string resultante no formato
YYYY-MM-DD.
Sua saída será:
1
2025-02-25
Convertendo Strings para Datas
Às vezes, precisamos converter strings que representam datas em objetos de data.
Usando strptime
A função strptime permite analisar strings em objetos de data:
1
2
3
data_string = "25/12/2023"
data_convertida = datetime.datetime.strptime(data_string, "%d/%m/%Y").date()
print(data_convertida)
Explicação do código:
-
String de Data: Definimos
data_stringno formatoDD/MM/AAAA. -
Análise: Usamos
strptimepara converter a string em um objetodatetime. -
Extração de Data: Com
.date(), extraímos apenas a data. -
Exibição: Imprimimos a data convertida no formato
YYYY-MM-DD.
A saída será:
1
2023-12-25
Uma forma fácil de lembrar a diferença: strftime tem f de format (data -> texto) e strptime tem p de parse (texto -> data). No strptime, o formato precisa descrever o texto inteiro, inclusive barras, traços, espaços e a hora, se houver.
Códigos de formato do strftime e strptime (tabela)
Os mesmos códigos servem para strftime (data -> texto) e strptime (texto -> data). Os exemplos usam a data datetime(2026, 9, 7, 14, 5, 9), ou seja, 07/09/2026 às 14:05:09:
| Código | Significado | Resultado |
|---|---|---|
%d |
Dia do mês com 2 dígitos | 07 |
%m |
Mês com 2 dígitos | 09 |
%Y |
Ano com 4 dígitos | 2026 |
%y |
Ano com 2 dígitos | 26 |
%H |
Hora (00 a 23) | 14 |
%I |
Hora (01 a 12) | 02 |
%p |
AM ou PM | PM |
%M |
Minuto | 05 |
%S |
Segundo | 09 |
%A |
Dia da semana por extenso |
Monday (com locale pt_BR: segunda) |
%a |
Dia da semana abreviado |
Mon (com locale pt_BR: seg) |
%B |
Mês por extenso |
September (com locale pt_BR: setembro) |
%b |
Mês abreviado |
Sep (com locale pt_BR: set) |
%j |
Dia do ano (001 a 366) | 250 |
%w |
Dia da semana (0 = domingo) | 1 |
E as combinações mais pedidas:
| Formato | Resultado |
|---|---|
"%d/%m/%Y" |
07/09/2026 |
"%d/%m/%Y %H:%M" |
07/09/2026 14:05 |
"%Y-%m-%d" |
2026-09-07 |
"%Y-%m-%d %H:%M:%S" |
2026-09-07 14:05:09 |
"%A, %d de %B de %Y" (locale pt_BR) |
segunda, 07 de setembro de 2026 |
Cuidado com duas pegadinhas: %m é mês e %M é minuto; e %w conta a semana a partir do domingo (0), enquanto o método weekday() conta a partir da segunda (0). A lista completa de códigos está na documentação oficial do strftime e strptime.
Calculando Diferença entre Datas
Calcular a diferença entre datas é útil para determinar durações ou prazos.
Usando timedelta
A classe timedelta representa uma duração ou intervalo de tempo:
1
2
3
data_futura = datetime.date(2050, 1, 1)
diferenca = data_futura - data_atual
print(diferenca.days, "dias restantes")
Explicação do código:
- Data Futura: Criamos uma data específica para o futuro.
-
Cálculo da Diferença: Subtraímos
data_atualdedata_futurapara obter a diferença. - Exibição: Imprimimos o número de dias restantes.
Considerando data_atual igual a 25/02/2025, a saída será:
1
9076 dias restantes
Trabalhando com Timezones
Gerenciar fusos horários é crucial para aplicações globais.
Usando zoneinfo (recomendado)
Desde o Python 3.9, a biblioteca padrão tem o módulo zoneinfo, que dá acesso aos fusos horários do banco de dados da IANA (como America/Sao_Paulo), incluindo regras de horário de verão.
Esse é o caminho recomendado hoje, sem instalar nada:
1
2
3
4
5
6
import datetime
from zoneinfo import ZoneInfo
fuso_horario = ZoneInfo("America/Sao_Paulo")
data_hora_local = datetime.datetime.now(fuso_horario)
print(data_hora_local)
Explicação do código:
-
Importação do
ZoneInfo: Vem da biblioteca padrão, a partir do Python 3.9. - Definição do Fuso Horário: Criamos o fuso pelo nome da IANA.
-
Obtendo Data e Hora Local: Passamos o fuso para
now(), que devolve umdatetimecom fuso (aware). - Exibição: Imprimimos a data e hora com o deslocamento em relação ao UTC.
A saída será algo como:
1
2026-09-27 10:54:05.097672-03:00
Para converter um horário de um fuso para outro, use astimezone():
1
2
3
4
reuniao = datetime.datetime(2026, 9, 27, 14, 0, tzinfo=ZoneInfo("America/Sao_Paulo"))
print(reuniao)
print(reuniao.astimezone(ZoneInfo("Europe/Lisbon")))
print(reuniao.astimezone(datetime.timezone.utc))
A saída será:
1
2
3
2026-09-27 14:00:00-03:00
2026-09-27 18:00:00+01:00
2026-09-27 17:00:00+00:00
Windows: o Windows não traz o banco de dados de fusos da IANA. Nesse caso, instale o pacote
tzdata(pip install tzdata), que ozoneinfousa automaticamente como alternativa. Sem ele,ZoneInfo(...)levantaZoneInfoNotFoundError.
Usando pytz
O pytz é uma biblioteca externa que foi, por muitos anos, a forma padrão de trabalhar com fusos no Python. Hoje ela é considerada legada: para código novo prefira o zoneinfo acima. Você ainda vai encontrá-la em projetos antigos, então vale saber ler.
Para isso, instale o pytz utilizando o pip com pip install pytz. Em seguida:
1
2
3
4
5
import pytz
fuso_horario = pytz.timezone("America/Sao_Paulo")
data_hora_local = datetime.datetime.now(fuso_horario)
print(data_hora_local)
Explicação do código:
-
Importação do
pytz: Importamos a bibliotecapytz. - Definição do Fuso Horário: Especificamos o fuso horário desejado.
-
Obtendo Data e Hora Local: Usamos
nowcom o fuso horário definido. - Exibição: Imprimimos a data e hora local com o fuso aplicado.
A saída será:
1
2025-02-25 15:37:28.861810-03:00
A parte final da data -03:00 é o fuso de São Paulo, GMT-3!
Cuidado com uma pegadinha clássica do pytz: não passe o fuso direto em tzinfo= ao construir um datetime (por exemplo datetime.datetime(2026, 9, 27, 14, 0, tzinfo=pytz.timezone("America/Sao_Paulo"))), porque o resultado sai com o deslocamento histórico -03:06. Com pytz o certo é usar fuso_horario.localize(...). Com zoneinfo essa pegadinha não existe.
Aproveitando o tema: Estou desenvolvendo o Ebookr.ai, uma plataforma para criar ebooks profissionais com IA sobre qualquer assunto. Capa gerada por IA, infográficos automáticos e exportação em PDF. Ideal para documentar seu conhecimento. Dá uma olhada!
Trabalhando com timedelta
A classe timedelta permite realizar operações com intervalos de tempo.
Adicionando Dias a uma Data
1
2
3
4
5
6
import datetime
data_atual = datetime.date.today()
intervalo = datetime.timedelta(days=10)
nova_data = data_atual + intervalo
print(nova_data)
Explicação do código:
-
Criação do Intervalo: Definimos um intervalo de 10 dias com
datetime.timedelta(days=10). - Adição à Data Atual: Somamos o intervalo à data atual.
- Exibição: Imprimimos a nova data resultante.
A saída esperada é:
1
2025-03-07
Subtraindo Horas de um Horário
1
2
3
4
5
6
intervalo_horas = datetime.timedelta(hours=5)
nova_hora = datetime.datetime.now().time()
print("Hora atual:", nova_hora)
hora_ajustada = (datetime.datetime.combine(datetime.date.today(), nova_hora) - intervalo_horas).time()
print("Hora ajustada:", hora_ajustada)
Explicação do código:
- Criação do Intervalo de Horas: Definimos um intervalo de 5 horas.
- Combinação de Data e Hora: Combinamos a data de hoje com a hora atual.
- Subtração do Intervalo: Subtraímos o intervalo de horas da data e hora combinadas.
- Extração da Hora Ajustada: Obtemos apenas o componente de hora.
- Exibição: Imprimimos a hora antes e após a subtração.
Veja a saída esperada:
1
2
Hora atual: 15:40:58.201792
Hora ajustada: 10:40:58.201792
E para somar meses ou anos?
O timedelta só aceita days, seconds, microseconds, milliseconds, minutes, hours e weeks. Ele não tem months nem years (tentar datetime.timedelta(months=1) levanta TypeError), porque meses e anos não têm duração fixa.
Para isso, a opção mais usada é o relativedelta, da biblioteca externa python-dateutil (instale com pip install python-dateutil):
1
2
3
4
5
6
import datetime
from dateutil.relativedelta import relativedelta
data = datetime.date(2025, 1, 31)
print(data + relativedelta(months=1))
print(data + relativedelta(years=1))
A saída será:
1
2
2025-02-28
2026-01-31
Repare que 31 de janeiro + 1 mês vira 28 de fevereiro: o relativedelta ajusta para o último dia válido do mês.
Trabalhando com Datas em Diferentes Formatos
Datas podem estar em diversos formatos, dependendo da aplicação.
Parsing de Múltiplos Formatos
Podemos criar funções para lidar com múltiplos formatos de data:
1
2
3
4
5
6
7
8
9
10
def parse_data(data_str):
for fmt in ("%d/%m/%Y", "%Y-%m-%d", "%m-%d-%Y"):
try:
return datetime.datetime.strptime(data_str, fmt).date()
except ValueError:
continue
raise ValueError("Formato de data inválido")
data_exemplo = parse_data("12-31-2023")
print(data_exemplo)
Explicação do código:
- Função de Parsing: Tentamos diferentes formatos para analisar a string de data.
- Laço de Tentativas: Iteramos sobre uma lista de formatos possíveis.
- Retorno da Data: Retornamos a data convertida se o formato corresponder.
- Exceção: Lançamos um erro se nenhum formato for válido.
-
Exibição: Imprimimos a data convertida no formato
YYYY-MM-DD.
A saída será:
1
2023-12-31
O try/except ValueError é o que permite testar um formato atrás do outro sem quebrar o programa. Se quiser entender melhor esse mecanismo, veja o guia de tratamento de erros e exceções no Python.
Atenção se você acrescentar formatos parecidos à lista: uma string como "01/02/2026" é válida tanto em %d/%m/%Y (1º de fevereiro) quanto em %m/%d/%Y (2 de janeiro), e a função devolveria o primeiro que funcionar. Por isso, prefira saber de antemão o formato de cada fonte de dados.
Trabalhando com Datas em Diferentes Idiomas
Manipular datas em diferentes idiomas melhora a experiência do usuário global.
Usando locale
O módulo locale permite configurar a localização para formatação de datas:
1
2
3
4
5
6
7
8
9
10
import locale
# Seta a categoria do locale "tempo" (Locale Category: Time) para
# - Português do Brasil (pt_BR)
# - Codificação UTF-8
locale.setlocale(locale.LC_TIME, 'pt_BR.UTF-8')
data_atual = datetime.date.today()
data_formatada = data_atual.strftime("%A, %d de %B de %Y")
print(data_formatada)
Explicação do código:
-
Importação do
locale: Importamos o módulolocale. - Configuração da Localização: Definimos a localidade para português brasileiro.
-
Formatação com
locale: Usamosstrftimepara formatar a data com nomes de dias e meses em português. - Exibição: Imprimimos a data formatada, por exemplo, “segunda, 25 de dezembro de 2023”.
A saída será (em 25/02/2025, no Linux):
1
terça, 25 de fevereiro de 2025
Os nomes de dias e meses vêm do sistema operacional, então podem variar um pouco (por exemplo, “terça” ou “terça-feira”). Se o locale pt_BR.UTF-8 não estiver instalado, setlocale levanta locale.Error.
Qual usar: date, datetime, time, timedelta ou relativedelta?
Boa parte das dúvidas com datas no Python se resolve escolhendo a classe certa logo no começo:
| Situação | Use | Exemplo |
|---|---|---|
| Só a data (aniversário, vencimento, feriado) | date |
date(2026, 9, 27) |
| Data e hora (log, pedido, agendamento) | datetime |
datetime(2026, 9, 27, 14, 30) |
| Só o horário, sem dia (abertura da loja) | time |
time(8, 30) |
| Somar ou subtrair dias, horas, minutos ou semanas | timedelta |
hoje + timedelta(days=10) |
| Somar meses ou anos respeitando o calendário |
relativedelta (python-dateutil) |
hoje + relativedelta(months=1) |
| Horário de um lugar específico ou conversão entre fusos |
datetime + zoneinfo
|
datetime.now(ZoneInfo("America/Sao_Paulo")) |
| Mostrar a data para o usuário |
strftime ou f-string |
f"{hoje:%d/%m/%Y}" |
| Ler uma data digitada ou vinda de um arquivo | strptime |
datetime.strptime(txt, "%d/%m/%Y") |
Regra prática: se a hora não importa, use date. Comparar ou subtrair date com datetime gera TypeError, então converta com .date() antes.
Saber escolher a classe certa de data já resolve boa parte dos bugs do dia a dia - e prática assim, com projetos guiados do zero ao avançado, é o que você encontra na Jornada Python:
Casos Práticos Reais
1. Sistema de Agendamentos
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from datetime import datetime, timedelta
from zoneinfo import ZoneInfo
def agendar_reuniao(data_hora_str, duracao_minutos, timezone="America/Sao_Paulo"):
"""Agenda reunião e calcula horário de fim"""
tz = ZoneInfo(timezone)
inicio = datetime.fromisoformat(data_hora_str).replace(tzinfo=tz)
fim = inicio + timedelta(minutes=duracao_minutos)
return {
"inicio": inicio.isoformat(),
"fim": fim.isoformat(),
"duracao": f"{duracao_minutos} minutos",
"dia_semana": inicio.strftime("%A"),
"horario": inicio.strftime("%H:%M")
}
# Uso
reuniao = agendar_reuniao("2025-02-28 14:00:00", 90)
print(reuniao)
A saída será:
1
{'inicio': '2025-02-28T14:00:00-03:00', 'fim': '2025-02-28T15:30:00-03:00', 'duracao': '90 minutos', 'dia_semana': 'Friday', 'horario': '14:00'}
Repare que dia_semana saiu em inglês: sem configurar o locale (veja a seção anterior), %A usa os nomes em inglês.
2. Cálculo de Idade e Validações
Este exemplo usa o relativedelta, da biblioteca externa python-dateutil (pip install python-dateutil):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from datetime import date, datetime
from dateutil.relativedelta import relativedelta
def calcular_idade_exata(data_nascimento):
"""Calcula idade exata em anos, meses e dias"""
hoje = date.today()
if isinstance(data_nascimento, str):
data_nascimento = datetime.strptime(data_nascimento, "%Y-%m-%d").date()
diff = relativedelta(hoje, data_nascimento)
return {
"anos": diff.years,
"meses": diff.months,
"dias": diff.days,
"total_dias": (hoje - data_nascimento).days,
"maior_idade": diff.years >= 18
}
# Uso
idade = calcular_idade_exata("1990-05-15")
print(f"{idade['anos']} anos, {idade['meses']} meses, {idade['dias']} dias")
Como depende da data de hoje, a saída muda a cada dia. Rodando em 27/09/2026:
1
36 anos, 4 meses, 12 dias
3. Dias Úteis (excluindo fins de semana)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from datetime import date, timedelta
def calcular_dias_uteis(data_inicio, data_fim, feriados=None):
"""Calcula número de dias úteis entre duas datas"""
if feriados is None:
feriados = []
dias_uteis = 0
data_atual = data_inicio
while data_atual <= data_fim:
# 0=Segunda, 6=Domingo
if data_atual.weekday() < 5 and data_atual not in feriados:
dias_uteis += 1
data_atual += timedelta(days=1)
return dias_uteis
# Uso
inicio = date(2025, 3, 1)
fim = date(2025, 3, 31)
feriados = [date(2025, 3, 3), date(2025, 3, 4)] # Carnaval 2025
uteis = calcular_dias_uteis(inicio, fim, feriados)
print(f"Dias úteis: {uteis}")
A saída será:
1
Dias úteis: 19
4. Lembretes e Notificações
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from datetime import datetime, timedelta
def calcular_lembretes(data_evento, lembretes=(7, 3, 1)):
"""Calcula datas para enviar lembretes antes do evento"""
if isinstance(data_evento, str):
data_evento = datetime.fromisoformat(data_evento)
alertas = []
for dias in lembretes:
data_lembrete = data_evento - timedelta(days=dias)
alertas.append({
"dias_antes": dias,
"data": data_lembrete.strftime("%d/%m/%Y"),
"horario": data_lembrete.strftime("%H:%M"),
"mensagem": f"Lembrete: evento em {dias} dia(s)"
})
return alertas
# Uso
event_date = "2025-03-15 10:00:00"
alertas = calcular_lembretes(event_date)
for alerta in alertas:
print(f"{alerta['data']} - {alerta['mensagem']}")
A saída será:
1
2
3
08/03/2025 - Lembrete: evento em 7 dia(s)
12/03/2025 - Lembrete: evento em 3 dia(s)
14/03/2025 - Lembrete: evento em 1 dia(s)
5. Prazo de Vencimento em Dias Úteis
Uma dúvida frequente (e comum em provas) é qual função pronta do Python calcula um prazo “em N dias úteis”. Não existe função built-in para isso. A solução com a biblioteca padrão é avançar um dia por vez com timedelta e contar só os dias de segunda a sexta que não são feriados:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from datetime import date, timedelta
def somar_dias_uteis(inicio, dias_uteis, feriados=()):
"""Retorna a data que fica N dias úteis depois de inicio"""
data = inicio
while dias_uteis > 0:
data += timedelta(days=1)
if data.weekday() < 5 and data not in feriados:
dias_uteis -= 1
return data
# Pedido feito na sexta, 25/09/2026, com prazo de 5 dias úteis
print(somar_dias_uteis(date(2026, 9, 25), 5))
# Pedido na sexta, 09/10/2026, 3 dias úteis, com o feriado de 12/10
print(somar_dias_uteis(date(2026, 10, 9), 3, feriados=[date(2026, 10, 12)]))
A saída será:
1
2
2026-10-02
2026-10-15
No segundo caso, o sábado, o domingo e o feriado de segunda (12/10) são pulados, então os 3 dias úteis são 13, 14 e 15 de outubro. Se o seu projeto já usa NumPy, numpy.busday_offset faz o mesmo cálculo.
Erros comuns
Estes são os erros com datas que mais aparecem em código de iniciante. As mensagens abaixo são as reais do Python 3.10.
1. ValueError: time data ... does not match format
1
2
3
from datetime import datetime
datetime.strptime("2026-09-27", "%d/%m/%Y")
1
ValueError: time data '2026-09-27' does not match format '%d/%m/%Y'
O formato precisa descrever o texto exatamente. Aqui o texto está em ano-mês-dia com traços, então o formato certo é "%Y-%m-%d". Uma variação do mesmo problema é o texto ter mais coisa que o formato:
1
datetime.strptime("27/09/2026 14:30", "%d/%m/%Y")
1
ValueError: unconverted data remains: 14:30
Correção: inclua a hora no formato, datetime.strptime("27/09/2026 14:30", "%d/%m/%Y %H:%M").
2. AttributeError por misturar os estilos de importação
1
2
3
from datetime import datetime
agora = datetime.datetime.now()
1
AttributeError: type object 'datetime.datetime' has no attribute 'datetime'
O módulo e a classe se chamam datetime. Depois de from datetime import datetime, o nome datetime já é a classe, então basta datetime.now(). Se você fez import datetime, aí sim é datetime.datetime.now().
3. TypeError ao comparar ou subtrair datetime com e sem fuso
1
2
3
4
5
from datetime import datetime, timezone
prazo = datetime(2026, 9, 27, 14, 0) # sem fuso (naive)
agora = datetime.now(timezone.utc) # com fuso (aware)
print(agora > prazo)
1
TypeError: can't compare offset-naive and offset-aware datetimes
Na subtração, a mensagem é TypeError: can't subtract offset-naive and offset-aware datetimes. Correção: deixe os dois do mesmo tipo, de preferência ambos com fuso, por exemplo datetime(2026, 9, 27, 14, 0, tzinfo=ZoneInfo("America/Sao_Paulo")). O mesmo vale para date e datetime: date(2026, 9, 27) < datetime(2026, 9, 28) gera TypeError: can't compare datetime.datetime to datetime.date.
4. Tentar somar meses com timedelta
1
2
3
from datetime import date, timedelta
proximo_mes = date(2026, 1, 31) + timedelta(months=1)
1
TypeError: 'months' is an invalid keyword argument for __new__()
O timedelta não tem months nem years. E trocar por timedelta(days=30) não resolve: date(2026, 1, 31) + timedelta(days=30) dá 2026-03-02, pulando fevereiro inteiro. Para meses e anos, use o relativedelta mostrado em E para somar meses ou anos?.
5. strftime com nomes em inglês (e o locale.Error)
1
2
3
from datetime import date
print(date(2026, 9, 27).strftime("%A, %d de %B de %Y"))
1
Sunday, 27 de September de 2026
Não é erro de sintaxe, mas é o resultado que ninguém quer: sem configurar o locale, %A e %B saem em inglês. A correção é locale.setlocale(locale.LC_TIME, "pt_BR.UTF-8") antes do strftime. Se esse locale não estiver instalado no sistema (comum em containers Docker e em alguns Windows), a chamada falha com:
1
locale.Error: unsupported locale setting
Nesse caso, instale o locale no sistema ou use a alternativa sem locale do Exercício 2 abaixo (uma lista com os nomes em português indexada por weekday()).
Exercícios resolvidos
Tente resolver antes de abrir a solução. Para deixar as saídas reproduzíveis, os exercícios usam datas fixas no lugar de date.today(). Se quiser praticar datas, arquivos e APIs em projetos guiados, o curso de Python completo da Jornada Python tem exercícios assim do começo ao fim.
Exercício 1. Dada a data date(2026, 9, 7), mostre-a no formato brasileiro dd/mm/aaaa, de duas formas: com strftime e com f-string.
Ver solução
1
2
3
4
5
from datetime import date
d = date(2026, 9, 7)
print(d.strftime("%d/%m/%Y"))
print(f"{d:%d/%m/%Y}")
Saída: 07/09/2026 (nas duas linhas)
%d e %m sempre usam 2 dígitos, por isso o dia 7 vira 07. Na f-string, tudo o que vem depois dos dois-pontos é repassado para o strftime.
Exercício 2. Descubra em que dia da semana caiu o Natal de 2025 e mostre o nome em português, sem depender do locale.
Ver solução
1
2
3
4
5
6
7
from datetime import date
DIAS = ["segunda-feira", "terça-feira", "quarta-feira", "quinta-feira",
"sexta-feira", "sábado", "domingo"]
natal = date(2025, 12, 25)
print(DIAS[natal.weekday()])
Saída: quinta-feira
weekday() devolve um número de 0 (segunda) a 6 (domingo), que serve direto como índice da lista. Isso funciona em qualquer sistema, ao contrário de %A com locale.
Exercício 3. O usuário digita a data de um evento no formato dd/mm/aaaa. Considerando que hoje é 27/09/2026 e que ele digitou 25/12/2026, mostre quantos dias faltam.
Ver solução
1
2
3
4
5
6
7
from datetime import date, datetime
hoje = date(2026, 9, 27) # no seu código: date.today()
texto = "25/12/2026" # no seu código: input("Data do evento: ")
alvo = datetime.strptime(texto, "%d/%m/%Y").date()
print(f"Faltam {(alvo - hoje).days} dias")
Saída: Faltam 89 dias
O strptime converte o texto em datetime, o .date() descarta a hora e a subtração devolve um timedelta, cujo .days é o que queremos. Para ler o valor do teclado, use input() como mostrado no post de entrada e saída de dados com input e print.
Exercício 4. Escreva uma função calcular_idade(nascimento, hoje) que devolve a idade em anos completos, sem bibliotecas externas. Teste com nascimentos em 15/05/1990 e 10/10/2000, considerando hoje = 27/09/2026.
Ver solução
1
2
3
4
5
6
7
8
9
from datetime import date
def calcular_idade(nascimento, hoje):
ja_fez = (hoje.month, hoje.day) >= (nascimento.month, nascimento.day)
return hoje.year - nascimento.year - (0 if ja_fez else 1)
hoje = date(2026, 9, 27)
print(calcular_idade(date(1990, 5, 15), hoje))
print(calcular_idade(date(2000, 10, 10), hoje))
Saída: 36 e 25
Só subtrair os anos erra para quem ainda não fez aniversário no ano (2026 - 2000 = 26, mas a pessoa só completa 26 em outubro). Comparar a tupla (mês, dia) resolve isso. Dividir (hoje - nascimento).days por 365 também erra, por causa dos anos bissextos.
Exercício 5 (estilo prova). Qual é a saída do código abaixo?
1
2
3
from datetime import datetime
print(datetime.strptime("07/09/2026", "%d/%m/%Y").strftime("%Y-%m-%d"))
a) 07/09/2026
b) 2026-09-07
c) 2026-07-09
d) ValueError
Ver solução
Resposta: b) 2026-09-07
O strptime lê o texto como dia 07, mês 09, ano 2026. Depois, o strftime escreve a mesma data em outra ordem: ano, mês e dia separados por traço. A alternativa c inverteria dia e mês, e não há ValueError porque o formato bate com o texto.
Exercício 6 (estilo prova). Qual é o resultado de date(2026, 1, 31) + timedelta(days=30)?
a) 2026-02-28
b) 2026-03-02
c) 2026-02-31
d) TypeError
Ver solução
1
2
3
from datetime import date, timedelta
print(date(2026, 1, 31) + timedelta(days=30))
Saída: 2026-03-02
Resposta: b. O timedelta soma exatamente 30 dias: fevereiro de 2026 tem 28 dias, então 31/01 + 28 dias = 28/02, e mais 2 dias = 02/03. A alternativa a seria o resultado de relativedelta(months=1), e 2026-02-31 não existe.
Exercício 7. Um boleto vence 30 dias após a emissão, mas, se o vencimento cair num sábado ou domingo, passa para a segunda-feira seguinte. Calcule o vencimento para emissões em 01/10/2026 e 27/09/2026.
Ver solução
1
2
3
4
5
6
7
8
9
10
from datetime import date, timedelta
def vencimento(emissao, prazo_dias=30):
venc = emissao + timedelta(days=prazo_dias)
while venc.weekday() >= 5: # 5 = sábado, 6 = domingo
venc += timedelta(days=1)
return venc
print(vencimento(date(2026, 10, 1)))
print(vencimento(date(2026, 9, 27)))
Saída: 2026-11-02 e 2026-10-27
01/10 + 30 dias cai em 31/10/2026, um sábado, então o laço avança até segunda, 02/11. Já 27/10/2026 é uma terça, e o vencimento fica como está.
Exercício 8. Um funcionário entrou às 08:30 e saiu às 17:45. Calcule o tempo trabalhado como timedelta e em horas decimais.
Ver solução
1
2
3
4
5
6
7
8
from datetime import datetime
entrada = datetime.strptime("08:30", "%H:%M")
saida = datetime.strptime("17:45", "%H:%M")
jornada = saida - entrada
print(jornada)
print(jornada.total_seconds() / 3600)
Saída: 9:15:00 e 9.25
Objetos time não podem ser subtraídos, mas strptime só com hora cria um datetime (no dia 01/01/1900), e aí a subtração funciona. total_seconds() converte o timedelta em segundos, e dividir por 3600 dá as horas.
Antes de continuar… Está curtindo esse conteúdo? ![]()
Que tal receber 30 dias de conteúdo direto na sua Caixa de Entrada?
Conclusão
Neste artigo, exploramos como trabalhar com datas no Python utilizando o módulo datetime.
Aprendemos a criar e formatar datas e horários, converter entre strings e objetos de data, calcular diferenças e manipular fusos horários com o zoneinfo.
Além disso, abordamos operações com timedelta (e o relativedelta para meses e anos), manipulações de datas futuras e passadas e formatação de datas em diferentes idiomas.
Com esses conhecimentos, você está preparado para gerenciar datas de forma eficaz em suas aplicações Python!
Quer mais exemplos? Veja também nosso post sobre manipulação de datas e horas no Python.
Perguntas frequentes
Como pegar a data atual no Python?
Importe o módulo datetime da biblioteca padrão e use date.today() para só a data (ex.: 2026-09-27) ou datetime.now() para data e hora (ex.: 2026-09-27 10:54:05.097672). Com fuso horário, passe um ZoneInfo: datetime.now(ZoneInfo("America/Sao_Paulo")). Para UTC, use datetime.now(timezone.utc), porque datetime.utcnow() está obsoleto desde o Python 3.12.
Como formatar uma data no formato brasileiro dd/mm/aaaa em Python?
Use o método strftime com os códigos %d (dia), %m (mês) e %Y (ano com 4 dígitos): date(2026, 9, 7).strftime("%d/%m/%Y") devolve 07/09/2026. Dentro de uma f-string o mesmo formato funciona depois dos dois-pontos: f"{data:%d/%m/%Y}". Para incluir a hora, acrescente %H:%M.
Como converter uma string em data no Python?
Use datetime.strptime(texto, formato), informando um formato que descreva o texto exatamente. Para "25/12/2026", o formato é "%d/%m/%Y": datetime.strptime("25/12/2026", "%d/%m/%Y") devolve um datetime, e .date() deixa só a data. Se o texto não bater com o formato, o Python levanta ValueError: time data ... does not match format. Para datas no padrão ISO (2026-12-25), date.fromisoformat() é mais simples.
Como calcular a diferença entre duas datas em Python?
Subtraia uma data da outra: o resultado é um timedelta, e o atributo .days dá o número de dias. Exemplo: (date(2026, 12, 25) - date(2026, 9, 27)).days resulta em 89. Com datetime, use .total_seconds() para ter a diferença exata em segundos. As duas datas precisam ser do mesmo tipo e, se tiverem fuso, ambas precisam ter fuso.
Como somar dias, meses ou anos a uma data no Python?
Para dias, horas, minutos e semanas use timedelta: date(2026, 9, 27) + timedelta(days=30) dá 2026-10-27. O timedelta não aceita months nem years, porque meses e anos não têm duração fixa. Para isso use relativedelta, da biblioteca externa python-dateutil: date(2025, 1, 31) + relativedelta(months=1) dá 2025-02-28.
Como mostrar o dia da semana e o nome do mês em português no Python?
Por padrão, %A e %B saem em inglês (Monday, September). Para português, chame locale.setlocale(locale.LC_TIME, "pt_BR.UTF-8") antes do strftime, desde que esse locale exista no sistema (senão ocorre locale.Error: unsupported locale setting). Uma alternativa que não depende do sistema é usar data.weekday(), que devolve 0 para segunda e 6 para domingo, como índice de uma lista com os nomes em português.
Qual a diferença entre date, datetime, time e timedelta no Python?
São as quatro classes principais do módulo datetime. date guarda só dia, mês e ano; time guarda só hora, minuto, segundo e microssegundo; datetime guarda data e hora juntas (e, opcionalmente, o fuso); timedelta representa uma duração, como 10 dias ou 5 horas, e é o resultado da subtração de duas datas.
Qual função built-in do Python calcula uma data de vencimento considerando dias úteis?
Nenhuma: o Python não tem função pronta para dias úteis. A solução com a biblioteca padrão é somar timedelta(days=1) em um laço e contar só os dias em que data.weekday() < 5 (segunda a sexta) e que não estão numa lista de feriados. Quem já usa NumPy pode recorrer a numpy.busday_offset, que faz o mesmo cálculo.
"Porque o Senhor dá a sabedoria, e da sua boca vem a inteligência e o entendimento" Pv 2:6