Tutoriales

Manejando Cambios de Horario de Verano (DST): Guía Completa para Desarrolladores

Introducción

El Horario de Verano (DST) es uno de los aspectos más complicados del manejo de fechas y horas. Este tutorial te enseñará cómo manejar correctamente las transiciones DST en tu código.

Lo que Aprenderás

  • ✅ Qué es DST y cuándo ocurre
  • ✅ El problema de "Spring Forward" (hora faltante)
  • ✅ El problema de "Fall Back" (hora duplicada)
  • ✅ Mejores prácticas para manejar DST
  • ✅ Ejemplos prácticos en JavaScript y Python

¿Qué es DST?

El Horario de Verano es la práctica de adelantar los relojes durante los meses más cálidos:

  • Spring Forward (Primavera): Los relojes avanzan 1 hora (ej. 2:00 AM → 3:00 AM)
  • Fall Back (Otoño): Los relojes retroceden 1 hora (ej. 2:00 AM → 1:00 AM)

Fechas de Transición (2024)

RegiónSpring ForwardFall Back
EE.UU.10 marzo3 noviembre
Europa31 marzo27 octubre
Australia6 octubre7 abril

El Problema de la Hora Faltante

Cuando los relojes "saltan hacia adelante", una hora completa no existe.

JavaScript

// En zona horaria de España (Europe/Madrid)
// El 31 de marzo de 2024, 2:00 AM no existe

const fechaProblema = new Date('2024-03-31T02:30:00');
// JavaScript ajusta automáticamente a 3:30 AM

// Usando Luxon para mejor control
import { DateTime } from 'luxon';

const dt = DateTime.fromObject(
  { year: 2024, month: 3, day: 31, hour: 2, minute: 30 },
  { zone: 'Europe/Madrid' }
);
console.log(dt.isValid); // true, pero ajustado
console.log(dt.hour);    // 3 (ajustado)

Python

from datetime import datetime
from zoneinfo import ZoneInfo

madrid = ZoneInfo('Europe/Madrid')

# Esto se ajusta automáticamente
dt = datetime(2024, 3, 31, 2, 30, tzinfo=madrid)
print(dt)  # Se ajusta a hora válida

El Problema de la Hora Duplicada

Cuando los relojes "retroceden", la misma hora ocurre dos veces.

JavaScript con Luxon

import { DateTime } from 'luxon';

// 27 de octubre 2024, 2:30 AM ocurre DOS veces en Madrid
const primeraVez = DateTime.fromObject(
  { year: 2024, month: 10, day: 27, hour: 2, minute: 30 },
  { zone: 'Europe/Madrid' }
).set({ offset: 120 }); // +02:00 (antes del cambio)

const segundaVez = DateTime.fromObject(
  { year: 2024, month: 10, day: 27, hour: 2, minute: 30 },
  { zone: 'Europe/Madrid' }
).set({ offset: 60 }); // +01:00 (después del cambio)

console.log(primeraVez.toISO()); // 2024-10-27T02:30:00+02:00
console.log(segundaVez.toISO()); // 2024-10-27T02:30:00+01:00

Python

from datetime import datetime
from zoneinfo import ZoneInfo

madrid = ZoneInfo('Europe/Madrid')

# fold=0 significa primera ocurrencia (antes del cambio)
# fold=1 significa segunda ocurrencia (después del cambio)
primera = datetime(2024, 10, 27, 2, 30, fold=0, tzinfo=madrid)
segunda = datetime(2024, 10, 27, 2, 30, fold=1, tzinfo=madrid)

print(f"Primera: {primera} (offset: {primera.strftime('%z')})")
print(f"Segunda: {segunda} (offset: {segunda.strftime('%z')})")

Mejores Prácticas

1. Siempre Trabaja en UTC

// ✅ Almacenar en UTC
const timestampUtc = Date.now();
const fechaUtc = new Date(timestampUtc).toISOString();
// "2024-03-31T01:30:00.000Z" - siempre válido

// Convertir a local solo para mostrar
const local = new Date(timestampUtc).toLocaleString('es-ES', {
  timeZone: 'Europe/Madrid'
});

2. Usa Bibliotecas de Zona Horaria

# ✅ Usar zoneinfo o pytz
from zoneinfo import ZoneInfo

# ❌ No hacer cálculos manuales de offset
offset = -5  # ¡Ignora DST!

3. Valida Fechas Durante Transiciones

function esFechaValida(year, month, day, hour, minute, zona) {
  const dt = DateTime.fromObject(
    { year, month, day, hour, minute },
    { zone: zona }
  );

  if (!dt.isValid) {
    return { valida: false, razon: 'Hora no existe (DST gap)' };
  }

  // Verificar si la hora fue ajustada
  if (dt.hour !== hour || dt.minute !== minute) {
    return { 
      valida: true, 
      ajustada: true,
      horaOriginal: `${hour}:${minute}`,
      horaAjustada: `${dt.hour}:${dt.minute}`
    };
  }

  return { valida: true, ajustada: false };
}

4. Prueba con Fechas de Transición

# Incluye estas fechas en tus tests
FECHAS_DST_TEST = [
    # Spring Forward (hora faltante)
    datetime(2024, 3, 31, 2, 30),

    # Fall Back (hora duplicada)
    datetime(2024, 10, 27, 2, 30),

    # Día normal
    datetime(2024, 6, 15, 12, 0),
]

Errores Comunes a Evitar

1. Asumir que todos los días tienen 24 horas

# ❌ Incorrecto
siguiente_dia = fecha + timedelta(hours=24)

# ✅ Correcto - usar días
siguiente_dia = fecha + timedelta(days=1)

2. Codificar offsets manualmente

// ❌ Incorrecto
const offset = -5 * 60 * 60 * 1000; // EST siempre

// ✅ Correcto - usar biblioteca
const zona = 'America/New_York'; // Maneja DST automáticamente

3. Ignorar ambigüedad en hora duplicada

# ❌ No especificar fold
dt = datetime(2024, 10, 27, 2, 30, tzinfo=madrid)

# ✅ Especificar fold explícitamente
dt = datetime(2024, 10, 27, 2, 30, fold=1, tzinfo=madrid)

Resumen

  • Spring Forward: Una hora no existe - valida y ajusta
  • Fall Back: Una hora ocurre dos veces - especifica cuál
  • Regla de oro: Almacena en UTC, muestra en local
  • Usa bibliotecas: No calcules offsets manualmente

¡Prueba nuestro Convertidor de Zona Horaria para ver cómo funcionan las conversiones durante transiciones DST!

Pruébalo

Prueba la conversión de timestamps

Resultado de fecha

¿Necesitas más opciones? Convertidor de zona horaria