Cómo obtener una 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 construir 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 manualmente una lista de zonas horarias, creas varios problemas.

Primero, la lista queda desactualizada. Las definiciones de zonas horarias cambian cuando los gobiernos modifican las reglas de horario de verano o crean nuevas zonas horarias. Segundo, diferentes entornos JavaScript soportan 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 zonas horarias 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 el entorno actual soporta. Esto asegura 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 zonas horarias y 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. Entender este formato te ayuda a trabajar con zonas horarias de manera efectiva.

Entendiendo el formato de los identificadores de zona horaria IANA

Los identificadores de zona horaria IANA siguen el patrón Área/Ubicación, 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 típicamente representa la ciudad más grande o más representativa en la zona horaria. New York representa la zona horaria del Este de Estados Unidos. Tokyo representa Japón. Sydney 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',    // No "New York"
  'America/Los_Angeles', // No "Los Angeles"
  'Asia/Ho_Chi_Minh'     // No "Ho Chi Minh"
];

Este formato asegura que los identificadores funcionen como tokens únicos sin caracteres especiales que podrían 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 Norteamérica 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 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.

Obtener 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);
// Salida: más de 400

console.log(timeZones.slice(0, 10));
// Salida: [
//   "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 en el 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));
// Salida: "October 15, 2025 at 12:00 PM"

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

Construyendo un selector de zona horaria

El caso de uso más común para obtener todos los identificadores de zona horaria es construir un menú desplegable o elemento 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 soportada. 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 experiencia de usuario deficiente. Los usuarios necesitan entender cómo están organizados los identificadores y encontrar su ubicación rápidamente.

Agrupando 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 agruparlos 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 en la barra diagonal y utiliza la primera parte como clave de región. Esto crea un objeto donde cada región contiene un array de zonas horarias.

Puedes utilizar 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.

Filtrado de 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: más de 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 comiencen con la región especificada. Puedes llamarla con cualquier nombre de región para obtener una lista específica.

Puedes filtrar por 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: más de 200

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

Búsqueda de zonas horarias específicas

Cuando los usuarios conocen la ciudad que están buscando, la búsqueda 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 zonas horarias. 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 utilizado en los identificadores de zonas horarias.

Validación de identificadores de zona horaria

Cuando los usuarios proporcionan identificadores de zona horaria como entrada, es necesario 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 comprueba 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. Utiliza la comprobación de valores soportados cuando el rendimiento sea importante.

Mostrar desplazamientos actuales para zonas horarias

Los usuarios a menudo piensan en las zonas horarias en términos de su desplazamiento desde UTC. Mostrar el desplazamiento actual junto con cada nombre de zona horaria ayuda a los usuarios a entender 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 de desplazamiento de las partes formateadas. Esto muestra cuántas horas por delante o por detrás de UTC está cada zona horaria.

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

const newYorkWinter = getTimeZoneOffset('America/New_York');
// En enero: GMT-5

const newYorkSummer = getTimeZoneOffset('America/New_York');
// En julio: GMT-4

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

Construyendo un selector de zona horaria completo con desplazamientos

Combinar agrupación, filtrado y visualización de desplazamientos 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 zonas horarias por región, muestra nombres de ubicación legibles e incluye desplazamientos UTC actuales. Los usuarios pueden encontrar rápidamente su zona horaria por región y verificar que el desplazamiento coincida con sus expectativas.

Obteniendo la zona horaria actual del usuario

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

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

const userTimeZone = getUserTimeZone();
console.log(userTimeZone);
// Salida: "America/New_York" (o la zona horaria real del usuario)

Esto devuelve el identificador IANA para 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.

Manejo de zonas horarias especiales

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

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

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

El identificador UTC representa el Tiempo Universal Coordinado, que no tiene desplazamiento ni cambios por 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);
// Resultado: más de 400

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

Entendiendo 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 ambos se refieren 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, sigue funcionando 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));
// Resultado: hora en Hora Estándar de India

console.log(aliasFormatter.format(date));
// Resultado: hora en Hora Estándar de India

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

Sin embargo, la lista de valores compatibles 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'));
// Resultado: "Asia/Kolkata"

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

console.log(normalizeTimeZone('Invalid/Zone'));
// Resultado: 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 de navegadores

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 disponibilidad del método 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 comprueba si Intl.supportedValuesOf existe y devuelve la lista completa si está disponible. Si no, devuelve una lista predefinida más pequeña de zonas horarias comunes. La alternativa asegura que tu aplicación funcione en entornos más antiguos mientras proporciona la lista completa en los modernos.