A manipulação de datas e horas é uma das tarefas mais comuns no desenvolvimento de software. Seja para registrar eventos, calcular intervalos de tempo, formatar saídas para usuários ou lidar com fusos horários, o módulo datetime do Python é a ferramenta essencial que todo desenvolvedor precisa dominar.

Neste guia completo, você aprenderá desde os conceitos básicos até técnicas avançadas de manipulação de temporal data em Python, com exemplos práticos que você pode aplicar imediatamente em seus projetos.

📦 Introdução ao Módulo datetime

O Python possui o módulo datetime integrado à sua biblioteca padrão, o que significa que você não precisa instalar nada extra para começar a usá-lo. Este módulo fornece classes para trabalhar com datas, horas e combinações de ambos.

Segundo a documentação oficial do Python, o módulo datetime oferece várias classes fundamentais que tornam a manipulação de dados temporais simples e intuitiva.

import datetime

# Verificar versão do módulo
print(datetime.__version__)

🕐 As Principais Classes do datetime

1. datetime.date — Apenas a Data

A classe date representa uma data no formato ano-mês-dia, sem informação de horário. É ideal quando você precisa trabalhar apenas com calendários, anniversários, prazos, etc.

import datetime

# Criar uma data específica
data_nascimento = datetime.date(1995, 3, 15)
print(data_nascimento)  # 1995-03-15

# Obter a data de hoje
hoje = datetime.date.today()
print(f"Hoje é {hoje}")  # Hoje é 2026-05-13

# Acessar componentes individuais
print(f"Ano: {hoje.year}")        # 2026
print(f"Mês: {hoje.month}")       # 5
print(f"Dia: {hoje.day}")         # 13
print(f"Dia da semana: {hoje.weekday()}")  # 0 (segunda-feira)

# Dia da semana com nome
dias = ["Segunda", "Terça", "Quarta", "Quinta", "Sexta", "Sábado", "Domingo"]
print(f"Hoje é {dias[hoje.weekday()]}")

# Criar data a partir de timestamp Unix
data_timestamp = datetime.date.fromtimestamp(1700000000)
print(data_timestamp)

2. datetime.time — Apenas o Horário

A classe time representa um horário específico, sem informação de data. Útil para agendamentos, lembretes e controle de ponto.

import datetime

# Criar um horário específico
hora_reuniao = datetime.time(14, 30, 0)  # 14h30min
print(hora_reuniao)  # 14:30:00

# Com microsegundos
hora_exata = datetime.time(14, 30, 45, 123456)
print(hora_exata)  # 14:30:45.123456

# Acessar componentes
print(f"Hora: {hora_reuniao.hour}")        # 14
print(f"Minutos: {hora_reuniao.minute}")   # 30
print(f"Segundos: {hora_reuniao.second}")  # 0

# Formatar horário
print(hora_reuniao.strftime("%H:%M"))      # 14:30
print(hora_reuniao.strftime("%I:%M %p"))  # 02:30 PM

3. datetime.datetime — Data e Hora Combinados

A classe datetime é a mais usada e completa, combinando data e hora em um único objeto. É perfect para timestamps, logs, registros de eventos e muito mais.

import datetime

# Criar datetime específico
agora = datetime.datetime.now()
print(f"Agora: {agora}")

# Criar datetime específico
evento = datetime.datetime(2026, 12, 25, 18, 0, 0)
print(f"Christmas: {evento}")

# datetime atual com timezone
utc_atual = datetime.datetime.utcnow()
print(f"UTC agora: {utc_atual}")

# Criar a partir de string
data_str = "2026-05-13 15:30:00"
data_parsed = datetime.datetime.strptime(data_str, "%Y-%m-%d %H:%M:%S")
print(f"Parseado: {data_parsed}")

# Acessar todos os componentes
print(f"Data: {agora.date()}")
print(f"Hora: {agora.time()}")
print(f"Ano: {agora.year}, Mês: {agora.month}, Dia: {agora.day}")
print(f"Hora: {agora.hour}, Minuto: {agora.minute}, Segundo: {agora.second}")

4. datetime.timedelta — Diferenças de Tempo

