💻 Exemplos: Capítulo 07: Manipulação de Datas, Horas, Timedeltas e Fusos Horários (zoneinfo)
Especialização em Sistemas com Python 3.12+ • Capítulo 07
🎯 Demonstração Prática: Motor de SLA Global e Horário Comercial com ZoneInfo
O exemplo abaixo demonstra o tratamento corporativo de tempo em arquiteturas distribuídas:
- Captura e tráfego em UTC padrão ISO 8601 com
datetime.now(timezone.utc). - Conversão dinâmica para múltiplos fusos horários globais com o módulo nativo
zoneinfo.ZoneInfo(PEP 615). - Algoritmo de cálculo de expiração de SLA pulando finais de semana (sábado e domingo).
- Formatação regionalizada de datas para dashboards executivos.
"""
demonstracao_datas_e_zoneinfo.py
Motor de SLA Empresarial com ZoneInfo, Timedeltas e Conversão Global de Fusos.
Compatível com Python 3.12+ (PEP 615).
"""
from __future__ import annotations
from dataclasses import dataclass
from datetime import datetime, timedelta, timezone
from zoneinfo import ZoneInfo
from typing import Final
# ==============================================================================
# 1. CONSTANTES E FUSOS HORÁRIOS IANA
# ==============================================================================
FUSO_SP: Final[ZoneInfo] = ZoneInfo("America/Sao_Paulo")
FUSO_NY: Final[ZoneInfo] = ZoneInfo("America/New_York")
FUSO_LONDRES: Final[ZoneInfo] = ZoneInfo("Europe/London")
FUSO_TOQUIO: Final[ZoneInfo] = ZoneInfo("Asia/Tokyo")
@dataclass(slots=True)
class ChamadoSuporte:
id_ticket: str
cliente: str
abertura_utc: datetime
horas_sla_util: int
vencimento_utc: datetime | None = None
# ==============================================================================
# 2. MOTOR DE CÁLCULO DE PRAZO DE SLA ÚTIL (DIAS DE SEMANA)
# ==============================================================================
def calcular_vencimento_sla_util(data_inicio_utc: datetime, horas_uteis: int) -> datetime:
"""
Acrescenta horas de SLA considerando apenas dias úteis (segunda a sexta).
Avança sobre sábados e domingos sem consumir a franquia de horas.
"""
if data_inicio_utc.tzinfo is None:
raise ValueError("A data deve ser Timezone-Aware (obrigatoriamente UTC).")
cursor: datetime = data_inicio_utc
horas_restantes: int = horas_uteis
while horas_restantes > 0:
cursor += timedelta(hours=1)
# weekday(): 0=Segunda, 4=Sexta, 5=Sábado, 6=Domingo
if cursor.weekday() < 5:
horas_restantes -= 1
return cursor
# ==============================================================================
# 3. CONVERSÃO E FORMATAÇÃO MULTIFUSO
# ==============================================================================
def gerar_painel_internacional(instante_utc: datetime) -> dict[str, str]:
"""Renderiza o mesmo instante temporal ajustado aos fusos das sedes globais."""
return {
"UTC (Referência Global)" : instante_utc.strftime("%Y-%m-%dT%H:%M:%SZ"),
"São Paulo (BRT)" : instante_utc.astimezone(FUSO_SP).strftime("%d/%m/%Y %H:%M:%S (%Z)"),
"Nova York (EDT/EST)" : instante_utc.astimezone(FUSO_NY).strftime("%m/%d/%Y %I:%M:%S %p (%Z)"),
"Londres (BST/GMT)" : instante_utc.astimezone(FUSO_LONDRES).strftime("%d/%m/%Y %H:%M:%S (%Z)"),
"Tóquio (JST)" : instante_utc.astimezone(FUSO_TOQUIO).strftime("%Y年%m月%d日 %H:%M:%S (%Z)"),
}
# ==============================================================================
# 4. EXECUÇÃO PRINCIPAL
# ==============================================================================
if __name__ == "__main__":
# Simulação de um ticket aberto na sexta-feira às 18:00 UTC com SLA de 16 horas úteis
ticket_sexta = ChamadoSuporte(
id_ticket="INC-2026-8801",
cliente="Banco Internacional de Investimentos",
abertura_utc=datetime(2026, 9, 25, 18, 0, 0, tzinfo=timezone.utc), # 25/09/2026 é sexta-feira
horas_sla_util=16
)
ticket_sexta.vencimento_utc = calcular_vencimento_sla_util(
ticket_sexta.abertura_utc,
ticket_sexta.horas_sla_util
)
print("=" * 80)
print(" SISTEMA DE GESTÃO DE SLA CORPORATIVO GLOBAL (ZONEINFO)")
print("=" * 80)
print(f"Ticket de Suporte : {ticket_sexta.id_ticket}")
print(f"Cliente Corporativo: {ticket_sexta.cliente}")
print(f"Franquia SLA : {ticket_sexta.horas_sla_util} horas úteis (Segunda a Sexta)")
print("-" * 80)
print(">> MOMENTO DA ABERTURA DO CHAMADO:")
for fuso_nome, data_formatada in gerar_painel_internacional(ticket_sexta.abertura_utc).items():
print(f" * {fuso_nome:<24} : {data_formatada}")
print("\n" + "-" * 80)
print(">> PRAZO FATAL DE VENCIMENTO DO SLA (PULOU O FIM DE SEMANA):")
for fuso_nome, data_formatada in gerar_painel_internacional(ticket_sexta.vencimento_utc).items():
print(f" * {fuso_nome:<24} : {data_formatada}")
# Cálculo da duração total decorrida (incluindo as 48h do fim de semana)
delta_total: timedelta = ticket_sexta.vencimento_utc - ticket_sexta.abertura_utc
print("-" * 80)
print(f"Tempo Corrido Total (com fim de semana) : {delta_total.total_seconds() / 3600:.1f} horas físicas")
print(f"Tempo Útil Efetivamente Contabilizado : {ticket_sexta.horas_sla_util}.0 horas comerciais")
print("=" * 80)