Las fechas y horas aparecen en informes, recordatorios, suscripciones, registros, citas, nombres de archivos y respuestas de APIs. Parecen sencillas hasta que entran en juego las zonas horarias, el horario de verano, los formatos y la aritmética de calendario. Los módulos estándar datetime y zoneinfo proporcionan las herramientas principales.
En esta guía de datetime en Python aprenderás a crear, analizar, formatear y comparar fechas; calcular duraciones; trabajar con UTC y convertir valores entre zonas horarias.
Tipos principales
El módulo contiene varias clases relacionadas:
date: una fecha de calendario.time: una hora del día.datetime: fecha y hora combinadas.timedelta: una duración.
from datetime import date, datetime, time, timedelta
hoy = date.today()
hora_reunion = time(14, 30)
reunion = datetime(2026, 7, 11, 14, 30)
duracion = timedelta(hours=1, minutes=15)
print(hoy)
print(hora_reunion)
print(reunion + duracion)Obtener la fecha y hora actuales
Para un instante que será intercambiado entre sistemas, utiliza un objeto con zona horaria.
from datetime import datetime, timezone
hora_utc = datetime.now(timezone.utc)
print(hora_utc)Un datetime.now() sin zona es ingenuo: no identifica un instante universal. Puede ser suficiente en un script estrictamente local, pero es arriesgado en aplicaciones distribuidas.
Crear objetos manualmente
from datetime import date, datetime
fecha_lanzamiento = date(2026, 9, 15)
fecha_limite = datetime(2026, 9, 15, 17, 0)
print(fecha_lanzamiento.year)
print(fecha_limite.hour)Los constructores validan el calendario. Una fecha imposible genera ValueError. La guía de try y except en Python explica cómo responder a entradas inválidas.
Formatear fechas para personas
from datetime import datetime
momento = datetime(2026, 7, 11, 16, 45)
print(momento.strftime("%Y-%m-%d"))
print(momento.strftime("%d/%m/%Y a las %H:%M"))El formato es una capa de presentación. Mantén objetos estructurados durante los cálculos y conviértelos a texto al mostrar o exportar.
Analizar strings con strptime()
from datetime import datetime
texto = "11/07/2026 16:45"
momento = datetime.strptime(texto, "%d/%m/%Y %H:%M")
print(momento)El patrón debe coincidir exactamente con la entrada. Para comprender mejor limpieza y manipulación textual, revisa la guía de strings en Python.
Utilizar ISO 8601
from datetime import datetime
momento = datetime.fromisoformat(
"2026-07-11T16:45:00+00:00"
)
print(momento)ISO 8601 es una buena opción para intercambiar datos porque es legible y ampliamente compatible. En archivos tabulares, documenta siempre el formato de cada columna; la guía de CSV en Python muestra un flujo completo.
Aritmética con timedelta
from datetime import date, timedelta
hoy = date.today()
proxima_semana = hoy + timedelta(weeks=1)
ayer = hoy - timedelta(days=1)
print(proxima_semana)
print(ayer)Restar dos fechas devuelve una duración.
from datetime import date
inicio = date(2026, 7, 11)
fin = date(2026, 8, 1)
diferencia = fin - inicio
print(diferencia.days)Un mes no equivale a una duración fija, porque los meses tienen longitudes distintas. Define la regla de negocio o utiliza una biblioteca especializada.
Comparar y ordenar eventos
from datetime import datetime
eventos = [
datetime(2026, 8, 1, 9, 0),
datetime(2026, 7, 15, 14, 0),
datetime(2026, 7, 20, 10, 30),
]
for evento in sorted(eventos):
print(evento.isoformat())No compares un datetime ingenuo con uno que contiene zona. Normaliza ambos valores primero.
Zonas horarias con zoneinfo
from datetime import datetime
from zoneinfo import ZoneInfo
sao_paulo = ZoneInfo("America/Sao_Paulo")
madrid = ZoneInfo("Europe/Madrid")
reunion_local = datetime(
2026, 7, 11, 10, 0,
tzinfo=sao_paulo,
)
reunion_madrid = reunion_local.astimezone(madrid)
print(reunion_local)
print(reunion_madrid)Una zona con nombre conoce cambios históricos y horario de verano. Un desplazamiento fijo como -03:00 no contiene esas reglas.
Ingenuo frente a consciente
from datetime import datetime, timezone
ingenuo = datetime(2026, 7, 11, 12, 0)
consciente = datetime(
2026, 7, 11, 12, 0,
tzinfo=timezone.utc,
)
print(ingenuo.tzinfo)
print(consciente.tzinfo)No añadas una zona arbitraria a un valor ingenuo sin saber qué lugar representaba originalmente.
Crear una función para fechas límite
from datetime import datetime, timezone
def segundos_hasta(fecha_limite):
if fecha_limite.tzinfo is None:
raise ValueError(
"La fecha límite debe incluir zona horaria"
)
ahora = datetime.now(timezone.utc)
normalizada = fecha_limite.astimezone(timezone.utc)
return max(
0.0,
(normalizada - ahora).total_seconds(),
)Usar fechas en nombres de archivos
from datetime import datetime, timezone
from pathlib import Path
marca = datetime.now(timezone.utc).strftime(
"%Y%m%dT%H%M%SZ"
)
ruta = Path("exportaciones") / f"informe-{marca}.txt"
ruta.parent.mkdir(parents=True, exist_ok=True)
ruta.write_text("Informe creado.", encoding="utf-8")La guía de pathlib en Python explica cómo construir rutas portables.
Guardar fechas en SQLite
Una base SQLite puede almacenar texto ISO o timestamps, pero la aplicación debe definir una estrategia coherente. Revisa la guía de SQLite con Python para integrar fechas en una base local.
Errores frecuentes
- Guardar fechas en formatos humanos inconsistentes.
- Utilizar datetimes ingenuos en datos intercambiados entre sistemas.
- Suponer que todos los días locales tienen exactamente 24 horas.
- Tratar un mes como una cantidad fija de días.
- Comparar valores ingenuos y conscientes.
- Usar la hora local del servidor como referencia universal.
Conclusión
El código fiable comienza definiendo qué representa cada valor: una fecha de calendario, una hora local, una duración o un instante global. Mantén objetos estructurados durante los cálculos, utiliza UTC para intercambiar instantes y convierte a una zona con nombre al mostrar la información.
Documentación oficial
Consulta la referencia oficial de Python sobre datetime y la documentación de zoneinfo para trabajar correctamente con fechas, duraciones y zonas horarias.


