Ir al contenido principal

Manejo de fechas y tiempo con datetime

Introducción

El manejo de fechas y tiempo es una tarea común en muchos proyectos de programación: desde aplicaciones que necesitan registrar eventos, programar tareas o calcular duraciones, hasta análisis de datos temporales. Python ofrece el módulo datetime en su biblioteca estándar, que proporciona clases para manipular fechas y horas de manera eficiente y precisa. En este artículo, aprenderemos a trabajar con este módulo para crear, modificar y operar con fechas y horas en nuestros programas Python.

El módulo datetime

El módulo datetime contiene varias clases que nos permiten trabajar con diferentes aspectos de fechas y tiempo:

  • datetime: Combina fecha y hora
  • date: Solo fecha (año, mes, día)
  • time: Solo hora (hora, minuto, segundo, microsegundo)
  • timedelta: Representa una duración o diferencia de tiempo
  • tzinfo: Clase base abstracta para información de zona horaria

Comencemos importando el módulo:

import datetime

También es común importar clases específicas para mayor comodidad:

from datetime import datetime, date, time, timedelta

La clase date

La clase date representa una fecha (año, mes, día) sin información horaria.

Creación de objetos date

Podemos crear un objeto date especificando año, mes y día:

# Crear una fecha específica
fecha = date(2023, 10, 15)
print(fecha)  # Salida: 2023-10-15

Obtener la fecha actual

hoy = date.today()
print(f"Hoy es: {hoy}")

Acceso a los componentes de una fecha

print(f"Año: {hoy.year}")
print(f"Mes: {hoy.month}")
print(f"Día: {hoy.day}")

# También podemos obtener el día de la semana (0 = lunes, 6 = domingo)
print(f"Día de la semana: {hoy.weekday()}")

Formateo de fechas

Podemos formatear fechas como cadenas usando el método strftime():

# Formato personalizado
formato_espanol = hoy.strftime("%d/%m/%Y")
print(f"Formato español: {formato_espanol}")  # Ejemplo: 15/10/2023

# Nombre del mes y día de la semana
formato_largo = hoy.strftime("%A, %d de %B de %Y")
print(formato_largo)  # Ejemplo: domingo, 15 de octubre de 2023

La clase time

La clase time representa un tiempo (hora, minuto, segundo, microsegundo) sin información de fecha.

Creación de objetos time

# Hora, minuto, segundo, microsegundo
hora = time(14, 30, 15, 0)
print(hora)  # Salida: 14:30:15

Acceso a los componentes de time

print(f"Hora: {hora.hour}")
print(f"Minuto: {hora.minute}")
print(f"Segundo: {hora.second}")
print(f"Microsegundo: {hora.microsecond}")

Formateo de time

formato_hora = hora.strftime("%H:%M:%S")
print(f"La hora es: {formato_hora}")

La clase datetime

La clase datetime combina fecha y hora en un solo objeto.

Creación de objetos datetime

# Crear un datetime específico (año, mes, día, hora, minuto, segundo, microsegundo)
dt = datetime(2023, 10, 15, 14, 30, 0)
print(dt)  # Salida: 2023-10-15 14:30:00

Obtener el datetime actual

ahora = datetime.now()
print(f"Fecha y hora actual: {ahora}")

También podemos usar datetime.today(), aunque now() permite especificar una zona horaria.

Combinar objetos date y time

fecha = date(2023, 10, 15)
hora = time(14, 30, 0)

# Combinar fecha y hora
dt_combinado = datetime.combine(fecha, hora)
print(dt_combinado)  # Salida: 2023-10-15 14:30:00

Acceso a componentes de datetime

print(f"Año: {ahora.year}")
print(f"Mes: {ahora.month}")
print(f"Día: {ahora.day}")
print(f"Hora: {ahora.hour}")
print(f"Minuto: {ahora.minute}")
print(f"Segundo: {ahora.second}")

Obtener solo la fecha o la hora

solo_fecha = ahora.date()
solo_hora = ahora.time()

print(f"Solo fecha: {solo_fecha}")
print(f"Solo hora: {solo_hora}")

La clase timedelta

La clase timedelta representa una duración o diferencia entre dos fechas o horas.

Creación de timedelta

# Un día de diferencia
un_dia = timedelta(days=1)

# Combinación de diferentes unidades
duracion = timedelta(days=2, hours=3, minutes=30, seconds=15)
print(duracion)  # Salida: 2 days, 3:30:15

Operaciones con fechas usando timedelta

hoy = date.today()
manana = hoy + timedelta(days=1)
ayer = hoy - timedelta(days=1)

print(f"Hoy: {hoy}")
print(f"Mañana: {manana}")
print(f"Ayer: {ayer}")

Cálculo de diferencias entre fechas

fecha1 = date(2023, 10, 15)
fecha2 = date(2023, 12, 25)

diferencia = fecha2 - fecha1
print(f"Días entre fechas: {diferencia.days}")  # Salida: 71

Operaciones con datetime

ahora = datetime.now()
en_tres_horas = ahora + timedelta(hours=3)
hace_dos_dias = ahora - timedelta(days=2)

print(f"Ahora: {ahora}")
print(f"En tres horas: {en_tres_horas}")
print(f"Hace dos días: {hace_dos_dias}")

Formateo y análisis de fechas

