Los horarios de zona son una mentira (y cómo manejarlos en el código)
Los husos horarios parecen simples en un mapa. No lo son. Aquí se explica por qué rompen el software — y el modelo mental adecuado para manejarlos en el código.
Abres un mapa. Ves cortes verticales. «UTC-5 es hora este, UTC+1 es hora central europea». ¿Simple, verdad?
Incorrecto. Los husos horarios son una construcción política, no un hecho geográfico — y esa distinción te salvará de algunos de los errores más graves en el desarrollo de software.
Por qué los husos horarios son realmente un desastre
Aquí está lo que maneja silenciosamente tu sistema operativo mediante la base de datos tz:
- El horario de verano (DST) — No todos los países lo observan, los países cambian las reglas y la transición ocurre en fechas diferentes según tu ubicación. Estados Unidos cambió las fechas en 2007. Egipto eliminó el DST en 2011, luego lo reactivó, y luego lo eliminó nuevamente.
- Desplazamientos de media hora y cuarto de hora — India (UTC+5:30), Nepal (UTC+5:45) y partes de Australia (UTC+9:30) existen. Tu suposición de que los desplazamientos son horas completas es incorrecta.
- Cambios históricos — Rusia pasó de UTC+4 a UTC+3 en 2014. Samoa saltó un día entero (30 de diciembre de 2011) para pasar de un lado a otro de la línea de fecha internacional. Cuando trabajas con timestamps históricos, el desplazamiento «correcto» puede ser completamente distinto al de hoy.
- Tiempo ambiguo — Cuando los relojes retroceden, las 1:30 AM ocurren dos veces. Cuando avanzan, las 2:30 AM no existen en absoluto. Si guardas «3 de noviembre de 2024 a las 1:45 AM Este» sin un desplazamiento UTC, tienes un timestamp ambiguo.
Ninguna de esta información es trivia. Cada uno de estos casos extremos ha causado errores reales en producción — eventos de calendario perdidos, pagos duplicados, sistemas de programación rotos.
La única regla que soluciona la mayoría de los problemas
Almacena y procesa en UTC. Convierte a hora local solo en el momento de la visualización.
Esta no es una recomendación controvertida. Es el consenso de todas las bases de datos principales, estándares de API y equipos de sistemas distribuidos. Si la columna de tu base de datos almacena 2024-11-03 06:45:00 en UTC, siempre sabrás exactamente qué momento en el tiempo representa — independientemente de dónde se aloje tu servidor, de qué zona horaria tenga tu usuario o de si ocurrió el DST ese día.
El momento en que almacenas 2024-11-03 01:45:00 sin un desplazamiento UTC, has perdido información. Has creado un timestamp que puede tener dos significados diferentes.
Cómo manejar husos horarios en JavaScript
El objeto integrado de JavaScript Date almacena el tiempo como milisegundos desde el epoch de Unix (1 de enero de 1970 UTC) — lo cual es bueno. El problema es que su API es confusa e inconsistente.
Lo que evitar
// BAD: Parsing without explicit timezone
const d = new Date('2024-11-03 01:45:00');
// Interpreted as LOCAL time — behavior varies by environment
// BAD: Storing user-facing strings as dates
const meeting = '3:00 PM Thursday';
// This is meaningless without a timezone
Lo que usar en su lugar
// GOOD: Always use ISO 8601 with explicit UTC offset
const d = new Date('2024-11-03T06:45:00Z'); // Z = UTC
// GOOD: Display in user's local timezone using Intl API
const formatter = new Intl.DateTimeFormat('en-US', {
timeZone: 'America/New_York',
dateStyle: 'full',
timeStyle: 'short',
});
console.log(formatter.format(d)); // "Sunday, November 3, 2024 at 1:45 AM"
Si estás construyendo algo más allá de una simple formateación de fechas, usa la Luxon biblioteca. Tiene soporte primero para husos horarios, maneja correctamente las transiciones del DST y hace evidente la intención de tu código.
import { DateTime } from 'luxon';
// Parse an ISO string and convert to a specific zone
const utc = DateTime.fromISO('2024-11-03T06:45:00Z');
const eastern = utc.setZone('America/New_York');
console.log(eastern.toLocaleString(DateTime.DATETIME_FULL));
// "November 3, 2024, 1:45 AM EDT"
Cómo manejar husos horarios en Python
Python’s datetime módulo distingue entre naive (sin huso horario) y aware (con huso horario) objetos de fechas. Los objetos naive son una trampa — evítalos en cualquier código que cruce fronteras horarias.
from datetime import datetime, timezone
import zoneinfo # Python 3.9+
# BAD: naive datetime (no timezone info)
d = datetime(2024, 11, 3, 1, 45, 0)
# GOOD: always attach a timezone
d_utc = datetime(2024, 11, 3, 6, 45, 0, tzinfo=timezone.utc)
# Convert to a specific timezone
eastern = zoneinfo.ZoneInfo('America/New_York')
d_eastern = d_utc.astimezone(eastern)
print(d_eastern) # 2024-11-03 01:45:00-05:00
Para Python más antigua o para necesidades más complejas de programación, python-dateutil y Flecha son opciones bien mantenidas. El principio clave permanece igual: trabaja en UTC, convierte en la frontera.
Cómo manejar husos horarios en bases de datos
El manejo de husos horarios en bases de datos confunde incluso a desarrolladores experimentados.
PostgreSQL
PostgreSQL tiene dos tipos de fechas: timestamp (sin huso horario) y timestamptz (con huso horario). A pesar del nombre, timestamptz no almacena realmente el huso horario — se convierte a UTC al escribir y se convierte de nuevo al huso horario de sesión al leer. Ese es el comportamiento correcto. Usa siempre timestamptz.
-- BAD
CREATE TABLE events (created_at TIMESTAMP);
-- GOOD
CREATE TABLE events (created_at TIMESTAMPTZ);
-- Querying across timezones
SELECT created_at AT TIME ZONE 'America/New_York' FROM events;
MySQL
MySQL’s DATETIME que almacena sin contexto de huso horario — lo que pones es lo que obtienes, sin conversión. TIMESTAMP se convierte a UTC al escribir y de nuevo al huso horario del servidor al leer — pero está limitado a fechas entre 1970 y 2038 (el desbordamiento del timestamp de Unix). En la práctica: usa DATETIME columnas y asegúrate de que tu aplicación escriba valores en UTC explícitamente.
Programación acrós husos horarios: la trampa oculta
Supón que un usuario programa una reunión semanal recurrente para «cada lunes a las 9 AM en hora de Nueva York». Almacenas el próximo evento como un timestamp en UTC. Bien — hasta que cambia el DST, y ahora el tiempo UTC que guardaste corresponde a las 10 AM en Nueva York en lugar de las 9 AM.
La solución: no almacenes timestamps absolutos futuros para eventos recurrentes. Almacena la regla local — el identificador de huso horario más la hora local — y calcula el próximo timestamp en UTC en tiempo real. Así, el sistema recalcula correctamente tras transiciones del DST.
-- Store the intent, not the absolute moment
CREATE TABLE recurring_events (
id SERIAL PRIMARY KEY,
timezone TEXT NOT NULL, -- 'America/New_York'
local_time TIME NOT NULL, -- '09:00:00'
recurrence TEXT NOT NULL -- 'WEEKLY:MONDAY'
);
-- Compute next_occurrence_utc in application code at dispatch time
Nombres de husos horarios IANA frente a desplazamientos UTC
Cuando almacenas la preferencia de huso horario de un usuario, almacena el nombre IANA (America/New_York, Europe/London, Asia/Kolkata) — no el desplazamiento UTC (UTC-5, UTC+1). Los desplazamientos son instantáneos; los nombres IANA codifican toda la historia del DST y las reglas futuras.
America/New_York es UTC-5 en invierno y UTC-4 en verano. Si almacenas UTC-5, estás incorporando el desplazamiento incorrecto la mitad del año.
Referencia rápida: las reglas
- Almacena los timestamps en UTC — siempre, sin excepciones en tu base de datos o en tus respuestas de API.
- Usa nombres de huso horario IANA — no desplazamientos UTC — para preferencias de usuarios y para horarios recurrentes.
- Nunca analiza cadenas de fechas sin un huso horario explícito — el comportamiento implícito depende del entorno.
- Convierte a hora local solo en la capa de visualización — no en tu lógica de negocio ni en tus consultas a la base de datos.
- Para horarios recurrentes, almacena la regla — no el tiempo UTC precalculado — para que las transiciones del DST no corrompan los eventos futuros.
- Prueba con casos extremos — la hora de transición del DST, fechas cerca de la línea de fecha internacional y timestamps históricos en regiones que han cambiado su desplazamiento.
Instalar extensiones
Agregue herramientas IO a su navegador favorito para obtener acceso instantáneo y búsquedas más rápidas
恵 ¡El marcador ha llegado!
Marcador es una forma divertida de llevar un registro de tus juegos, todos los datos se almacenan en tu navegador. ¡Próximamente habrá más funciones!
Herramientas clave
Ver todo Los recién llegados
Ver todoActualizar: Nuestro última herramienta fue agregado el 16 de junio de 2026
