Cómo obtener la lista de identificadores de zona horaria válidos

Recupera todos los identificadores de zona horaria IANA compatibles en JavaScript para crear menús desplegables y validar la entrada del usuario

Introducción

Al crear funcionalidades que permiten a los usuarios seleccionar su zona horaria, necesitas saber qué identificadores de zona horaria son válidos. Un usuario en Nueva York podría necesitar elegir America/New_York, mientras que un usuario en Tokio necesita Asia/Tokyo. Si codificas una lista de zonas horarias de forma fija, creas varios problemas.

Primero, la lista queda obsoleta. Las definiciones de zona horaria cambian cuando los gobiernos modifican las reglas de horario de verano o crean nuevas zonas horarias. Segundo, diferentes entornos JavaScript admiten diferentes zonas horarias. Una zona horaria que funciona en Chrome podría no funcionar en un navegador más antiguo o en una versión de Node.js. Tercero, mantener cientos de cadenas de zona horaria manualmente crea oportunidades para errores tipográficos e inconsistencias.

JavaScript proporciona el método Intl.supportedValuesOf() para recuperar todos los identificadores de zona horaria que admite el entorno actual. Esto garantiza que tu aplicación solo ofrezca zonas horarias que funcionen correctamente y se mantenga actualizada con los cambios en la base de datos de zonas horarias.

Qué son los identificadores de zona horaria

Los identificadores de zona horaria son cadenas estandarizadas que representan regiones geográficas con reglas de tiempo consistentes. Provienen de la base de datos de zonas horarias IANA, una lista completa mantenida por una organización internacional que rastrea las zonas horarias y los cambios de horario de verano en todo el mundo.

Los identificadores utilizan un formato específico que los hace inequívocos y estables en diferentes sistemas. Comprender este formato te ayuda a trabajar con zonas horarias de manera efectiva.

Comprender el formato de los identificadores de zona horaria IANA

Los identificadores de zona horaria IANA siguen el patrón Area/Location, donde el área representa un continente u océano y la ubicación representa una ciudad o región dentro de esa área.

const examples = [
  'America/New_York',
  'Europe/London',
  'Asia/Tokyo',
  'Australia/Sydney',
  'Pacific/Auckland'
];

El área corresponde a:

  • America para América del Norte y del Sur
  • Europe para ubicaciones europeas
  • Asia para ubicaciones asiáticas
  • Africa para ubicaciones africanas
  • Australia para ubicaciones australianas
  • Pacific para islas del Pacífico
  • Atlantic para islas del Atlántico
  • Indian para islas del océano Índico
  • Antarctica para estaciones de investigación antárticas

La ubicación normalmente representa la ciudad más grande o más representativa de la zona horaria. Nueva York representa la zona horaria del este de Estados Unidos. Tokio representa Japón. Sídney representa la zona horaria del este de Australia.

Algunos identificadores incluyen tres partes para regiones dentro de un área más grande:

const detailedExamples = [
  'America/Indiana/Indianapolis',
  'America/Kentucky/Louisville',
  'America/North_Dakota/Center'
];

Estos identificadores de varias partes distinguen regiones que siguen diferentes reglas horarias dentro del mismo país.

La base de datos utiliza guiones bajos en lugar de espacios en los nombres de ciudades:

const underscoreExamples = [
  'America/New_York',    // Not "New York"
  'America/Los_Angeles', // Not "Los Angeles"
  'Asia/Ho_Chi_Minh'     // Not "Ho Chi Minh"
];

Este formato garantiza que los identificadores funcionen como tokens únicos sin caracteres especiales que puedan causar problemas de análisis.

Por qué los identificadores usan ciudades en lugar de abreviaturas

Podrías esperar usar abreviaturas como EST para Eastern Standard Time o PST para Pacific Standard Time. Sin embargo, estas abreviaturas son ambiguas. EST significa Eastern Standard Time en América del Norte pero también significa Australian Eastern Standard Time. CST podría significar Central Standard Time, China Standard Time o Cuba Standard Time.

Los identificadores basados en ciudades permanecen inequívocos. America/New_York siempre se refiere al mismo lugar y las mismas reglas horarias, independientemente del contexto.

Además, las abreviaturas no capturan las transiciones de horario de verano. EST solo representa el horario estándar, no EDT (Eastern Daylight Time). El identificador America/New_York maneja automáticamente tanto el horario estándar como el de verano según la fecha.

Obtención de todos los identificadores de zona horaria compatibles

