Cómo almacenar y gestionar zonas horarias en software

Desarrollador
time-zonesdevelopment

Los errores de zona horaria son algunos de los más difíciles de detectar en el software. Una reunión almacenada como “UTC−5” muestra la hora correcta hoy, pero se desplaza una hora en silencio cuando entra en vigor el horario de verano. La solución es directa una vez que entiendes qué capa gestiona qué.

Nunca almacenes offsets UTC en bruto

Un offset como −5 o +05:30 es una instantánea de la diferencia actual respecto a UTC: no dice nada sobre cuál será ese offset en marzo, ni después de que un gobierno cambie las reglas. Guardar UTC−5 para representar “hora de Nueva York” mostrará la hora incorrecta durante medio año.

No hagas esto:

meeting_time: "2026-03-10T14:00:00-05:00"
user_timezone: "UTC-5"

Almacena nombres de zona horaria IANA

La base de datos de zonas horarias IANA (America/New_York, Europe/London, Asia/Kolkata) codifica el conjunto completo de reglas para una región, incluidas todas las transiciones de horario de verano pasadas y futuras. Todos los lenguajes y entornos de ejecución principales la incluyen.

Haz esto en su lugar:

meeting_time_utc: "2026-03-10T19:00:00Z"   // momento en el tiempo, siempre UTC
user_timezone: "America/New_York"            // conjunto de reglas para la visualización

Almacena el momento en UTC, guarda el nombre IANA del usuario por separado y calcula la hora local en el momento de mostrarla.

Usa las APIs con soporte de zonas horarias de la plataforma

La mayoría de los entornos de ejecución ofrecen una API que acepta nombres IANA. Dales preferencia frente a la aritmética manual de offsets.

JavaScript / TypeScript:

const formatter = new Intl.DateTimeFormat("en-US", {
  timeZone: "America/New_York",
  dateStyle: "full",
  timeStyle: "short",
});
formatter.format(new Date("2026-03-10T19:00:00Z"));
// → "Tuesday, March 10, 2026 at 3:00 PM"

Python:

from zoneinfo import ZoneInfo  # Python 3.9+
from datetime import datetime

utc_dt = datetime(2026, 3, 10, 19, 0, tzinfo=ZoneInfo("UTC"))
ny_dt = utc_dt.astimezone(ZoneInfo("America/New_York"))
# → 2026-03-10 15:00:00-04:00 (EDT, not EST)

PostgreSQL:

-- Almacena como timestamptz (UTC internamente), muestra con AT TIME ZONE
SELECT meeting_at AT TIME ZONE 'America/New_York' FROM meetings;

Valida los nombres IANA procedentes de la entrada del usuario

Si los usuarios pueden introducir o seleccionar su zona horaria, valida el valor contra la base de datos IANA antes de guardarlo. Los nombres no válidos o heredados (US/Eastern en lugar de America/New_York) pueden comportarse de forma inconsistente entre plataformas.

JavaScript:

function isValidIANA(tz: string): boolean {
  try {
    Intl.DateTimeFormat(undefined, { timeZone: tz });
    return true;
  } catch {
    return false;
  }
}

Mantén actualizada la base de datos IANA

La base de datos IANA se actualiza varias veces al año a medida que los gobiernos cambian sus reglas de horario de verano. Los sistemas operativos y los entornos de ejecución distribuyen actualizaciones: mantenlos al día, especialmente en entornos de servidor que no se actualizan automáticamente.

Para proyectos Node.js, los paquetes @js-joda/timezone o luxon incluyen su propia copia de los datos IANA de forma independiente al sistema operativo.

Lista de verificación rápida

  • Almacena las zonas horarias de los usuarios como nombres IANA (America/Chicago), no como offsets (UTC−6)
  • Almacena los momentos en el tiempo como marcas temporales UTC
  • Convierte a hora local en el momento de mostrar, no en el de almacenar
  • Usa las APIs nativas de la plataforma que acepten nombres IANA
  • Valida los nombres IANA procedentes de la entrada del usuario antes de persistirlos
Buy me a coffe