A classe timedelta representa a diferença entre duas datas ou horas. É essencial para calcular durações, intervalos e fazer operações aritméticas com datas.

import datetime

# Criar timedelta
um_dia = datetime.timedelta(days=1)
duas_horas = datetime.timedelta(hours=2)
meia_hora = datetime.timedelta(minutes=30)

# Operações com datetime
hoje = datetime.datetime.now()
amanha = hoje + um_dia
print(f"Amanhã: {amanha}")

semana_passada = hoje - datetime.timedelta(weeks=1)
print(f"Semana passada: {semana_passada}")

# Calcular diferença entre datas
inicio = datetime.datetime(2026, 1, 1)
fim = datetime.datetime(2026, 5, 13)
diff = fim - inicio
print(f"Diferença: {diff}")
print(f"Dias: {diff.days}")
print(f"Segundos: {diff.seconds}")

# timedelta total em horas
total_horas = diff.total_seconds() / 3600
print(f"Total de horas: {total_horas:.2f}")

📝 Formatação de Datas e Horas

A formatação de datas é crucial para exibir informações aos usuários de manera clara e compreensível. O Python oferece duas funções principais para isso: strftime() para formatar datetime em string e strptime() para converter string em datetime.

Códigos de Formato Mais Usados

import datetime

agora = datetime.datetime.now()

# Formatos comuns
print(agora.strftime("%d/%m/%Y"))           # 13/05/2026
print(agora.strftime("%d-%m-%Y"))           # 13-05-2026
print(agora.strftime("%d de %B de %Y"))     # 13 de maio de 2026
print(agora.strftime("%H:%M:%S"))           # 14:30:45
print(agora.strftime("%H:%M"))              # 14:30
print(agora.strftime("%d/%m/%Y às %H:%M"))  # 13/05/2026 às 14:30

# Formatos internacionais
print(agora.strftime("%Y-%m-%d"))           # 2026-05-13 (ISO 8601)
print(agora.strftime("%B %d, %Y"))          # May 13, 2026

# Dia da semana
print(agora.strftime("%A"))                 # quarta-feira
print(agora.strftime("%a"))                 # qua
print(agora.strftime("%A, %d de %B de %Y")) # quarta-feira, 13 de maio de 2026