El método Intl.supportedValuesOf() con el parámetro 'timeZone' devuelve un array de todos los identificadores de zona horaria compatibles con el entorno JavaScript.

const timeZones = Intl.supportedValuesOf('timeZone');

console.log(timeZones.length);
// Output: over 400

console.log(timeZones.slice(0, 10));
// Output: [
//   "Africa/Abidjan",
//   "Africa/Accra",
//   "Africa/Addis_Ababa",
//   "Africa/Algiers",
//   "Africa/Asmera",
//   "Africa/Bamako",
//   "Africa/Bangui",
//   "Africa/Banjul",
//   "Africa/Bissau",
//   "Africa/Blantyre"
// ]

El método devuelve los identificadores en orden alfabético sin duplicados. La lista exacta depende del entorno JavaScript, pero los navegadores modernos y las versiones de Node.js admiten más de 400 zonas horarias.

Cada identificador del array puede usarse con Intl.DateTimeFormat para formatear fechas y horas para esa zona horaria:

const timeZone = timeZones[0]; // "Africa/Abidjan"
const date = new Date('2025-10-15T12:00:00Z');

const formatter = new Intl.DateTimeFormat('en-US', {
  timeZone: timeZone,
  dateStyle: 'long',
  timeStyle: 'short'
});

console.log(formatter.format(date));
// Output: "October 15, 2025 at 12:00 PM"

El método garantiza que cada identificador que devuelve funciona correctamente con las APIs Intl.

Construcción de un selector de zona horaria

El caso de uso más común para obtener todos los identificadores de zona horaria es construir un elemento desplegable o select que permita a los usuarios elegir su zona horaria.

function buildTimeZoneSelector() {
  const timeZones = Intl.supportedValuesOf('timeZone');
  const select = document.createElement('select');
  select.name = 'timeZone';

  timeZones.forEach(timeZone => {
    const option = document.createElement('option');
    option.value = timeZone;
    option.textContent = timeZone;
    select.appendChild(option);
  });

  return select;
}

const selector = buildTimeZoneSelector();
document.body.appendChild(selector);

Esto crea un elemento select con opciones para cada zona horaria compatible. Los usuarios pueden desplazarse por la lista y seleccionar su ubicación.

Sin embargo, una lista de más de 400 identificadores sin ordenar crea una mala experiencia de usuario. Los usuarios necesitan entender cómo están organizados los identificadores y encontrar su ubicación rápidamente.

Agrupación de zonas horarias por región

Organizar las zonas horarias por continente hace que la lista sea más fácil de navegar. Puedes extraer la región de cada identificador y agruparlas en consecuencia.

function groupTimeZonesByRegion() {
  const timeZones = Intl.supportedValuesOf('timeZone');
  const grouped = {};

  timeZones.forEach(timeZone => {
    const parts = timeZone.split('/');
    const region = parts[0];

    if (!grouped[region]) {
      grouped[region] = [];
    }

    grouped[region].push(timeZone);
  });

  return grouped;
}

const grouped = groupTimeZonesByRegion();

console.log(Object.keys(grouped));
// Output: [
//   "Africa", "America", "Antarctica", "Arctic",
//   "Asia", "Atlantic", "Australia", "Europe",
//   "Indian", "Pacific", "Etc"
// ]

console.log(grouped['America'].slice(0, 5));
// Output: [
//   "America/Adak",
//   "America/Anchorage",
//   "America/Anguilla",
//   "America/Antigua",
//   "America/Araguaina"
// ]

La función divide cada identificador por la barra diagonal y usa la primera parte como clave de región. Esto crea un objeto donde cada región contiene un array de zonas horarias.

Puedes usar estos datos agrupados para construir un selector más organizado con elementos optgroup:

function buildGroupedTimeZoneSelector() {
  const grouped = groupTimeZonesByRegion();
  const select = document.createElement('select');
  select.name = 'timeZone';

  Object.keys(grouped).sort().forEach(region => {
    const optgroup = document.createElement('optgroup');
    optgroup.label = region;

    grouped[region].forEach(timeZone => {
      const option = document.createElement('option');
      option.value = timeZone;
      option.textContent = timeZone.split('/').slice(1).join('/');
      optgroup.appendChild(option);
    });

    select.appendChild(optgroup);
  });

  return select;
}

const groupedSelector = buildGroupedTimeZoneSelector();
document.body.appendChild(groupedSelector);

Esto crea un elemento select donde las zonas horarias aparecen bajo sus encabezados regionales. El texto de la opción muestra solo la porción de ciudad del identificador, haciendo la lista más legible.

