La manipulación de fechas y tiempos es una de las tareas más comunes en el desarrollo de software. Ya sea para registrar eventos, calcular intervalos de tiempo, formatear salida para usuarios o trabajar con zonas horarias, el módulo datetime de Python es la herramienta esencial que todo desarrollador necesita dominar.
En esta guía completa, aprenderás desde los conceptos básicos hasta técnicas avanzadas de manipulación de datos temporales en Python, con ejemplos prácticos que puedes aplicar inmediatamente en tus proyectos.
📦 Introducción al Módulo datetime
Python viene con el módulo datetime integrado en su biblioteca estándar, lo que significa que no necesitas instalar nada extra para comenzar a usarlo. Este módulo proporciona clases para trabajar con fechas, tiempos y combinaciones de ambos.
Según la documentación oficial de Python, el módulo datetime ofrece varias clases fundamentales que hacen que el manejo de datos temporales sea simple e intuitivo.
import datetime
# Verificar versión del módulo
print(datetime.__version__)
🕐 Las Principales Clases de datetime
1. datetime.date — Solo la Fecha
La clase date representa una fecha en formato año-mes-día, sin información de horario. Es ideal cuando necesitas trabajar solo con calendarios, aniversario, plazos, etc.
import datetime
# Crear una fecha específica
fecha_nacimiento = datetime.date(1995, 3, 15)
print(fecha_nacimiento) # 1995-03-15
# Obtener la fecha de hoy
hoy = datetime.date.today()
print(f"Hoy es {hoy}") # Hoy es 2026-05-13
# Acceder a componentes individuales
print(f"Año: {hoy.year}") # 2026
print(f"Mes: {hoy.month}") # 5
print(f"Día: {hoy.day}") # 13
print(f"Día de la semana: {hoy.weekday()}") # 0 (lunes)
# Día de la semana con nombre
días = ["Lunes", "Martes", "Miércoles", "Jueves", "Viernes", "Sábado", "Domingo"]
print(f"Hoy es {días[hoy.weekday()]}")
# Crear fecha a partir de timestamp Unix
fecha_timestamp = datetime.date.fromtimestamp(1700000000)
print(fecha_timestamp)
2. datetime.time — Solo el Horario
La clase time representa un horario específico, sin información de fecha. Útil para agendamientos, recordatorios y control de asistencia.
import datetime
# Crear un horario específico
hora_reunión = datetime.time(14, 30, 0) # 14h30min
print(hora_reunión) # 14:30:00
# Con microsegundos
hora_exacta = datetime.time(14, 30, 45, 123456)
print(hora_exacta) # 14:30:45.123456
# Acceder componentes
print(f"Hora: {hora_reunión.hour}") # 14
print(f"Minutos: {hora_reunión.minute}") # 30
print(f"Segundos: {hora_reunión.second}") # 0
# Formatear horario
print(hora_reunión.strftime("%H:%M")) # 14:30
print(hora_reunión.strftime("%I:%M %p")) # 02:30 PM
3. datetime.datetime — Fecha y Hora Combinados
La clase datetime es la más usada y completa, combinando fecha y hora en un solo objeto. Es perfecta para timestamps, logs, registros de eventos y mucho más.
import datetime
# Crear datetime específico
ahora = datetime.datetime.now()
print(f"Ahora: {ahora}")
# Crear datetime específico
evento = datetime.datetime(2026, 12, 25, 18, 0, 0)
print(f"Navidad: {evento}")
# datetime actual con timezone
utc_actual = datetime.datetime.utcnow()
print(f"UTC ahora: {utc_actual}")
# Crear a partir de string
fecha_str = "2026-05-13 15:30:00"
fecha_parsed = datetime.datetime.strptime(fecha_str, "%Y-%m-%d %H:%M:%S")
print(f"Parseado: {fecha_parsed}")
# Acceder todos los componentes
print(f"Fecha: {ahora.date()}")
print(f"Hora: {ahora.time()}")
print(f"Año: {ahora.year}, Mes: {ahora.month}, Día: {ahora.day}")
print(f"Hora: {ahora.hour}, Minuto: {ahora.minute}, Segundo: {ahora.second}")
4. datetime.timedelta — Diferencias de Tiempo
La clase timedelta representa la diferencia entre dos fechas u horas. Es esencial para calcular duraciones, intervalos y hacer operaciones aritméticas con fechas.
import datetime
# Crear timedelta
un_día = datetime.timedelta(days=1)
dos_horas = datetime.timedelta(hours=2)
media_hora = datetime.timedelta(minutes=30)
# Operaciones con datetime
hoy = datetime.datetime.now()
mañana = hoy + un_día
print(f"Mañana: {mañana}")
semana_pasada = hoy - datetime.timedelta(weeks=1)
print(f"Semana pasada: {semana_pasada}")
# Calcular diferencia entre fechas
inicio = datetime.datetime(2026, 1, 1)
fin = datetime.datetime(2026, 5, 13)
diff = fin - inicio
print(f"Diferencia: {diff}")
print(f"Días: {diff.days}")
print(f"Segundos: {diff.seconds}")
# timedelta total en horas
total_horas = diff.total_seconds() / 3600
print(f"Total de horas: {total_horas:.2f}")
📝 Formateo de Fechas y Tiempos
El formateo de fechas es crucial para mostrar información a los usuarios de manera clara y comprensible. Python ofrece dos funciones principales para esto: strftime() para formatear datetime a string y strptime() para convertir string a datetime.
Códigos de Formato Más Usados
import datetime
ahora = datetime.datetime.now()
# Formatos comunes
print(ahora.strftime("%d/%m/%Y")) # 13/05/2026
print(ahora.strftime("%d-%m-%Y")) # 13-05-2026
print(ahora.strftime("%d de %B de %Y")) # 13 de mayo de 2026
print(ahora.strftime("%H:%M:%S")) # 14:30:45
print(ahora.strftime("%H:%M")) # 14:30
print(ahora.strftime("%d/%m/%Y a las %H:%M")) # 13/05/2026 a las 14:30
# Formatos internacionales
print(ahora.strftime("%Y-%m-%d")) # 2026-05-13 (ISO 8601)
print(ahora.strftime("%B %d, %Y")) # May 13, 2026
# Día de la semana
print(ahora.strftime("%A")) # miércoles
print(ahora.strftime("%a")) # mié
print(ahora.strftime("%A, %d de %B de %Y")) # miércoles, 13 de mayo de 2026
# Mes
print(ahora.strftime("%B")) # mayo
print(ahora.strftime("%b")) # may
print(ahora.strftime("%m")) # 05
# Hora en formato 12h
print(ahora.strftime("%I:%M %p")) # 02:30 PM
Para una referencia completa de todos los códigos de formato, W3Schools ofrece una guía útil y didáctica sobre datetime en Python.
🔄 Conversión de String a datetime
Una de las tareas más frecuentes en programación es convertir strings en varios formatos a objetos datetime. El strptime() (string parse time) hace exactamente eso.
import datetime
# Varios formatos de entrada
formatos = [
("2026-05-13", "%Y-%m-%d"),
("13/05/2026", "%d/%m/%Y"),
("13-05-2026", "%d-%m-%Y"),
("May 13, 2026", "%B %d, %Y"),
("13 May 2026", "%d %B %Y"),
("2026-05-13 14:30:00", "%Y-%m-%d %H:%M:%S"),
("13/05/2026 14:30", "%d/%m/%Y %H:%M"),
]
for fecha_str, formato in formatos:
try:
dt = datetime.datetime.strptime(fecha_str, formato)
print(f"'{fecha_str}' -> {dt}")
except ValueError as e:
print(f"Error al convertir '{fecha_str}': {e}")
# Función para detectar formato automáticamente
def convertir_fecha(fecha_str):
formatos = [
"%Y-%m-%d",
"%d/%m/%Y",
"%d-%m-%Y",
"%Y/%m/%d",
"%B %d, %Y",
"%d %B %Y",
]
for fmt in formatos:
try:
return datetime.datetime.strptime(fecha_str, fmt)
except ValueError:
continue
raise ValueError(f"No se pudo convertir: {fecha_str}")
print(convertir_fecha("13/05/2026"))
🌍 Trabajando con Zonas Horarias
Trabajar con zonas horarias es uno de los aspectos más complejos de la manipulación de fechas. Python usa la biblioteca pytz para gestionar zonas horarias de manera eficiente.
import datetime
import pytz
# Crear datetime con timezone
tz_brasil = pytz.timezone('America/Sao_Paulo')
tz_eeuu = pytz.timezone('America/New_York')
tz_japón = pytz.timezone('Asia/Tokyo')
# Datetime actual en diferentes zonas
ahora_brasil = datetime.datetime.now(tz_brasil)
ahora_eeuu = datetime.datetime.now(tz_eeuu)
ahora_japón = datetime.datetime.now(tz_japón)
print(f"Brasil: {ahora_brasil}")
print(f"EEUU: {ahora_eeuu}")
print(f"Japón: {ahora_japón}")
# Crear datetime en timezone específico
fecha_específica = datetime.datetime(2026, 12, 25, 18, 0, 0, tzinfo=tz_brasil)
print(f"Navidad en Brasil: {fecha_específica}")
# Convertir entre zonas horarias
navidad_brasil = datetime.datetime(2026, 12, 25, 18, 0, 0, tzinfo=tz_brasil)
navidad_eeuu = navidad_brasil.astimezone(tz_eeuu)
navidad_japón = navidad_brasil.astimezone(tz_japón)
print(f"Navidad 18h en Brasil = {navidad_eeuu.strftime('%H:%M')} en EEUU")
print(f"Navidad 18h en Brasil = {navidad_japón.strftime('%H:%M')} en Japón")
# Obtener timezone de string ISO 8601
fecha_iso = "2026-05-13T14:30:00-03:00"
dt_iso = datetime.datetime.fromisoformat(fecha_iso)
print(f"De ISO: {dt_iso}")
# Lista de timezones disponibles
print("Algunas zonas horarias disponibles:")
for tz in ['America/Sao_Paulo', 'America/New_York', 'Europe/London', 'Asia/Tokyo', 'Australia/Sydney']:
print(f" - {tz}")
La documentación de Real Python ofrece una guía detallada sobre cómo trabajar con zonas horarias correctamente.
📊 Operaciones Aritméticas con Fechas
Una de las grandes ventajas del módulo datetime es la capacidad de realizar operaciones aritméticas directamente entre fechas e intervalos de tiempo.
import datetime
# Adición y sustracción
fecha = datetime.datetime(2026, 5, 13)
# Agregar días
más_10_días = fecha + datetime.timedelta(days=10)
print(f"10 días después: {más_10_días}")
# Restar semanas
menos_2_semanas = fecha - datetime.timedelta(weeks=2)
print(f"2 semanas antes: {menos_2_semanas}")
# Agregar meses (necesita biblioteca adicional o lógica personalizada)
def agregar_meses(fecha, meses):
mes = fecha.month + meses
año = fecha.year + (mes - 1) // 12
mes = ((mes - 1) % 12) + 1
día = min(fecha.day, [31, 29 if año % 4 == 0 and (año % 100 != 0 or año % 400 == 0) else 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][mes-1])
return fecha.replace(year=año, month=mes, day=día)
resultado = agregar_meses(fecha, 6)
print(f"6 meses después: {resultado}")
# Calcular edad
def calcular_edad(fecha_nacimiento):
hoy = datetime.date.today()
edad = hoy.year - fecha_nacimiento.year
if (hoy.month, hoy.day) < (fecha_nacimiento.month, fecha_nacimiento.day):
edad -= 1
return edad
nac = datetime.date(1995, 3, 15)
print(f"Edad: {calcular_edad(nac)} años")
# Verificar si es día laboral
def es_día_laboral(fecha):
return fecha.weekday() < 5 # 0-4 = lun a vie
print(f"13/05/2026 es día laboral? {es_día_laboral(fecha)}")
🗓️ Generando Secuencias de Fechas
Para muchas aplicaciones, necesitas generar secuencias de fechas, como por ejemplo, crear una agenda, generar reportes por período o iterar sobre días laborales.
import datetime
# Generar secuencia de días
inicio = datetime.date(2026, 5, 1)
fin = datetime.date(2026, 5, 15)
días = []
fecha = inicio
while fecha <= fin:
días.append(fecha)
fecha += datetime.timedelta(days=1)
print("Días de mayo (1-15):")
for d in días:
print(f" {d.strftime('%d/%m')}")
# Usando list comprehension
días_mayo = [inicio + datetime.timedelta(days=i) for i in range(15)]
print(f"Total de días: {len(días_mayo)}")
# Generar meses entre fechas
def meses_entre(inicio, fin):
resultado = []
actual = inicio
while actual < fin:
resultado.append(actual)
if actual.month == 12:
actual = actual.replace(year=actual.year + 1, month=1)
else:
actual = actual.replace(month=actual.month + 1)
return resultado
meses = meses_entre(datetime.date(2026, 1, 1), datetime.date(2026, 12, 31))
print("Meses de 2026:")
for m in meses:
print(f" {m.strftime('%B')}")
# Días laborales entre fechas
def días_laborales(inicio, fin):
días = []
fecha = inicio
while fecha <= fin:
if fecha.weekday() < 5:
días.append(fecha)
fecha += datetime.timedelta(days=1)
return días
laborales = días_laborales(datetime.date(2026, 5, 1), datetime.date(2026, 5, 31))
print(f"Días laborales en mayo: {len(laborales)}")
# Generar horarios para un día específico
def horarios_día(fecha, inicio_hora=9, fin_hora=18, intervalo=30):
horarios = []
for h in range(inicio_hora, fin_hora):
for m in [0, intervalo]:
if h == fin_hora - 1 and m > 0:
break
horarios.append(fecha.replace(hour=h, minute=m))
return horarios
agenda = horarios_día(datetime.datetime(2026, 5, 13))
print("Horarios disponibles para 13/05:")
for h in agenda[:6]:
print(f" {h.strftime('%H:%M')}")
🔍 Comparación de Fechas
Comparar fechas es esencial para validaciones, ordenaciones y verificaciones de período. datetime permite varias formas de comparación.
import datetime
# Fechas de ejemplo
d1 = datetime.datetime(2026, 5, 13)
d2 = datetime.datetime(2026, 6, 15)
d3 = datetime.datetime(2026, 5, 13, 14, 30)
# Comparaciones directas
print(f"d1 == d2: {d1 == d2}") # False
print(f"d1 != d2: {d1 != d2}") # True
print(f"d1 < d2: {d1 < d2}") # True
print(f"d1 <= d2: {d1 <= d2}") # True
print(f"d1 > d2: {d1 > d2}") # False
# Comparar solo fechas (ignorando hora)
print(f"d1.date() == d3.date(): {d1.date() == d3.date()}") # True
# Verificar si está en pasado, presente o futuro
ahora = datetime.datetime.now()
if ahora < d1:
print("d1 está en el futuro")
elif ahora > d1:
print("d1 está en el pasado")
else:
print("d1 es ahora")
# Verificar si está en un intervalo
inicio = datetime.datetime(2026, 1, 1)
fin = datetime.datetime(2026, 12, 31)
print(f"d1 está entre {inicio.date()} y {fin.date()}? {inicio <= d1 <= fin}")
# Ordenar lista de fechas
fechas = [
datetime.datetime(2026, 3, 15),
datetime.datetime(2026, 1, 10),
datetime.datetime(2026, 12, 25),
datetime.datetime(2026, 7, 4),
]
fechas.sort()
print("Fechas ordenadas:")
for d in fechas:
print(f" {d.strftime('%d/%m/%Y')}")
⏰ Midiendo Tiempo de Ejecución
Datetime se usa frecuentemente para medir el tiempo de ejecución de código, lo cual es fundamental para optimización de rendimiento.
import datetime
import time
# Método 1: Usando datetime
inicio = datetime.datetime.now()
time.sleep(1) # Simulando procesamiento
fin = datetime.datetime.now()
duración = fin - inicio
print(f"Duración: {duración.total_seconds():.2f} segundos")
# Método 2: Usando time.time()
inicio_ts = time.time()
time.sleep(0.5)
fin_ts = time.time()
print(f"Duración (time): {fin_ts - inicio_ts:.2f} segundos")
# Método 3: Usando context manager
class Cronómetro:
def __init__(self):
self.inicio = None
self.fin = None
def __enter__(self):
self.inicio = datetime.datetime.now()
return self
def __exit__(self, *args):
self.fin = datetime.datetime.now()
self.duración = self.fin - self.inicio
def tiempo_total(self):
return self.duración.total_seconds()
with Cronómetro() as cron:
time.sleep(0.3)
print(f"Tiempo medido: {cron.tiempo_total():.3f} segundos")
# Medir múltiples ejecuciones
def medir_función(función, veces=100):
resultados = []
for _ in range(veces):
inicio = datetime.datetime.now()
función()
fin = datetime.datetime.now()
resultados.append((fin - inicio).total_seconds())
promedio = sum(resultados) / len(resultados)
return {
'promedio': promedio,
'mín': min(resultados),
'máx': max(resultados),
'veces': veces
}
def función_prueba():
suma = 0
for i in range(1000):
suma += i
resultado = medir_función(función_prueba, veces=50)
print(f"Promedio: {resultado['promedio']*1000:.2f}ms")
print(f"Mín: {resultado['mín']*1000:.2f}ms, Máx: {resultado['máx']*1000:.2f}ms")
🛠️ Casos de Uso Prácticos
1. Calcular días hasta una fecha futura
import datetime
def días_hasta(objetivo):
hoy = datetime.date.today()
if isinstance(objetivo, datetime.datetime):
objetivo = objetivo.date()
diff = objetivo - hoy
return diff.days
# Cumpleaños
cumpleaños = datetime.date(2026, 12, 25)
print(f"Días hasta Navidad: {días_hasta(cumpleaños)}")
# Feriado
feriado = datetime.date(2027, 1, 1)
print(f"Días hasta Año Nuevo: {días_hasta(feriado)}")
2. Verificar si un año es bisiesto
import datetime
def es_bisiesto(año):
return (año % 4 == 0 and año % 100 != 0) or (año % 400 == 0)
# Febrero en diferentes años
for año in [2024, 2026, 2027, 2028]:
print(f"{año}: {'Bisiesto' if es_bisiesto(año) else 'Normal'}")
# Usando dateutil
from datetime import date
import calendar
print(f"Febrero 2024 tiene {calendar.monthrange(2024, 2)[1]} días")
3. Generar nombre de archivo con timestamp
import datetime
def generar_nombre_archivo(prefijo, extensión):
ahora = datetime.datetime.now()
timestamp = ahora.strftime("%Y%m%d_%H%M%S")
return f"{prefijo}_{timestamp}.{extensión}"
print(generar_nombre_archivo("backup", "zip"))
print(generar_nombre_archivo("reporte", "pdf"))
print(generar_nombre_archivo("log", "txt"))
4. Calcular duración de un evento
import datetime
eventos = [
("Reunión", datetime.datetime(2026, 5, 13, 14, 0), datetime.datetime(2026, 5, 13, 15, 30)),
("Taller", datetime.datetime(2026, 5, 13, 9, 0), datetime.datetime(2026, 5, 13, 12, 0)),
("Charla", datetime.datetime(2026, 5, 13, 16, 0), datetime.datetime(2026, 5, 13, 17, 45)),
]
for nombre, inicio, fin in eventos:
duración = fin - inicio
print(f"{nombre}: {duración} ({duración.total_seconds()/3600:.2f}h)")
5. Validar fecha de expiración
import datetime
def está_expirado(fecha_expiración):
return datetime.datetime.now() > fecha_expiración
# Simular certificado SSL
certificado_expira = datetime.datetime(2026, 12, 31, 23, 59, 59)
print(f"Certificado expirado? {está_expirado(certificado_expira)}")
# Verificar días restantes
def días_para_expirar(fecha_expiración):
ahora = datetime.datetime.now()
if isinstance(fecha_expiración, datetime.datetime):
fecha_expiración = fecha_expiración.replace(tzinfo=None) - ahora
else:
fecha_expiración = fecha_expiración - ahora.date()
return fecha_expiración.days
print(f"Días hasta expirar: {días_para_expirar(certificado_expira)}")
📚 Bibliotecas Complementarias
Aunque el módulo datetime es extremadamente poderoso, existen bibliotecas que pueden facilitar aún más el trabajo con fechas en Python.
dateutil - Extensiones útiles
# dateutil proporciona funcionalidades avanzadas
from dateutil import parser
from dateutil.relativedelta import relativedelta
from dateutil.rrule import rrule, MONTHLY
# Parse automático de strings
fecha = parser.parse("mañana")
print(f"Parseado: {fecha}")
fecha = parser.parse("15 de mayo de 2026")
print(f"Parseado: {fecha}")
# Agregar meses con relativedelta
from datetime import datetime
ahora = datetime.now()
más_3_meses = ahora + relativedelta(months=3)
print(f"3 meses después: {más_3_meses}")
# Generar ocurrencias mensuales
from dateutil.rrule import rrule, MONTHLY
inicio = datetime(2026, 1, 1)
fin = datetime(2026, 12, 31)
ocurrencias = list(rrule(MONTHLY, dtstart=inicio, until=fin))
print(f"Meses de 2026: {len(ocurrencias)}")
pandas - Para series temporales
Para análisis de datos y series temporales, pandas es la biblioteca más recomendada. Ofrece funcionalidades avanzadas para manipulación de fechas en contextos de análisis de datos.
import pandas as pd
# Crear DataFrame con fechas
fechas = pd.date_range(start='2026-01-01', end='2026-12-31', freq='D')
df = pd.DataFrame({'fecha': fechas, 'valor': range(len(fechas))})
# Operaciones de tiempo
df['año'] = df['fecha'].dt.year
df['mes'] = df['fecha'].dt.month
df['día_semana'] = df['fecha'].dt.day_name()
df['trimestre'] = df['fecha'].dt.quarter
print(df.head())
# Resample - agregar por período
df['valor'] = range(1, len(fechas) + 1)
mensual = df.set_index('fecha')['valor'].resample('M').sum()
print(f"\nTotal por mes:\n{mensual}")
⚠️ Errores Comunes y Cómo Evitarlos
1. Mutabilidad de datetime
import datetime
# CUIDADO: datetime es mutable!
dt = datetime.datetime(2026, 5, 13)
dt_modificado = dt.replace(month=12) # Crea nuevo objeto
print(f"Original: {dt}")
print(f"Modificado: {dt_modificado}")
# Para alterar, necesitas asignar
dt = dt.replace(month=12)
print(f"Alterado: {dt}")
2. Zonas horarias y localización
import datetime
import pytz
# Siempre especifica timezone
tz = pytz.timezone('America/Sao_Paulo')
dt = datetime.datetime(2026, 5, 13, 12, 0, tzinfo=tz)
print(f"Con timezone: {dt}")
# CUIDADO: localize, no solo asignes
dt_no_localizado = datetime.datetime(2026, 5, 13, 12, 0)
dt_localizado = tz.localize(dt_no_localizado)
print(f"Localizado: {dt_localizado}")
# Usar timezone al crear fromisoformat (Python 3.11+)
dt_iso = datetime.datetime.fromisoformat("2026-05-13T12:00:00-03:00")
print(f"From ISO: {dt_iso}")
3. Fechas fuera del intervalo válido
import datetime
# CUIDADO: fechas inválidas pueden generar errores o resultados inesperados
try:
dt = datetime.datetime(2026, 2, 30) # Febrero no tiene 30 días
except ValueError as e:
print(f"Error: {e}")
# Siempre valida fechas
def fecha_válida(año, mes, día):
try:
datetime.date(año, mes, día)
return True
except ValueError:
return False
print(f"2026-02-30 válida? {fecha_válida(2026, 2, 30)}")
print(f"2026-02-28 válida? {fecha_válida(2026, 2, 28)}")
print(f"2024-02-29 válida? {fecha_válida(2024, 2, 29)}") # Año bisiesto
🚀 Próximos Pasos
Ahora que dominas el módulo datetime de Python, estás preparado para manejar la mayoría de las situaciones que involucran fechas y tiempos en tus aplicaciones. Para profundizar aún más tu conocimiento, recomendamos:
- Strings en Python — aprende cómo formatear y manipular strings, complementando el trabajo con fechas
- Manejo de Errores — descubre cómo manejar excepciones que pueden surgir al trabajar con fechas inválidas
- Pandas para Análisis de Datos — explora funcionalidades avanzadas de series temporales
- Curso Completo de Python — de cero a avanzado con proyectos reales
Dominar datetime es fundamental para cualquier desarrollador Python. ¡Sigue practicando y explorando las posibilidades de este poderoso módulo! 🎯