Python Datetime: Guia Completo de Datas e Horas em Python
Updated on
Trabalhar com datas e horas em Python deveria ser simples, mas raramente é. Você precisa fazer parsing de uma string de data de um arquivo CSV, mas "01/02/2026" pode significar 2 de janeiro ou 1 de fevereiro dependendo da localidade. Você quer calcular a diferença entre dois timestamps, mas um é uma string e o outro é uma época Unix. Você confunde strftime e strptime pela décima vez neste mês. Operações de data e hora são uma fonte constante de bugs, erros de deslocamento e dores de cabeça com fusos horários em código de produção.
As consequências vão além do incômodo. Um formato de data errado em um relatório financeiro significa cálculos incorretos. Uma comparação naive de datetime que ignora fusos horários causa jobs cron duplicados. Um cálculo errado de timedelta cobra de um cliente 31 dias em vez de 30.
O módulo integrado datetime do Python resolve esses problemas com uma API limpa e consistente. Ele fornece classes para datas, horas, timestamps e durações. Uma vez que você aprende seus padrões -- e especialmente a diferença entre strftime e strptime -- você pode lidar com qualquer operação de data sem bibliotecas de terceiros.
Obtendo a Data e Hora Atuais
O ponto de partida mais comum é obter a data e hora atuais. O módulo datetime oferece várias formas de fazer isso.
from datetime import datetime, date
# Data e hora atuais
now = datetime.now()
print(now) # 2026-02-10 14:30:45.123456
# Apenas data atual
today = date.today()
print(today) # 2026-02-10
# datetime.today() é similar a datetime.now() mas sem suporte a fuso horário
now_alt = datetime.today()
print(now_alt) # 2026-02-10 14:30:45.123456A diferença entre datetime.now() e datetime.today() é sutil mas importante. datetime.now() aceita um parâmetro opcional tz para datetimes com fuso horário. datetime.today() não. Para a maioria do código, prefira datetime.now().
from datetime import datetime
from zoneinfo import ZoneInfo
# Hora atual com fuso horário
utc_now = datetime.now(tz=ZoneInfo("UTC"))
print(utc_now) # 2026-02-10 14:30:45.123456+00:00
tokyo_now = datetime.now(tz=ZoneInfo("Asia/Tokyo"))
print(tokyo_now) # 2026-02-10 23:30:45.123456+09:00Criando Objetos Datetime
Você pode criar objetos datetime a partir de componentes individuais ou de dados existentes.
from datetime import datetime, date, time
# A partir de ano, mês, dia, hora, minuto, segundo
dt = datetime(2026, 3, 15, 9, 30, 0)
print(dt) # 2026-03-15 09:30:00
# Apenas data
d = date(2026, 12, 25)
print(d) # 2026-12-25
# Apenas hora
t = time(14, 30, 0)
print(t) # 14:30:00
# Combinar data e hora
combined = datetime.combine(d, t)
print(combined) # 2026-12-25 14:30:00Você também pode extrair componentes de um datetime existente.
from datetime import datetime
dt = datetime(2026, 3, 15, 9, 30, 45)
print(dt.year) # 2026
print(dt.month) # 3
print(dt.day) # 15
print(dt.hour) # 9
print(dt.minute) # 30
print(dt.second) # 45
print(dt.weekday()) # 6 (Domingo, Segunda=0)
print(dt.isoformat()) # 2026-03-15T09:30:45Formatando Datas com strftime
strftime significa "string format time" (formatar string de tempo). Ele converte um objeto datetime em uma string formatada. Você passa uma string de formato com diretivas que são substituídas por componentes de data.
from datetime import datetime
dt = datetime(2026, 3, 15, 9, 5, 7)
# Formatos comuns
print(dt.strftime("%Y-%m-%d")) # 2026-03-15
print(dt.strftime("%d/%m/%Y")) # 15/03/2026
print(dt.strftime("%B %d, %Y")) # March 15, 2026
print(dt.strftime("%Y-%m-%d %H:%M:%S")) # 2026-03-15 09:05:07
print(dt.strftime("%I:%M %p")) # 09:05 AM
print(dt.strftime("%A, %B %d, %Y")) # Sunday, March 15, 2026Uma forma rápida de lembrar: strftime = string from time (datetime para string).
Referência de Códigos de Formato strftime
| Código | Significado | Exemplo |
|---|---|---|
%Y | Ano com 4 dígitos | 2026 |
%y | Ano com 2 dígitos | 26 |
%m | Mês com zero à esquerda | 03 |
%B | Nome completo do mês | March |
%b | Nome abreviado do mês | Mar |
%d | Dia do mês (com zero) | 15 |
%A | Nome completo do dia da semana | Sunday |
%a | Nome abreviado do dia da semana | Sun |
%H | Hora (24h, com zero) | 09 |
%I | Hora (12h, com zero) | 09 |
%M | Minuto (com zero) | 05 |
%S | Segundo (com zero) | 07 |
%p | AM/PM | AM |
%f | Microssegundo (6 dígitos com zero) | 000000 |
%z | Deslocamento UTC (+HHMM ou -HHMM) | +0000 |
%Z | Nome do fuso horário | UTC |
%j | Dia do ano (001-366) | 074 |
%% | Caractere literal % | % |
Padrões de Formato Mais Usados
| Padrão | String de Formato | Saída |
|---|---|---|
| ISO 8601 | %Y-%m-%dT%H:%M:%S | 2026-03-15T09:05:07 |
| Data EUA | %m/%d/%Y | 03/15/2026 |
| Data europeia | %d/%m/%Y | 15/03/2026 |
| Data legível | %B %d, %Y | March 15, 2026 |
| Timestamp de log | %Y-%m-%d %H:%M:%S | 2026-03-15 09:05:07 |
| Hora 12h | %I:%M:%S %p | 09:05:07 AM |
| Data compacta | %Y%m%d | 20260315 |
| Timestamp seguro para arquivo | %Y%m%d_%H%M%S | 20260315_090507 |
Parsing de Strings com strptime
strptime significa "string parse time" (fazer parsing de string de tempo). É o inverso de strftime -- converte uma string em um objeto datetime. Você fornece a string e o formato que ela segue.
from datetime import datetime
# Fazer parsing de vários formatos de string de data
dt1 = datetime.strptime("2026-03-15", "%Y-%m-%d")
print(dt1) # 2026-03-15 00:00:00
dt2 = datetime.strptime("15/03/2026", "%d/%m/%Y")
print(dt2) # 2026-03-15 00:00:00
dt3 = datetime.strptime("March 15, 2026 09:30 AM", "%B %d, %Y %I:%M %p")
print(dt3) # 2026-03-15 09:30:00
dt4 = datetime.strptime("2026-03-15T09:30:00", "%Y-%m-%dT%H:%M:%S")
print(dt4) # 2026-03-15 09:30:00Lembre-se: strptime = string parse time (string para datetime).
Tratando Erros de Parsing
Se a string não corresponder ao formato, Python levanta um ValueError. Sempre envolva chamadas strptime em tratamento de erros ao fazer parsing de entrada do usuário ou dados externos.
from datetime import datetime
def safe_parse_date(date_string, fmt="%Y-%m-%d"):
"""Parse a date string safely, returning None on failure."""
try:
return datetime.strptime(date_string, fmt)
except ValueError as e:
print(f"Could not parse '{date_string}': {e}")
return None
# Valid input
print(safe_parse_date("2026-03-15")) # 2026-03-15 00:00:00
# Invalid input
print(safe_parse_date("15-03-2026")) # Could not parse '15-03-2026': ...
print(safe_parse_date("not a date")) # Could not parse 'not a date': ...Parsing de Múltiplos Formatos
Quando você recebe datas em formatos imprevisíveis, tente múltiplos padrões.
from datetime import datetime
def parse_flexible_date(date_string):
"""Try multiple date formats and return the first match."""
formats = [
"%Y-%m-%d",
"%d/%m/%Y",
"%m/%d/%Y",
"%B %d, %Y",
"%b %d, %Y",
"%Y-%m-%dT%H:%M:%S",
"%Y-%m-%d %H:%M:%S",
]
for fmt in formats:
try:
return datetime.strptime(date_string, fmt)
except ValueError:
continue
raise ValueError(f"No matching format found for '{date_string}'")
print(parse_flexible_date("2026-03-15")) # 2026-03-15 00:00:00
print(parse_flexible_date("March 15, 2026")) # 2026-03-15 00:00:00
print(parse_flexible_date("15/03/2026")) # 2026-03-15 00:00:00Aritmética de Datas com timedelta
A classe timedelta representa uma duração -- a diferença entre duas datas ou horas. Você pode adicionar ou subtrair objetos timedelta para mover datas para frente ou para trás.
from datetime import datetime, timedelta
now = datetime(2026, 2, 10, 12, 0, 0)
# Adicionar dias
tomorrow = now + timedelta(days=1)
print(tomorrow) # 2026-02-11 12:00:00
# Subtrair dias
last_week = now - timedelta(weeks=1)
print(last_week) # 2026-02-03 12:00:00
# Adicionar horas e minutos
later = now + timedelta(hours=5, minutes=30)
print(later) # 2026-02-10 17:30:00
# Combinar múltiplas unidades
future = now + timedelta(weeks=2, days=3, hours=6)
print(future) # 2026-02-27 18:00:00Calculando Diferenças de Tempo
Subtrair um datetime de outro retorna um timedelta.
from datetime import datetime
start = datetime(2026, 1, 1)
end = datetime(2026, 12, 31)
diff = end - start
print(diff) # 364 days, 0:00:00
print(diff.days) # 364
print(diff.total_seconds()) # 31449600.0Parâmetros do Construtor timedelta
| Parâmetro | Descrição | Exemplo |
|---|---|---|
weeks | Número de semanas | timedelta(weeks=2) = 14 dias |
days | Número de dias | timedelta(days=30) |
hours | Número de horas | timedelta(hours=12) |
minutes | Número de minutos | timedelta(minutes=45) |
seconds | Número de segundos | timedelta(seconds=120) |
milliseconds | Número de milissegundos | timedelta(milliseconds=500) |
microseconds | Número de microssegundos | timedelta(microseconds=1000) |
Todos os parâmetros podem ser combinados. Internamente, timedelta armazena apenas days, seconds e microseconds. Todo o resto é convertido.
from datetime import timedelta
delta = timedelta(weeks=1, days=2, hours=3, minutes=30, seconds=45)
print(delta) # 9 days, 3:30:45
print(delta.days) # 9
print(delta.seconds) # 12645 (3*3600 + 30*60 + 45)
print(delta.total_seconds()) # 790245.0Comparando Datas
Objetos datetime suportam todos os operadores de comparação padrão. Isso torna a ordenação e filtragem de datas simples.
from datetime import datetime
dt1 = datetime(2026, 1, 1)
dt2 = datetime(2026, 6, 15)
dt3 = datetime(2026, 12, 31)
print(dt1 < dt2) # True
print(dt3 > dt2) # True
print(dt1 == dt2) # False
print(dt1 != dt2) # TrueOrdenando Datas
from datetime import datetime
dates = [
datetime(2026, 12, 25),
datetime(2026, 1, 1),
datetime(2026, 7, 4),
datetime(2026, 2, 14),
]
sorted_dates = sorted(dates)
for d in sorted_dates:
print(d.strftime("%B %d, %Y"))
# January 01, 2026
# February 14, 2026
# July 04, 2026
# December 25, 2026Trabalhando com Timestamps
Timestamps Unix representam segundos desde 1 de janeiro de 1970 (a época Unix). O módulo datetime pode converter entre timestamps e objetos datetime.
from datetime import datetime, timezone
# Datetime para timestamp
dt = datetime(2026, 3, 15, 9, 30, 0)
ts = dt.timestamp()
print(ts) # 1773814200.0 (depende do fuso horário local)
# Timestamp para datetime (com fuso horário, recomendado)
dt_aware = datetime.fromtimestamp(ts, tz=timezone.utc)
print(dt_aware) # 2026-03-15 01:30:00+00:00Importante: datetime.fromtimestamp() sem fuso horário retorna a hora local. Para UTC, sempre passe tz=timezone.utc.
Tratamento de Fusos Horários
Datetimes ingênuos (sem informação de fuso horário) são uma fonte comum de bugs. Python fornece duas abordagens integradas para datetimes com fuso horário.
Usando datetime.timezone (Integrado)
A classe timezone lida com deslocamentos UTC fixos.
from datetime import datetime, timezone, timedelta
# UTC
utc_now = datetime.now(timezone.utc)
print(utc_now) # 2026-02-10 14:30:00+00:00
# Deslocamento fixo (ex: UTC+5:30 para Índia)
ist = timezone(timedelta(hours=5, minutes=30))
india_time = datetime.now(ist)
print(india_time) # 2026-02-10 20:00:00+05:30
# Converter entre fusos horários
utc_time = datetime(2026, 3, 15, 12, 0, 0, tzinfo=timezone.utc)
eastern = timezone(timedelta(hours=-5))
eastern_time = utc_time.astimezone(eastern)
print(eastern_time) # 2026-03-15 07:00:00-05:00Usando zoneinfo (Python 3.9+)
Para fusos horários nomeados com tratamento correto de horário de verão, use o módulo zoneinfo.
from datetime import datetime
from zoneinfo import ZoneInfo
# Fusos horários nomeados
utc = ZoneInfo("UTC")
eastern = ZoneInfo("America/New_York")
tokyo = ZoneInfo("Asia/Tokyo")
# Criar datetime com fuso horário
dt = datetime(2026, 7, 15, 12, 0, 0, tzinfo=utc)
print(dt) # 2026-07-15 12:00:00+00:00
# Converter para outros fusos horários
print(dt.astimezone(eastern)) # 2026-07-15 08:00:00-04:00 (EDT)
print(dt.astimezone(tokyo)) # 2026-07-15 21:00:00+09:00Datetimes Ingênuos vs Conscientes
| Característica | Ingênuo | Consciente |
|---|---|---|
| Tem informação de fuso horário | Não | Sim |
| Seguro para comparações entre zonas | Não | Sim |
Criado por datetime.now() | Sim | Não (a menos que tz seja passado) |
| Pode ser misturado em aritmética | Apenas com outros ingênuos | Apenas com outros conscientes |
| Recomendado para produção | Não | Sim |
Você não pode comparar ou subtrair um datetime ingênuo de um consciente. Python levanta um TypeError.
Exemplos Práticos
Calcular a Idade de uma Pessoa
from datetime import date
def calculate_age(birth_date):
"""Calculate age in years from a birth date."""
today = date.today()
age = today.year - birth_date.year
if (today.month, today.day) < (birth_date.month, birth_date.day):
age -= 1
return age
birthday = date(1995, 8, 20)
print(f"Age: {calculate_age(birthday)} years") # Age: 30 years (as of Feb 2026)Gerar um Intervalo de Datas
from datetime import date, timedelta
def date_range(start, end, step_days=1):
"""Generate dates from start to end (inclusive)."""
current = start
while current <= end:
yield current
current += timedelta(days=step_days)
start = date(2026, 2, 1)
end = date(2026, 2, 7)
for d in date_range(start, end):
print(d.strftime("%A, %B %d"))Contar Dias Úteis Entre Duas Datas
from datetime import date, timedelta
def business_days_between(start, end):
"""Count weekdays (Mon-Fri) between two dates, excluding endpoints."""
count = 0
current = start + timedelta(days=1)
while current < end:
if current.weekday() < 5: # 0=Mon, 4=Fri
count += 1
current += timedelta(days=1)
return count
start = date(2026, 2, 1)
end = date(2026, 2, 28)
print(f"Business days: {business_days_between(start, end)}") # Business days: 19Experimentando com Datetime no Jupyter
Operações de data e hora se beneficiam de experimentação interativa. Quando você está fazendo parsing de formatos de data inconsistentes de um CSV ou depurando conversões de fuso horário, poder testar cada passo em uma célula de notebook economiza tempo significativo.
RunCell (opens in a new tab) é um agente de IA que trabalha diretamente dentro de notebooks Jupyter. Ele pode inspecionar seus objetos datetime, sugerir os códigos de formato strftime/strptime corretos para seus dados e ajudar a depurar problemas de conversão de fuso horário em tempo real.
strftime vs strptime: Comparação Rápida
| strftime | strptime | |
|---|---|---|
| Nome completo | String Format Time | String Parse Time |
| Direção | datetime -> string | string -> datetime |
| Chamado em | Um objeto datetime | A classe datetime |
| Sintaxe | dt.strftime("%Y-%m-%d") | datetime.strptime(s, "%Y-%m-%d") |
| Retorna | Uma string formatada | Um objeto datetime |
| Levanta | Nunca | ValueError se o formato não corresponder |
| Caso de uso | Exibição, logging, nomes de arquivo | Parsing de CSV, respostas API, entrada do usuário |
from datetime import datetime
# strftime: datetime -> string
dt = datetime(2026, 3, 15, 9, 30)
formatted = dt.strftime("%B %d, %Y at %I:%M %p")
print(formatted) # March 15, 2026 at 09:30 AM
# strptime: string -> datetime
parsed = datetime.strptime("March 15, 2026 at 09:30 AM", "%B %d, %Y at %I:%M %p")
print(parsed) # 2026-03-15 09:30:00FAQ
Como obter a data e hora atuais em Python?
Use datetime.now() do módulo datetime. Para apenas a data, use date.today(). Para a hora atual com fuso horário, passe um fuso: datetime.now(tz=timezone.utc). Essas são as abordagens padrão e não requerem bibliotecas de terceiros.
Qual é a diferença entre strftime e strptime em Python?
strftime converte um objeto datetime em uma string formatada (string from time). strptime faz parsing de uma string e a converte em um objeto datetime (string parse time). Pense assim: strftime produz strings, strptime consome strings. Ambos usam os mesmos códigos de formato como %Y, %m, %d.
Como adicionar dias a uma data em Python?
Use a classe timedelta. Importe-a de datetime, depois adicione à sua data: new_date = old_date + timedelta(days=7). Você também pode usar weeks, hours, minutes e seconds como parâmetros. Subtrair funciona da mesma forma: past_date = today - timedelta(days=30).
Como converter uma string em datetime em Python?
Use datetime.strptime(string, format). Você precisa fornecer uma string de formato que corresponda à sua entrada. Por exemplo, datetime.strptime("2026-03-15", "%Y-%m-%d") faz parsing de uma data ISO. Se a string não corresponder ao formato, Python levanta um ValueError, então envolva a chamada em um bloco try/except para dados externos.
Como lidar com fusos horários em Python datetime?
Para Python 3.9+, use o módulo integrado zoneinfo: from zoneinfo import ZoneInfo. Crie datetimes com fuso horário com datetime.now(tz=ZoneInfo("UTC")) e converta entre zonas com dt.astimezone(ZoneInfo("America/New_York")). Para deslocamentos UTC fixos, use datetime.timezone(timedelta(hours=N)). Evite datetimes ingênuos em código de produção.
Conclusão
O módulo datetime do Python fornece tudo que você precisa para operações de data e hora: criar datas, formatá-las para exibição, fazer parsing de strings, realizar aritmética e lidar com fusos horários. Os padrões-chave são consistentes e previsíveis uma vez aprendidos.
Lembre-se da distinção central: strftime formata um datetime em uma string, strptime faz parsing de uma string em um datetime. Use timedelta para aritmética de datas. Use zoneinfo (Python 3.9+) para tratamento correto de fusos horários. Mantenha datetimes com fuso horário em código de produção para evitar bugs sutis de comparação.
Para a maioria dos projetos, o módulo integrado datetime é suficiente. Você não precisa de pytz em Python moderno -- zoneinfo lida com fusos horários nomeados nativamente. Comece com datetime.now(tz=timezone.utc) como ponto de referência e converta para fusos horários locais apenas ao exibir para usuários.