# Mês
print(agora.strftime("%B"))                 # maio
print(agora.strftime("%b")                 # mai
print(agora.strftime("%m"))                # 05

# Hora em formato 12h
print(agora.strftime("%I:%M %p"))           # 02:30 PM

Para uma referência completa de todos os códigos de formatação, a W3Schools oferece um guia útil e didático sobre datetime em Python.

🔄 Conversão de String para datetime

Uma das tarefas mais frequentes em programação é converter strings em formato variados para objetos datetime. O strptime() (string parse time) faz exatamente isso.

import datetime

#various formatos de entrada
formatos = [
    ("2026-05-13", "%Y-%m-%d"),
    ("13/05/2026", "%d/%m/%Y"),
    ("13-05-2026", "%d-%m-%Y"),
    ("May 13, 2026", "%B %d, %Y"),
    ("13 May 2026", "%d %B %Y"),
    ("2026-05-13 14:30:00", "%Y-%m-%d %H:%M:%S"),
    ("13/05/2026 14:30", "%d/%m/%Y %H:%M"),
]

for data_str, formato in formatos:
    try:
        dt = datetime.datetime.strptime(data_str, formato)
        print(f"'{data_str}' -> {dt}")
    except ValueError as e:
        print(f"Erro ao converter '{data_str}': {e}")

# Função para detectar formato automaticamente
def converter_data(data_str):
    formatos = [
        "%Y-%m-%d",
        "%d/%m/%Y",
        "%d-%m-%Y",
        "%Y/%m/%d",
        "%B %d, %Y",
        "%d %B %Y",
    ]
    for fmt in formatos:
        try:
            return datetime.datetime.strptime(data_str, fmt)
        except ValueError:
            continue
    raise ValueError(f"Não foi possível converter: {data_str}")

print(converter_data("13/05/2026"))

🌍 Trabalhando com Fusos Horários

Lidar com fusos horários é um dos aspectos mais complexos da manipulação de datas. O Python usa a biblioteca pytz para gerenciar fusos horários de forma eficiente.

import datetime
import pytz

# Criar datetime com timezone
tz_brasil = pytz.timezone('America/Sao_Paulo')
tz_eua = pytz.timezone('America/New_York')
tz_japao = pytz.timezone('Asia/Tokyo')

# Datetime atual em diferentes fusos
agora_brasil = datetime.datetime.now(tz_brasil)
agora_eua = datetime.datetime.now(tz_eua)
agora_japao = datetime.datetime.now(tz_japao)

print(f"Brasil: {agora_brasil}")
print(f"EUA: {agora_eua}")
print(fJapão: {agora_japao}")

# Criar datetime em timezone específico
data_especifica = datetime.datetime(2026, 12, 25, 18, 0, 0, tzinfo=tz_brasil)
print(f"Natal no Brasil: {data_especifica}")

# Converter entre fusos horários
natal_brasil = datetime.datetime(2026, 12, 25, 18, 0, 0, tzinfo=tz_brasil)
natal_eua = natal_brasil.astimezone(tz_eua)
natal_japao = natal_brasil.astimezone(tz_japao)

print(f"Natal 18h no Brasil = {natal_eua.strftime('%H:%M')} nos EUA")
print(f"Natal 18h no Brasil = {natal_japao.strftime('%H:%M')} no Japão")

# Obter timezone de uma string ISO 8601
data_iso = "2026-05-13T14:30:00-03:00"
dt_iso = datetime.datetime.fromisoformat(data_iso)
print(f"De ISO: {dt_iso}")

# Lista de fusos disponíveis
print("Alguns fusos horários disponíveis:")
for tz in ['America/Sao_Paulo', 'America/New_York', 'Europe/London', 'Asia/Tokyo', 'Australia/Sydney']:
    print(f"  - {tz}")

A documentação do Real Python oferece um guia detalhado sobre como trabalhar com fusos horários de manera correta.

📊 Operações Aritméticas com Datas

Uma das grandes vantagens do módulo datetime é a capacidade de realizar operações aritméticas diretamente entre datas e intervalos de tempo.

import datetime

# Adição e subtração
data = datetime.datetime(2026, 5, 13)

# Adicionar dias
mais_10_dias = data + datetime.timedelta(days=10)
print(f"10 dias depois: {mais_10_dias}")

# Subtrair semanas
menos_2_semanas = data - datetime.timedelta(weeks=2)
print(f"2 semanas antes: {menos_2_semanas}")

# Adicionar meses (precisa de biblioteca adicional ou lógica personalizada)
def adicionar_meses(data, meses):
    mes = data.month + meses
    ano = data.year + (mes - 1) // 12
    mes = ((mes - 1) % 12) + 1
    dia = min(data.day, [31, 29 if ano % 4 == 0 and (ano % 100 != 0 or ano % 400 == 0) else 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][mes-1])
    return data.replace(year=ano, month=mes, day=dia)

resultado = adicionar_meses(data, 6)
print(f"6 meses depois: {resultado}")

# Calcular idade
def calcular_idade(data_nascimento):
    hoje = datetime.date.today()
    idade = hoje.year - data_nascimento.year
    if (hoje.month, hoje.day) < (data_nascimento.month, data_nascimento.day):
        idade -= 1
    return idade

nasc = datetime.date(1995, 3, 15)
print(f"Idade: {calcular_idade(nasc)} anos")

# Verificar se é dia útil
def eh_dia_util(data):
    return data.weekday() < 5  # 0-4 = seg a sex

print(f"13/05/2026 é dia útil? {eh_dia_util(data)}")

🗓️ Gerando Sequências de Datas

Para muitas aplicações, você precisa gerar sequências de datas, como por exemplo, criar uma agenda, gerar relatórios por período ou iterar sobre dias úteis.

import datetime

# Gerar sequência de dias
inicio = datetime.date(2026, 5, 1)
fim = datetime.date(2026, 5, 15)

dias = []
data = inicio
while data <= fim:
    dias.append(data)
    data += datetime.timedelta(days=1)

print("Dias de maio (1-15):")
for d in dias:
    print(f"  {d.strftime('%d/%m')}")

# Usando list comprehension
dias_maio = [inicio + datetime.timedelta(days=i) for i in range(15)]
print(f"Total de dias: {len(dias_maio)}")

# Gerar meses entre datas
def meses_entre(inicio, fim):
    resultado = []
    atual = inicio
    while atual < fim:
        resultado.append(atual)
        if atual.month == 12:
            atual = atual.replace(year=atual.year + 1, month=1)
        else:
            atual = atual.replace(month=atual.month + 1)
    return resultado

meses = meses_entre(datetime.date(2026, 1, 1), datetime.date(2026, 12, 31))
print("Meses de 2026:")
for m in meses:
    print(f"  {m.strftime('%B')}")

# Dias úteis entre datas
def dias_uteis(inicio, fim):
    dias = []
    data = inicio
    while data <= fim:
        if data.weekday() < 5:
            dias.append(data)
        data += datetime.timedelta(days=1)
    return dias

uteis = dias_uteis(datetime.date(2026, 5, 1), datetime.date(2026, 5, 31))
print(f"Dias úteis em maio: {len(uteis)}")

# Gerar horários para um dia específico
def horarios_dia(data, inicio_hora=9, fim_hora=18, intervalo=30):
    horarios = []
    for h in range(inicio_hora, fim_hora):
        for m in [0, intervalo]:
            if h == fim_hora - 1 and m > 0:
                break
            horarios.append(data.replace(hour=h, minute=m))
    return horarios

agenda = horarios_dia(datetime.datetime(2026, 5, 13))
print("Horários disponíveis para 13/05:")
for h in agenda[:6]:
    print(f"  {h.strftime('%H:%M')}")

🔍 Comparação de Datas

Comparar datas é essencial para validações, ordenações e verificações de período. O datetime permite várias formas de comparação.

import datetime

# Datas de exemplo
d1 = datetime.datetime(2026, 5, 13)
d2 = datetime.datetime(2026, 6, 15)
d3 = datetime.datetime(2026, 5, 13, 14, 30)

# Comparações diretas
print(f"d1 == d2: {d1 == d2}")  # False
print(f"d1 != d2: {d1 != d2}")  # True
print(f"d1 < d2: {d1 < d2}")    # True
print(f"d1 <= d2: {d1 <= d2}")  # True
print(f"d1 > d2: {d1 > d2}")    # False

# Comparar apenas datas (ignorando hora)
print(f"d1.date() == d3.date(): {d1.date() == d3.date()}")  # True

# Verificar se está no passado, presente ou futuro
agora = datetime.datetime.now()
if agora < d1:
    print("d1 está no futuro")
elif agora > d1:
    print("d1 está no passado")
else:
    print("d1 é agora")

# Verificar se está em um intervalo
inicio = datetime.datetime(2026, 1, 1)
fim = datetime.datetime(2026, 12, 31)
print(f"d1 está entre {inicio.date()} e {fim.date()}? {inicio <= d1 <= fim}")

# Ordenar lista de datas
datas = [
    datetime.datetime(2026, 3, 15),
    datetime.datetime(2026, 1, 10),
    datetime.datetime(2026, 12, 25),
    datetime.datetime(2026, 7, 4),
]
datas.sort()
print("Datas ordenadas:")
for d in datas:
    print(f"  {d.strftime('%d/%m/%Y')}")

⏰ Medindo Tempo de Execução

O datetime é frequentemente usado para medir o tempo de execução de código, o que é fundamental para otimização de performance.

import datetime
import time

# Método 1: Usando datetime
inicio = datetime.datetime.now()
time.sleep(1)  # Simulando processamento
fim = datetime.datetime.now()
duracao = fim - inicio
print(f"Duração: {duracao.total_seconds():.2f} segundos")

# Método 2: Usando time.time()
inicio_ts = time.time()
time.sleep(0.5)
fim_ts = time.time()
print(f"Duração (time): {fim_ts - inicio_ts:.2f} segundos")

# Método 3: Usando context manager
class Cronometro:
    def __init__(self):
        self.inicio = None
        self.fim = None

    def __enter__(self):
        self.inicio = datetime.datetime.now()
        return self

    def __exit__(self, *args):
        self.fim = datetime.datetime.now()
        self.duracao = self.fim - self.inicio

    def tempo_total(self):
        return self.duracao.total_seconds()

with Cronometro() as cron:
    time.sleep(0.3)
    print(f"Tempo medido: {cron.tempo_total():.3f} segundos")

# Medir múltiplas execuções
def medir_funcao(func, vezes=100):
    resultados = []
    for _ in range(vezes):
        inicio = datetime.datetime.now()
        func()
        fim = datetime.datetime.now()
        resultados.append((fim - inicio).total_seconds())

    media = sum(resultados) / len(resultados)
    return {
        'media': media,
        'min': min(resultados),
        'max': max(resultados),
        'vezes': vezes
    }

def funcao_teste():
    soma = 0
    for i in range(1000):
        soma += i

resultado = medir_funcao(funcao_teste, vezes=50)
print(f"Média: {resultado['media']*1000:.2f}ms")
print(f"Mín: {resultado['min']*1000:.2f}ms, Máx: {resultado['max']*1000:.2f}ms")

🛠️ Casos de Uso Práticos

1. Calcular dias até uma data futura

import datetime

def dias_ate(alvo):
    hoje = datetime.date.today()
    if isinstance(alvo, datetime.datetime):
        alvo = alvo.date()
    diff = alvo - hoje
    return diff.days

# Aniversário
aniversario = datetime.date(2026, 12, 25)
print(f"Dias até o Natal: {dias_ate(aniversario)}")

# Feriado
feriado = datetime.date(2027, 1, 1)
print(f"Dias até o Ano Novo: {dias_ate(feriado)}")

2. Verificar se um ano é bissexto

import datetime

def eh_bissexto(ano):
    return (ano % 4 == 0 and ano % 100 != 0) or (ano % 400 == 0)

# Mês de fevereiro em diferentes anos
for ano in [2024, 2025, 2026, 2028]:
    print(f"{ano}: {'Bissexto' if eh_bissexto(ano) else 'Normal'}")

# Usando dateutil
from datetime import date
import calendar
print(f"Fevereiro 2024 tem {calendar.monthrange(2024, 2)[1]} dias")

3. Gerar nome de arquivo com timestamp

import datetime

def gerar_nome_arquivo(prefixo, extensao):
    agora = datetime.datetime.now()
    timestamp = agora.strftime("%Y%m%d_%H%M%S")
    return f"{prefixo}_{timestamp}.{extensao}"

print(gerar_nome_arquivo("backup", "zip"))
print(gerar_nome_arquivo("relatorio", "pdf"))
print(gerar_nome_arquivo("log", "txt"))

4. Calcular duração de um evento

import datetime

eventos = [
    ("Reunião", datetime.datetime(2026, 5, 13, 14, 0), datetime.datetime(2026, 5, 13, 15, 30)),
    ("Workshop", datetime.datetime(2026, 5, 13, 9, 0), datetime.datetime(2026, 5, 13, 12, 0)),
    ("Palestra", datetime.datetime(2026, 5, 13, 16, 0), datetime.datetime(2026, 5, 13, 17, 45)),
]

for nome, inicio, fim in eventos:
    duracao = fim - inicio
    print(f"{nome}: {duracao} ({duracao.total_seconds()/3600:.2f}h)")

5. Validar data de expiration

import datetime

def esta_expirado(data_expiracao):
    return datetime.datetime.now() > data_expiracao

# Simular certidicado SSL
certificado_expira = datetime.datetime(2026, 12, 31, 23, 59, 59)
print(f"Certificado expirado? {esta_expirado(certificado_expira)}")

# Verificar dias restantes
def dias_para_expirar(data_expiracao):
    agora = datetime.datetime.now()
    if isinstance(data_expiracao, datetime.datetime):
        data_expiracao = data_expiracao.replace(tzinfo=None) - agora
    else:
        data_expiracao = data_expiracao - agora.date()
    return data_expiracao.days

print(f"Dias até expirar: {dias_para_expirar(certificado_expira)}")

📚 Bibliotecas Complementares

Embora o módulo datetime seja extremamente poderoso, existem bibliotecas que podem facilitar ainda mais o trabalho com datas em Python.

dateutil - Extensões úteis

# dateutil fornece funcionalidades avançadas
from dateutil import parser
from dateutil.relativedelta import relativedelta
from dateutil.rrule import rrule, MONTHLY

# Parse automático de strings
data = parser.parse("amanhã")
print(f"Parseado: {data}")

data = parser.parse("15 de maio de 2026")
print(f"Parseado: {data}")

# Adicionar meses relativedelta
from datetime import datetime
agora = datetime.now()
mais_3_meses = agora + relativedelta(months=3)
print(f"3 meses depois: {mais_3_meses}")

# Gerar ocorrências mensais
from dateutil.rrule import rrule, MONTHLY
inicio = datetime(2026, 1, 1)
fim = datetime(2026, 12, 31)
ocorrencias = list(rrule(MONTHLY, dtstart=inicio, until=fim))
print(f"Meses de 2026: {len(ocorrencias)}")

pandas - Para séries temporais

Para análise de dados e séries temporais, o pandas é a biblioteca mais recomendada. Ela oferece funcionalidades avançadas para manipulação de datas em contextos de análise de dados.

import pandas as pd

# Criar DataFrame com datas
datas = pd.date_range(start='2026-01-01', end='2026-12-31', freq='D')
df = pd.DataFrame({'data': datas, 'valor': range(len(datas))})

# Operações de tempo
df['ano'] = df['data'].dt.year
df['mes'] = df['data'].dt.month
df['dia_semana'] = df['data'].dt.day_name()
df['trimestre'] = df['data'].dt.quarter

print(df.head())

# Resample - agregar por período
df['valor'] = range(1, len(datas) + 1)
mensal = df.set_index('data')['valor'].resample('M').sum()
print(f"\nTotal por mês:\n{mensal}")

⚠️ Armadilhas Comuns e Como Evitá-las

1. Mutabilidade de datetime

import datetime

# CUIDADO: datetime é mutável!
dt = datetime.datetime(2026, 5, 13)
dt_modificado = dt.replace(month=12)  # Cria novo objeto
print(f"Original: {dt}")
print(f"Modificado: {dt_modificado}")

# Para alterar, você precisa atribuir
dt = dt.replace(month=12)
print(f"Alterado: {dt}")

2. Fusos horários e localization

import datetime
import pytz

# Sempre especifique timezone
tz = pytz.timezone('America/Sao_Paulo')
dt = datetime.datetime(2026, 5, 13, 12, 0, tzinfo=tz)
print(f"Com timezone: {dt}")

# CUIDADO: localize, não apenas atribua
dt_nao_localizado = datetime.datetime(2026, 5, 13, 12, 0)
dt_localizado = tz.localize(dt_nao_localizado)
print(f"Localizado: {dt_localizado}")

# Usar timezone ao criar fromisoformat (Python 3.11+)
dt_iso = datetime.datetime.fromisoformat("2026-05-13T12:00:00-03:00")
print(f"From ISO: {dt_iso}")

3. Datas fora do intervalo válido

import datetime

# CUIDADO: datas inválidas podem raising erro ou gerar resultados inesperados
try:
    dt = datetime.datetime(2026, 2, 30)  # Fevereiro não tem 30 dias
except ValueError as e:
    print(f"Erro: {e}")

# Sempre valide datas
def data_valida(ano, mes, dia):
    try:
        datetime.date(ano, mes, dia)
        return True
    except ValueError:
        return False

print(f"2026-02-30 válida? {data_valida(2026, 2, 30)}")
print(f"2026-02-28 válida? {data_valida(2026, 2, 28)}")
print(f"2024-02-29 válida? {data_valida(2024, 2, 29)}")  # Ano bissexto

🚀 Próximos Passos

Agora que você domina o módulo datetime do Python, você está preparado para lidar com a maioria das situações envolvendo datas e horas em suas aplicações. Para aprofundar ainda mais seu conhecimento, recomendamos:

O domínio de datetime é fundamental para qualquer desenvolvedor Python. Continue praticando e explorando as possibilidades deste módulo poderoso! 🎯