Python ofrece potentes herramientas para convertir fechas a cadenas y viceversa.

Formateo con strftime()

ahora = datetime.now()

# Diferentes formatos
formato_basico = ahora.strftime("%d/%m/%Y %H:%M:%S")
formato_americano = ahora.strftime("%m/%d/%Y %I:%M %p")  # Con AM/PM
formato_iso = ahora.strftime("%Y-%m-%dT%H:%M:%S")
formato_personalizado = ahora.strftime("Hoy es %A, %d de %B de %Y - %H:%M horas")

print(formato_basico)       # Ejemplo: 15/10/2023 14:30:00
print(formato_americano)    # Ejemplo: 10/15/2023 02:30 PM
print(formato_iso)          # Ejemplo: 2023-10-15T14:30:00
print(formato_personalizado)  # Ejemplo: Hoy es domingo, 15 de octubre de 2023 - 14:30 horas

Los códigos más comunes para formateo son:

  • %Y: Año con 4 dígitos
  • %m: Mes como número (01-12)
  • %d: Día del mes (01-31)
  • %H: Hora formato 24h (00-23)
  • %I: Hora formato 12h (01-12)
  • %M: Minutos (00-59)
  • %S: Segundos (00-59)
  • %A: Día de la semana completo
  • %a: Día de la semana abreviado
  • %B: Nombre del mes completo
  • %b: Nombre del mes abreviado
  • %p: AM/PM

Análisis de fechas con strptime()

El método strptime() permite convertir una cadena a un objeto datetime:

# Convertir una cadena a datetime
fecha_texto = "15/10/2023 14:30:00"
fecha_objeto = datetime.strptime(fecha_texto, "%d/%m/%Y %H:%M:%S")
print(f"Fecha convertida: {fecha_objeto}")

Zonas horarias

Para trabajar con zonas horarias, es recomendable usar la biblioteca externa pytz que se integra con datetime.

# Primero debemos instalar pytz: pip install pytz
import pytz
from datetime import datetime

# Crear datetime con zona horaria
utc_now = datetime.now(pytz.UTC)
print(f"UTC ahora: {utc_now}")

# Convertir a otra zona horaria
madrid_tz = pytz.timezone('Europe/Madrid')
madrid_now = utc_now.astimezone(madrid_tz)
print(f"Hora en Madrid: {madrid_now}")

# Lista de zonas horarias disponibles
# print(pytz.all_timezones)

Ejemplo práctico: Calculadora de edad

Vamos a crear una función que calcule la edad exacta en años, meses y días a partir de una fecha de nacimiento:

from datetime import datetime, date

def calcular_edad(fecha_nacimiento):
    """
    Calcula la edad exacta en años, meses y días
    a partir de una fecha de nacimiento.
    
    Args:
        fecha_nacimiento: Objeto date con la fecha de nacimiento
        
    Returns:
        Tupla con (años, meses, días)
    """
    hoy = date.today()
    
    # Calculamos años
    años = hoy.year - fecha_nacimiento.year
    
    # Ajustamos si aún no ha llegado el cumpleaños este año
    if (hoy.month, hoy.day) < (fecha_nacimiento.month, fecha_nacimiento.day):
        años -= 1
    
    # Calculamos la fecha del último cumpleaños
    ultimo_cumpleaños = date(hoy.year, fecha_nacimiento.month, fecha_nacimiento.day)
    if ultimo_cumpleaños > hoy:
        ultimo_cumpleaños = date(hoy.year - 1, fecha_nacimiento.month, fecha_nacimiento.day)
    
    # Calculamos meses y días desde el último cumpleaños
    meses = 0
    dias = 0
    
    # Ajustamos el día para cálculo de meses completos
    mes_aux = ultimo_cumpleaños.month
    año_aux = ultimo_cumpleaños.year
    
    while True:
        # Intentamos avanzar un mes
        mes_aux += 1
        if mes_aux > 12:
            mes_aux = 1
            año_aux += 1
        
        try:
            siguiente_mes = date(año_aux, mes_aux, ultimo_cumpleaños.day)
            if siguiente_mes > hoy:
                break
            meses += 1
            ultimo_cumpleaños = siguiente_mes
        except ValueError:
            # Si el día no existe en el mes (ej. 31 de febrero)
            continue
    
    # Calculamos los días restantes
    dias = (hoy - ultimo_cumpleaños).days
    
    return (años, meses, dias)

# Ejemplo de uso
fecha_nacimiento = date(1990, 5, 15)
años, meses, dias = calcular_edad(fecha_nacimiento)
print(f"Edad: {años} años, {meses} meses y {dias} días")

Resumen

En este artículo hemos aprendido a utilizar el módulo datetime de Python para manejar fechas y tiempo de manera efectiva. Hemos explorado las principales clases (date, time, datetime y timedelta), cómo crear y manipular fechas, calcular diferencias entre ellas, y formatear fechas para su presentación. También hemos visto un ejemplo práctico de cálculo de edad que demuestra la utilidad de estas herramientas. El manejo adecuado de fechas y tiempo es esencial para muchas aplicaciones, desde la gestión de usuarios hasta el análisis de datos temporales. En el próximo artículo, exploraremos el uso de expresiones regulares con el módulo re para procesar y manipular texto de manera avanzada.