Filtrando zonas horarias por región

A veces solo necesitas zonas horarias de regiones específicas. Por ejemplo, una aplicación que sirve únicamente a usuarios de Norteamérica podría mostrar solo zonas horarias americanas.

function getTimeZonesForRegion(region) {
  const timeZones = Intl.supportedValuesOf('timeZone');
  return timeZones.filter(timeZone => timeZone.startsWith(`${region}/`));
}

const americanTimeZones = getTimeZonesForRegion('America');
console.log(americanTimeZones.length);
// Output: over 150

console.log(americanTimeZones.slice(0, 5));
// Output: [
//   "America/Adak",
//   "America/Anchorage",
//   "America/Anguilla",
//   "America/Antigua",
//   "America/Araguaina"
// ]

Esta función filtra la lista completa para incluir solo identificadores que comienzan con la región especificada. Puedes llamarla con cualquier nombre de región para obtener una lista enfocada.

Puedes filtrar para múltiples regiones:

function getTimeZonesForRegions(regions) {
  const timeZones = Intl.supportedValuesOf('timeZone');
  return timeZones.filter(timeZone => {
    return regions.some(region => timeZone.startsWith(`${region}/`));
  });
}

const europeanAndAsianTimeZones = getTimeZonesForRegions(['Europe', 'Asia']);
console.log(europeanAndAsianTimeZones.length);
// Output: over 200

Esto proporciona flexibilidad para aplicaciones que sirven a múltiples regiones, pero no a todas.

Buscando zonas horarias específicas

Cuando los usuarios conocen la ciudad que están buscando, buscar por nombre les ayuda a encontrarla rápidamente.

function searchTimeZones(query) {
  const timeZones = Intl.supportedValuesOf('timeZone');
  const lowerQuery = query.toLowerCase();

  return timeZones.filter(timeZone => {
    return timeZone.toLowerCase().includes(lowerQuery);
  });
}

const newYorkResults = searchTimeZones('new_york');
console.log(newYorkResults);
// Output: ["America/New_York"]

const londonResults = searchTimeZones('london');
console.log(londonResults);
// Output: ["Europe/London"]

const tokyoResults = searchTimeZones('tokyo');
console.log(tokyoResults);
// Output: ["Asia/Tokyo"]

Esta función realiza una búsqueda sin distinción entre mayúsculas y minúsculas en todos los identificadores de zona horaria. Los usuarios pueden escribir parte del nombre de una ciudad para encontrar zonas horarias coincidentes.

Para una mejor experiencia de usuario, puedes buscar coincidencias parciales y manejar espacios:

function searchTimeZonesFlexible(query) {
  const timeZones = Intl.supportedValuesOf('timeZone');
  const normalizedQuery = query.toLowerCase().replace(/\s+/g, '_');

  return timeZones.filter(timeZone => {
    return timeZone.toLowerCase().includes(normalizedQuery);
  });
}

const results = searchTimeZonesFlexible('new york');
console.log(results);
// Output: ["America/New_York"]

Esta versión convierte los espacios en la consulta a guiones bajos, coincidiendo con el formato usado en los identificadores de zona horaria.

Validando identificadores de zona horaria

Cuando los usuarios proporcionan identificadores de zona horaria como entrada, necesitas verificar que el identificador sea válido antes de usarlo con Intl.DateTimeFormat.

function isValidTimeZone(timeZone) {
  const supportedTimeZones = Intl.supportedValuesOf('timeZone');
  return supportedTimeZones.includes(timeZone);
}

console.log(isValidTimeZone('America/New_York'));
// Output: true

console.log(isValidTimeZone('Europe/London'));
// Output: true

console.log(isValidTimeZone('Invalid/TimeZone'));
// Output: false

console.log(isValidTimeZone('EST'));
// Output: false

Esta función verifica si una cadena dada aparece en la lista de zonas horarias soportadas. Si el identificador no es válido, puedes rechazarlo o solicitar al usuario que elija entre opciones válidas.

También puedes intentar usar el identificador y capturar errores:

function validateTimeZoneByCatch(timeZone) {
  try {
    new Intl.DateTimeFormat('en-US', { timeZone });
    return true;
  } catch (error) {
    return false;
  }
}

console.log(validateTimeZoneByCatch('America/New_York'));
// Output: true

console.log(validateTimeZoneByCatch('Invalid/TimeZone'));
// Output: false

