Dominar el tiempo con la biblioteca estándar de Python: datetime al máximo
Serie 03 – Operaciones de fecha y hora, zonas horarias y conversiones de formato todo en uno
El tiempo no es simplemente una "cadena de texto". Los días cambian, los meses transcurren, el horario de verano entra en juego y cada región tiene su propio estándar. Por eso, al trabajar con fechas y horas es crucial distinguir entre la representación textual y el valor numérico que se puede calcular, y también incluir la zona horaria al manejarlas.

En este artículo, nos centraremos en la explicación del módulo datetime y abordaremos:
- Crear la fecha y hora actuales
- Calcular periodos (
timedelta) - Formatear y analizar cadenas (
strftime,strptime) - Gestionar zonas horarias (
timezone,zoneinfo) - Puntos clave a considerar y patrones de uso recomendados
1. ¿Qué ofrece datetime?
El módulo datetime incluye varios tipos que, aunque parecidos, cumplen roles distintos.
date: cuando solo necesitas año‑mes‑díatime: cuando solo necesitas hora:minuto:segundodatetime: fecha + hora (el más usado)timedelta: la diferencia (periodo) entre dos instantestimezone: zona horaria con desplazamiento fijo (ej.: UTC+9)
A partir de Python 3.9, la biblioteca estándar incorpora zoneinfo, facilitando el manejo de zonas horarias locales (ej.: Asia/Tokyo).
2. Obtener el "ahora": desde naive hasta aware
2.1 ¿Qué son naive y aware?
Los objetos datetime se clasifican en dos grupos.
- naive datetime: sin información de zona horaria
- aware datetime: con información de zona horaria (
tzinfo)
Mezclar ambos en cálculos o comparaciones puede generar errores o resultados inesperados.
2.2 Configuración predeterminada recomendada: comenzar con UTC aware
Unificar la base de cálculo y almacenamiento en UTC suele simplificar considerablemente las cosas.
from datetime import datetime, timezone
utc_now = datetime.now(timezone.utc) # aware (UTC)
print(utc_now)
Si necesitas la hora local, conviértela en la fase de visualización.
from datetime import datetime, timezone
from zoneinfo import ZoneInfo
utc_now = datetime.now(timezone.utc)
tokyo_now = utc_now.astimezone(ZoneInfo("Asia/Tokyo"))
print(utc_now)
print(tokyo_now)
3. Cálculo de fechas y horas: el papel central de timedelta
3.1 Sumar y restar
from datetime import datetime, timedelta, timezone
now = datetime.now(timezone.utc)
print(now + timedelta(days=3))
print(now - timedelta(hours=2))
3.2 Diferencia entre dos instantes
from datetime import datetime, timezone
a = datetime(2026, 1, 1, tzinfo=timezone.utc)
b = datetime(2026, 1, 10, tzinfo=timezone.utc)
delta = b - a
print(delta.days) # 9
print(delta.total_seconds()) # 777600.0
3.3 Sensibilidad al usar timedelta para "periodos"
timedelta opera en días, segundos y microsegundos. Expresiones como "un mes después" se aproximan con timedelta(days=30), pero para el calendario real (el mismo día del mes siguiente) se requiere un enfoque diferente, normalmente con dateutil u otras librerías externas.
4. Formato y análisis: strftime / strptime
4.1 datetime → cadena (strftime)
from datetime import datetime, timezone
dt = datetime(2026, 1, 30, 14, 5, 0, tzinfo=timezone.utc)
print(dt.strftime("%Y-%m-%d %H:%M:%S %z"))
Patrones comunes:
%Y-%m-%d: 2026-01-30%H:%M:%S: 14:05:00%z: +0000 (desplazamiento UTC)
4.2 Cadena → datetime (strptime)
from datetime import datetime
s = "2026-01-30 14:05:00"
dt = datetime.strptime(s, "%Y-%m-%d %H:%M:%S")
print(dt)
El dt resultante es naive. Si quieres establecer la zona horaria, añade tzinfo.
from datetime import datetime, timezone
s = "2026-01-30 14:05:00"
dt = datetime.strptime(s, "%Y-%m-%d %H:%M:%S").replace(tzinfo=timezone.utc)
print(dt)
replace(tzinfo=...)no convierte el valor de tiempo, solo le asigna la zona horaria. Para convertir, usaastimezone()(ver siguiente sección).
5. Zonas horarias: diferenciar timezone y zoneinfo
5.1 Desplazamiento fijo → timezone
Ej.: UTC, UTC+9 con desplazamiento constante.
from datetime import datetime, timezone, timedelta
kst_fixed = timezone(timedelta(hours=9))
dt = datetime(2026, 1, 30, 12, 0, tzinfo=kst_fixed)
print(dt)
5.2 Zona horaria local → zoneinfo
Para zonas con horario de verano, zoneinfo es la opción adecuada.
from datetime import datetime, timezone
from zoneinfo import ZoneInfo
utc_now = datetime.now(timezone.utc)
ny_now = utc_now.astimezone(ZoneInfo("America/New_York"))
print(ny_now)
5.3 Diferencia entre replace(tzinfo=...) y astimezone(...)
replace(tzinfo=...): mantiene el valor de tiempo, solo cambia la etiqueta de zonaastimezone(...): convierte el mismo instante a la hora local de otra zona
Conocer esta distinción ayuda a evitar muchos errores relacionados con zonas horarias.
6. Aspectos clave a considerar
6.1 Mezcla de naive/aware
- Para cálculos internos, usar aware (UTC) es más seguro.
- Para entradas externas, normaliza la zona horaria al momento de su recepción.
6.2 "Hora local" varía según el entorno
datetime.now() sigue la configuración local del entorno de ejecución. En contenedores o servidores, la hora local puede ser UTC o no. Usar datetime.now(timezone.utc) evita ambigüedades.
6.3 Inconsistencias en el análisis de cadenas
strptime falla si el formato difiere en un solo carácter. Si se reciben múltiples formatos, es necesario pre‑procesar o probar secuencialmente. Lo ideal es restringir el formato de entrada.
7. Tres patrones comunes
7.1 Guardar en formato ISO 8601
Para una representación estándar, isoformat() es útil.
from datetime import datetime, timezone
dt = datetime.now(timezone.utc)
print(dt.isoformat()) # ej.: 2026-01-30T05:12:34.567890+00:00
7.2 Nombrar archivos con la fecha de hoy
from datetime import datetime
stamp = datetime.now().strftime("%Y%m%d")
filename = f"report_{stamp}.json"
print(filename)
7.3 Calcular tiempo restante hasta una fecha objetivo
from datetime import datetime, timezone
target = datetime(2026, 2, 1, 0, 0, tzinfo=timezone.utc)
now = datetime.now(timezone.utc)
remaining = target - now
print(remaining)
print(remaining.total_seconds())
8. Conclusión
datetime va más allá de crear cadenas de texto con fechas; convierte el tiempo en un valor que se puede manipular aritméticamente. Incluir zonas horarias (timezone, zoneinfo) garantiza que el código sea estable, independientemente del entorno de ejecución.
En la próxima entrega, abordaremos el módulo random por separado, abarcando la generación de números aleatorios, el muestreo, la mezcla, las semillas y la generación segura con secrets.
Enlaces relacionados:
- Usar correctamente datetime y timezone en Django
- La magia de la gestión del tiempo en Django - Guía completa de 'django.utils.timezone'
Consulta las entregas anteriores
No hay comentarios.