Datas e tempo
calendar, time, datetime, dateutil, conversão pandas, fusos e agregação temporal.
Uma data identifica um dia; uma data e hora pode identificar um instante; uma duração mede um intervalo. Misturar estes três conceitos produz erros, sobretudo ao somar meses ou atravessar mudanças de hora.
Tipos da biblioteca padrão
datetime.date guarda ano, mês e dia. datetime.datetime acrescenta a hora. datetime.timedelta guarda uma duração em dias, segundos e microssegundos. Subtrair duas datas produz uma duração; somar uma duração a uma data produz outra data.
import calendar
from datetime import date, timedelta
from dateutil.relativedelta import relativedelta
inicio = date(2026, 1, 31)
print(inicio + timedelta(days=30))
print(inicio + relativedelta(months=1))
print(calendar.isleap(2028))
print(calendar.monthrange(2026, 2))Dados de entrada
Trinta dias depois de 31 de janeiro de 2026 é 2 de março. Um mês depois, com relativedelta, é 28 de fevereiro. Fevereiro não tem dia 31, pelo que a operação ajusta para o último dia válido.
calendar.isleap testa um ano bissexto. calendar.monthrange devolve o dia da semana do primeiro dia e o número de dias do mês; segunda-feira é 0. Para fevereiro de 2026, o primeiro dia é domingo, código 6, e há 28 dias. Em versões recentes, o dia pode aparecer como calendar.SUNDAY, que tem valor 6.
Em relativedelta, months=1 acrescenta um mês; month=1 define o mês como janeiro. O plural e o singular exprimem operações diferentes.
Medir duração de código
time.time() dá um tempo baseado no relógio do sistema. Esse relógio pode ser ajustado. Para medir o tempo decorrido de uma operação, usa time.perf_counter() e subtrai o valor inicial ao final. O resultado depende da máquina e não é uma propriedade fixa do algoritmo.
time.sleep(1) pede uma pausa de um segundo, mas o sistema pode retomar mais tarde. Não o uses para provar que uma operação dura exatamente um segundo.
Converter datas em pandas
import pandas as pd
vendas = pd.DataFrame({
"data": ["01/10/2026", "01/10/2026", "03/10/2026", "inválida"],
"total": [3.0, 3.6, 7.5, 8.0],
})
vendas["data"] = pd.to_datetime(vendas["data"], format="%d/%m/%Y", errors="coerce")
print("datas inválidas:", vendas["data"].isna().sum())
conhecidas = vendas.dropna(subset=["data"]).set_index("data").sort_index()
print(conhecidas["total"].resample("D").sum(min_count=1).to_string())Dados de entrada
Há uma data inválida, convertida em NaT. Os dias conhecidos são 1 e 3 de outubro. O dia 1 soma 6,60 euros, o dia 2 fica sem valor conhecido e o dia 3 soma 7,50. min_count=1 evita chamar zero a um dia sem observações.
errors="coerce" permite inspecionar valores inválidos como ausentes; não os corrige. Com errors="raise", a conversão falha ao encontrá-los. Um formato explícito evita interpretar 03/04/2026 como março em vez de abril.
Aceder às partes e criar sequências
serie.dt.year, .dt.month, .dt.day e .dt.dayofweek extraem componentes. .dt.strftime("%d/%m/%Y") formata texto; depois disso, o resultado deixa de ser uma coluna temporal.
pd.date_range("2026-10-01", periods=3, freq="D") cria três dias consecutivos. Um índice temporal ordenado permite selecionar intervalos com loc. resample agrupa por intervalos de tempo; rolling(3) calcula uma janela móvel de três observações. Três observações não equivalem a três dias se houver falhas no calendário. rolling("3D") usa uma janela temporal quando existe um índice temporal apropriado.
Fusos horários
Uma hora sem fuso é naive e não identifica por si só um instante mundial. tz_localize("Europe/Lisbon") interpreta uma hora local nesse fuso. tz_convert("UTC") representa o mesmo instante noutro fuso e exige um valor já localizado.
Nas transições de hora, algumas horas locais são ambíguas ou não existem. Decide essa política na importação. Para registos de instantes com offsets conhecidos, pd.to_datetime(..., utc=True) normaliza-os para UTC. Conserva a distinção entre o instante e a apresentação na hora local.
Exercícios
Interpretar um formato explícito
A string 03/04/2026 é convertida com format=“%d/%m/%Y”. Qual é o número do mês?
Primeira pista
Mais uma pista
Ver solução
O mês é abril, número 4. Sem um formato explícito, a convenção da entrada podia ser interpretada de forma diferente.
Erros frequentes
Escolher calendário ou duração
Partindo de 31 de janeiro de 2026, compara somar 30 dias com somar um mês por relativedelta.
Primeira pista
Mais uma pista
Ver solução
timedelta(days=30) dá 2 de março. relativedelta(months=1) dá 28 de fevereiro, porque o mês seguinte não tem dia 31.
Confere a tua resposta:
- Obtive 2 de março para a soma de 30 dias.
- Obtive 28 de fevereiro para a soma de um mês.
- Expliquei o ajuste ao último dia válido do mês.
Erros frequentes
Substituir meses por 30 dias ou supor que a data inválida é conservada.