Este enfoque funciona pero es menos eficiente que verificar la lista de valores soportados. Usa la verificación de valores soportados cuando el rendimiento importa.

Mostrando los desfases actuales de las zonas horarias

Los usuarios suelen pensar en las zonas horarias en términos de su desfase respecto a UTC. Mostrar el desfase actual junto al nombre de cada zona horaria ayuda a los usuarios a comprender la diferencia horaria.

function getTimeZoneOffset(timeZone) {
  const date = new Date();
  const formatter = new Intl.DateTimeFormat('en-US', {
    timeZone,
    timeZoneName: 'shortOffset'
  });

  const parts = formatter.formatToParts(date);
  const offsetPart = parts.find(part => part.type === 'timeZoneName');

  return offsetPart ? offsetPart.value : '';
}

const timeZones = [
  'America/New_York',
  'Europe/London',
  'Asia/Tokyo',
  'Australia/Sydney'
];

timeZones.forEach(timeZone => {
  const offset = getTimeZoneOffset(timeZone);
  console.log(`${timeZone}: ${offset}`);
});

// Output:
// America/New_York: GMT-4
// Europe/London: GMT+1
// Asia/Tokyo: GMT+9
// Australia/Sydney: GMT+11

La función formatea una fecha con el estilo de nombre de zona horaria shortOffset, luego extrae la porción del desfase de las partes formateadas. Esto muestra cuántas horas adelante o atrás de UTC está cada zona horaria.

Ten en cuenta que los desfases cambian con el horario de verano. La misma zona horaria muestra diferentes desfases en invierno y verano:

const newYorkWinter = getTimeZoneOffset('America/New_York');
// In January: GMT-5

const newYorkSummer = getTimeZoneOffset('America/New_York');
// In July: GMT-4

El desfase devuelto por esta función refleja la fecha actual, por lo que se actualiza automáticamente a medida que las reglas del horario de verano cambian a lo largo del año.

Construyendo un selector completo de zona horaria con desfases

Combinar agrupación, filtrado y visualización de desfases crea un selector de zona horaria completo:

function buildCompleteTimeZoneSelector() {
  const timeZones = Intl.supportedValuesOf('timeZone');
  const select = document.createElement('select');
  select.name = 'timeZone';

  const grouped = {};
  timeZones.forEach(timeZone => {
    const region = timeZone.split('/')[0];
    if (!grouped[region]) {
      grouped[region] = [];
    }
    grouped[region].push(timeZone);
  });

  Object.keys(grouped).sort().forEach(region => {
    const optgroup = document.createElement('optgroup');
    optgroup.label = region;

    grouped[region].forEach(timeZone => {
      const offset = getTimeZoneOffset(timeZone);
      const location = timeZone.split('/').slice(1).join('/');

      const option = document.createElement('option');
      option.value = timeZone;
      option.textContent = `${location} (${offset})`;
      optgroup.appendChild(option);
    });

    select.appendChild(optgroup);
  });

  return select;
}

const completeSelector = buildCompleteTimeZoneSelector();
document.body.appendChild(completeSelector);

Este selector agrupa las zonas horarias por región, muestra nombres de ubicación legibles e incluye los desfases UTC actuales. Los usuarios pueden encontrar rápidamente su zona horaria por región y verificar que el desfase coincida con sus expectativas.

Obteniendo la zona horaria actual del usuario

Si bien obtener todas las zonas horarias compatibles es útil para interfaces de selección, a menudo quieres conocer la zona horaria actual del usuario para usarla como predeterminada.

function getUserTimeZone() {
  return Intl.DateTimeFormat().resolvedOptions().timeZone;
}

const userTimeZone = getUserTimeZone();
console.log(userTimeZone);
// Output: "America/New_York" (or user's actual time zone)

Esto devuelve el identificador IANA de la zona horaria del sistema del usuario. Puedes usar esto para preseleccionar la opción correcta en un selector de zona horaria:

function buildTimeZoneSelectorWithDefault() {
  const selector = buildCompleteTimeZoneSelector();
  const userTimeZone = getUserTimeZone();

  const options = selector.querySelectorAll('option');
  options.forEach(option => {
    if (option.value === userTimeZone) {
      option.selected = true;
    }
  });

  return selector;
}

const selectorWithDefault = buildTimeZoneSelectorWithDefault();
document.body.appendChild(selectorWithDefault);

Esto crea un selector con la zona horaria actual del usuario ya seleccionada, reduciendo la fricción cuando los usuarios confirman su ubicación.

