# Datas e tempo

calendar, time, datetime, dateutil, conversão pandas, fusos e agregação temporal.

Página: https://resumos.rgo.pt/cadeiras/ct-iadp/datas-tempos/

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.

```python
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))
```

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

```python
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())
```

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

%d lê o dia e %m o mês.

Mais uma pista

O segundo campo é 04.

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

Tratar a primeira componente como mês.

[Voltar à explicação](https://resumos.rgo.pt/cadeiras/ct-iadp/datas-tempos/#converter-datas-em-pandas)

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

Fevereiro de 2026 tem 28 dias.

Mais uma pista

Um mês não representa uma duração fixa de 30 dias.

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.

[Voltar à explicação](https://resumos.rgo.pt/cadeiras/ct-iadp/datas-tempos/#tipos-da-biblioteca-padr%C3%A3o)