Manejando zonas horarias especiales

La lista de zonas horarias compatibles incluye algunos identificadores especiales que no siguen el patrón estándar Area/Location.

const timeZones = Intl.supportedValuesOf('timeZone');

const specialTimeZones = timeZones.filter(tz => !tz.includes('/'));
console.log(specialTimeZones);
// Output: ["UTC"]

El identificador UTC representa el tiempo universal coordinado, que no tiene desplazamiento ni cambios de horario de verano. Este identificador es útil cuando deseas mostrar horas en un marco de referencia universal en lugar de una zona horaria local.

Algunos entornos incluyen identificadores especiales adicionales como GMT o desplazamientos de zona como Etc/GMT+5. Puedes filtrarlos si tu aplicación solo necesita zonas horarias geográficas estándar:

function getGeographicTimeZones() {
  const timeZones = Intl.supportedValuesOf('timeZone');
  return timeZones.filter(timeZone => {
    return timeZone.includes('/') && !timeZone.startsWith('Etc/');
  });
}

const geographicTimeZones = getGeographicTimeZones();
console.log(geographicTimeZones.length);
// Output: over 400

Esto filtra los identificadores no geográficos, dejando solo las zonas horarias estándar basadas en ciudades.

Comprender los alias de zonas horarias

La base de datos IANA incluye múltiples identificadores que se refieren a las mismas reglas de zona horaria. Por ejemplo, Asia/Calcutta y Asia/Kolkata se refieren ambos a la hora estándar de India, pero Kolkata es el nombre moderno.

El método Intl.supportedValuesOf() devuelve los identificadores canónicos. Si los usuarios proporcionan un alias, aún funciona con Intl.DateTimeFormat:

const canonicalFormatter = new Intl.DateTimeFormat('en-US', {
  timeZone: 'Asia/Kolkata',
  timeZoneName: 'long'
});

const aliasFormatter = new Intl.DateTimeFormat('en-US', {
  timeZone: 'Asia/Calcutta',
  timeZoneName: 'long'
});

const date = new Date('2025-10-15T12:00:00Z');

console.log(canonicalFormatter.format(date));
// Output: time in Indian Standard Time

console.log(aliasFormatter.format(date));
// Output: time in Indian Standard Time

Ambos formateadores producen el mismo resultado porque el alias se asigna internamente al identificador canónico.

Sin embargo, la lista de valores admitidos solo incluye identificadores canónicos. Si estás validando la entrada del usuario, considera normalizar los alias a sus formas canónicas:

function normalizeTimeZone(timeZone) {
  try {
    const formatter = new Intl.DateTimeFormat('en-US', { timeZone });
    return formatter.resolvedOptions().timeZone;
  } catch (error) {
    return null;
  }
}

console.log(normalizeTimeZone('Asia/Calcutta'));
// Output: "Asia/Kolkata"

console.log(normalizeTimeZone('America/New_York'));
// Output: "America/New_York"

console.log(normalizeTimeZone('Invalid/Zone'));
// Output: null

Esta función crea un formateador con la zona horaria proporcionada y extrae el identificador canónico de las opciones resueltas. Si el identificador no es válido, el formateador lanza un error y la función devuelve null.

Compatibilidad y soporte del navegador

El método Intl.supportedValuesOf() está disponible en navegadores modernos y versiones de Node.js:

  • Chrome 99 y posteriores
  • Firefox 93 y posteriores
  • Safari 15.4 y posteriores
  • Edge 99 y posteriores
  • Node.js 18.0.0 y posteriores

Para entornos más antiguos, puedes detectar la función y proporcionar una alternativa:

function getSupportedTimeZones() {
  if (typeof Intl.supportedValuesOf === 'function') {
    return Intl.supportedValuesOf('timeZone');
  }

  return [
    'Africa/Cairo',
    'America/New_York',
    'America/Chicago',
    'America/Denver',
    'America/Los_Angeles',
    'Asia/Dubai',
    'Asia/Kolkata',
    'Asia/Tokyo',
    'Australia/Sydney',
    'Europe/London',
    'Europe/Paris',
    'Pacific/Auckland',
    'UTC'
  ];
}

const timeZones = getSupportedTimeZones();

Esta función verifica si Intl.supportedValuesOf existe y devuelve la lista completa si está disponible. Si no, devuelve una lista más pequeña de zonas horarias comunes codificadas. El respaldo garantiza que tu aplicación funcione en entornos más antiguos mientras proporciona la lista completa en los modernos.