Obtener lista de sistemas de calendario disponibles

Descubre qué sistemas de calendario soporta tu entorno JavaScript

Introducción

Al desarrollar aplicaciones para una audiencia global, los usuarios a menudo necesitan ver fechas en su sistema de calendario preferido. Aunque quizás estés familiarizado con el calendario gregoriano utilizado en la mayoría de los países occidentales, muchas culturas utilizan sistemas de calendario completamente diferentes como el calendario islámico Hijri, el calendario hebreo o el calendario budista.

Para permitir que los usuarios seleccionen su calendario preferido, necesitas conocer qué sistemas de calendario soporta el entorno JavaScript. En lugar de mantener una lista codificada que se vuelve obsoleta o incluye valores no compatibles, JavaScript proporciona un método para descubrir los sistemas de calendario disponibles en tiempo de ejecución.

El método Intl.supportedValuesOf() con el parámetro "calendar" devuelve un array con todos los identificadores de sistemas de calendario compatibles con el entorno actual. Esto asegura que tu aplicación solo ofrezca opciones de calendario que funcionen correctamente.

Qué son los sistemas de calendario

Los sistemas de calendario son diferentes métodos para organizar y contar el tiempo. Aunque todos los calendarios registran días, meses y años, utilizan reglas diferentes para calcular cuándo comienza un año, cuánto duran los meses y cómo contabilizar los ciclos astronómicos.

El calendario gregoriano, introducido en 1582, es el calendario civil más utilizado. Utiliza un año solar de aproximadamente 365,25 días, dividido en 12 meses, con años bisiestos añadidos cada cuatro años (con excepciones para los años seculares).

Otros sistemas de calendario siguen reglas diferentes. El calendario islámico es puramente lunar, con meses que siguen las fases de la luna. Esto significa que el año islámico es aproximadamente 11 días más corto que un año solar, lo que hace que las fechas islámicas se desplacen a través de las estaciones con el tiempo. Los calendarios hebreo y chino son lunisolar, combinando meses lunares con ajustes para mantener el calendario sincronizado con el año solar.

Cuando formateas fechas en JavaScript, el sistema de calendario determina qué números de año, mes y día aparecen. El mismo momento en el tiempo tiene diferentes representaciones de fecha en diferentes sistemas de calendario.

Uso de Intl.supportedValuesOf para obtener sistemas de calendario

El método Intl.supportedValuesOf() acepta un parámetro de tipo string que especifica qué tipo de valores devolver. Para obtener sistemas de calendario, pasa "calendar":

const calendars = Intl.supportedValuesOf("calendar");
console.log(calendars);
// Salida: ["buddhist", "chinese", "coptic", "dangi", "ethioaa",
//          "ethiopic", "gregory", "hebrew", "indian", "islamic",
//          "islamic-civil", "islamic-rgsa", "islamic-tbla",
//          "islamic-umalqura", "iso8601", "japanese", "persian", "roc"]

El método devuelve un array de strings que representan identificadores de calendario. Estos identificadores siguen el estándar CLDR (Common Locale Data Repository) de Unicode, que proporciona una forma consistente de referenciar sistemas de calendario en diferentes plataformas y lenguajes de programación.

El array devuelto tiene estas características:

  • Los valores están ordenados alfabéticamente de forma ascendente
  • Los valores duplicados son eliminados
  • Cada identificador utiliza letras minúsculas y guiones
  • La lista incluye todos los sistemas de calendario soportados por la implementación de JavaScript

Diferentes navegadores y entornos JavaScript soportan diferentes conjuntos de calendarios, aunque todos los navegadores modernos soportan un conjunto básico de calendarios comunes.

Comprensión de los identificadores de calendario

Cada identificador de calendario representa un sistema de calendario específico utilizado por una o más culturas. Aquí están los identificadores más comunes:

El identificador "gregory" representa el calendario gregoriano, el calendario civil estándar utilizado en la mayoría de los países. Este es el calendario que utilizas en la vida cotidiana si vives en Estados Unidos, Europa o la mayoría de otras partes del mundo.

El identificador "buddhist" representa el calendario budista tailandés, que utiliza la misma estructura de mes y día que el calendario gregoriano pero cuenta los años desde el nacimiento de Buda (543 a.C. en el calendario gregoriano). El año 2025 en el calendario gregoriano es el año 2568 en el calendario budista.

El identificador "chinese" representa el calendario chino tradicional, un calendario lunisolar donde los meses siguen las fases de la luna y los años se alinean con el período orbital de Júpiter. El calendario chino se utiliza para determinar festividades tradicionales como el Año Nuevo Chino.

El identificador "islamic" representa el calendario islámico Hijri, un calendario puramente lunar con 12 meses de 29 o 30 días. Los años se cuentan desde la Hégira, cuando Mahoma emigró de La Meca a Medina en el 622 d.C.

El identificador "hebrew" representa el calendario hebreo, un calendario lunisolar utilizado para las observancias religiosas judías. Cuenta los años desde una fecha de creación tradicional (3761 a.C. en el calendario gregoriano).

El identificador "japanese" representa el calendario japonés, que utiliza la misma estructura de mes y día que el calendario gregoriano pero divide el tiempo en eras basadas en el emperador reinante. La era actual es Reiwa, que comenzó en 2019.

El identificador "persian" representa el calendario Solar Hijri utilizado en Irán y Afganistán. Es un calendario solar con años contados desde la Hégira, lo que lo hace diferente del calendario lunar islámico.

Otros identificadores incluyen "coptic" (calendario copto ortodoxo), "dangi" (calendario tradicional coreano), "ethiopic" (calendario etíope), "indian" (calendario nacional indio) y "roc" (calendario de la República de China utilizado en Taiwán).

Algunos identificadores tienen variantes como "islamic-civil", "islamic-rgsa", "islamic-tbla" y "islamic-umalqura", que representan diferentes métodos de cálculo para el calendario islámico.

El identificador "iso8601" representa el calendario ISO 8601, que es esencialmente el calendario gregoriano pero siempre utiliza el calendario gregoriano proléptico (extendiendo el calendario gregoriano hacia atrás antes de su introducción en 1582).

Viendo los sistemas de calendario en acción

Para entender cómo los sistemas de calendario afectan al formato de fecha, formatea la misma fecha usando diferentes calendarios:

const date = new Date("2025-10-15");

const gregorian = new Intl.DateTimeFormat("en-US", {
  calendar: "gregory",
  year: "numeric",
  month: "long",
  day: "numeric"
});

const islamic = new Intl.DateTimeFormat("en-US", {
  calendar: "islamic",
  year: "numeric",
  month: "long",
  day: "numeric"
});

const hebrew = new Intl.DateTimeFormat("en-US", {
  calendar: "hebrew",
  year: "numeric",
  month: "long",
  day: "numeric"
});

const buddhist = new Intl.DateTimeFormat("en-US", {
  calendar: "buddhist",
  year: "numeric",
  month: "long",
  day: "numeric"
});

console.log(gregorian.format(date));
// Output: "October 15, 2025"

console.log(islamic.format(date));
// Output: "Rabi' II 16, 1447 AH"

console.log(hebrew.format(date));
// Output: "Tishrei 23, 5786"

console.log(buddhist.format(date));
// Output: "October 15, 2568 BE"

El mismo objeto JavaScript Date representa el mismo momento en el tiempo, pero cada sistema de calendario expresa ese momento con diferentes valores de año, mes y día. La fecha gregoriana 15 de octubre de 2025 corresponde al 16 de Rabi' II de 1447 en el calendario islámico, al 23 de Tishrei de 5786 en el calendario hebreo, y al 15 de octubre de 2568 en el calendario budista.

Esto demuestra por qué es necesario especificar qué sistema de calendario usar al formatear fechas para usuarios que siguen diferentes calendarios.

Construyendo un selector de calendario

Al crear interfaces de usuario que permitan a los usuarios elegir su calendario preferido, consulta los calendarios disponibles y construye un selector dinámicamente:

function buildCalendarSelector() {
  const calendars = Intl.supportedValuesOf("calendar");
  const select = document.createElement("select");
  select.id = "calendar-selector";

  calendars.forEach(calendar => {
    const option = document.createElement("option");
    option.value = calendar;
    option.textContent = calendar;
    select.appendChild(option);
  });

  return select;
}

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

Esto crea un menú desplegable que contiene todos los calendarios compatibles. Sin embargo, los identificadores técnicos como "gregory" e "islamic" no son amigables para el usuario. Los usuarios necesitan ver nombres descriptivos en su propio idioma.

Mostrar nombres de calendario legibles para humanos

La API Intl.DisplayNames convierte los identificadores de calendario en nombres legibles para humanos. Úsala para crear un selector de calendario mejorado:

function buildCalendarSelector(locale = "en-US") {
  const calendars = Intl.supportedValuesOf("calendar");
  const displayNames = new Intl.DisplayNames([locale], { type: "calendar" });

  const select = document.createElement("select");
  select.id = "calendar-selector";

  calendars.forEach(calendar => {
    const option = document.createElement("option");
    option.value = calendar;
    option.textContent = displayNames.of(calendar);
    select.appendChild(option);
  });

  return select;
}

const selector = buildCalendarSelector("en-US");
document.body.appendChild(selector);

Ahora el menú desplegable muestra nombres como "Calendario gregoriano", "Calendario islámico" y "Calendario hebreo" en lugar de identificadores técnicos.

Puedes mostrar los nombres de calendario en diferentes idiomas cambiando la configuración regional:

const calendars = ["gregory", "islamic", "hebrew", "buddhist", "chinese"];

const englishNames = new Intl.DisplayNames(["en-US"], { type: "calendar" });
const frenchNames = new Intl.DisplayNames(["fr-FR"], { type: "calendar" });
const arabicNames = new Intl.DisplayNames(["ar-SA"], { type: "calendar" });

calendars.forEach(calendar => {
  console.log(`${calendar}:`);
  console.log(`  English: ${englishNames.of(calendar)}`);
  console.log(`  French: ${frenchNames.of(calendar)}`);
  console.log(`  Arabic: ${arabicNames.of(calendar)}`);
});

// Resultado:
// gregory:
//   English: Gregorian Calendar
//   French: calendrier grégorien
//   Arabic: التقويم الميلادي
// islamic:
//   English: Islamic Calendar
//   French: calendrier musulman
//   Arabic: التقويم الهجري
// ...

Esto permite a los usuarios ver los nombres de calendario en su idioma preferido.

Comprobar si un calendario específico es compatible

Antes de usar un calendario en tu aplicación, verifica si el entorno JavaScript lo admite. Esto evita errores en tiempo de ejecución y te permite implementar un comportamiento alternativo:

function isCalendarSupported(calendar) {
  const supported = Intl.supportedValuesOf("calendar");
  return supported.includes(calendar);
}

if (isCalendarSupported("islamic")) {
  const formatter = new Intl.DateTimeFormat("en-US", {
    calendar: "islamic",
    year: "numeric",
    month: "long",
    day: "numeric"
  });
  console.log(formatter.format(new Date()));
} else {
  console.log("Islamic calendar is not supported");
}

Este patrón funciona para cualquier identificador de calendario. Puedes usarlo para mostrar u ocultar opciones de calendario en tu interfaz de usuario, o para recurrir a un calendario predeterminado cuando el preferido no está disponible.

Creando una función reutilizable de detección de características

Construye una función genérica para verificar la compatibilidad de calendarios y manejar elegantemente los calendarios faltantes:

function getCalendarOrFallback(preferredCalendar, fallbackCalendar = "gregory") {
  const supported = Intl.supportedValuesOf("calendar");

  if (supported.includes(preferredCalendar)) {
    return preferredCalendar;
  }

  if (supported.includes(fallbackCalendar)) {
    return fallbackCalendar;
  }

  return supported[0];
}

const calendar = getCalendarOrFallback("islamic", "gregory");
const formatter = new Intl.DateTimeFormat("en-US", {
  calendar,
  year: "numeric",
  month: "long",
  day: "numeric"
});

console.log(formatter.format(new Date()));

Esta función intenta usar el calendario preferido, recurre al calendario de respaldo especificado si el preferido no está disponible, y finalmente devuelve el primer calendario disponible si ambos no son compatibles.

Filtrando calendarios para tu aplicación

La mayoría de las aplicaciones no necesitan soportar todos los sistemas de calendario. Filtra la lista para incluir solo los calendarios relevantes para tus usuarios:

function getRelevantCalendars(allowedCalendars) {
  const supported = Intl.supportedValuesOf("calendar");
  return allowedCalendars.filter(calendar => supported.includes(calendar));
}

const allowedCalendars = ["gregory", "islamic", "hebrew", "buddhist"];
const availableCalendars = getRelevantCalendars(allowedCalendars);

console.log(availableCalendars);
// Output: ["gregory", "islamic", "hebrew", "buddhist"]
// (asumiendo que todos son compatibles en el entorno actual)

Esto asegura que solo ofrezcas calendarios que cumplan con tus requisitos y funcionen en el navegador del usuario.

Puedes combinar esto con la selección de calendario para crear una interfaz de usuario enfocada:

function buildFilteredCalendarSelector(allowedCalendars, locale = "en-US") {
  const supported = Intl.supportedValuesOf("calendar");
  const available = allowedCalendars.filter(cal => supported.includes(cal));
  const displayNames = new Intl.DisplayNames([locale], { type: "calendar" });

  const select = document.createElement("select");

  available.forEach(calendar => {
    const option = document.createElement("option");
    option.value = calendar;
    option.textContent = displayNames.of(calendar);
    select.appendChild(option);
  });

  return select;
}

const selector = buildFilteredCalendarSelector(
  ["gregory", "islamic", "hebrew", "buddhist"],
  "en-US"
);
document.body.appendChild(selector);

Esto crea un selector que muestra solo los calendarios que deseas soportar, con nombres legibles para humanos, garantizando que funcionen en el entorno actual.

Agrupación de calendarios por categoría

Para aplicaciones que admiten muchos calendarios, agrúpalos por tipo o región para mejorar la usabilidad:

function groupCalendars() {
  const calendars = Intl.supportedValuesOf("calendar");

  const groups = {
    solar: ["gregory", "iso8601", "persian", "ethiopic", "coptic"],
    lunar: ["islamic", "islamic-civil", "islamic-rgsa", "islamic-tbla", "islamic-umalqura"],
    lunisolar: ["hebrew", "chinese", "dangi"],
    erasBased: ["japanese", "roc", "buddhist"],
    other: []
  };

  const grouped = {
    solar: [],
    lunar: [],
    lunisolar: [],
    erasBased: [],
    other: []
  };

  calendars.forEach(calendar => {
    let placed = false;

    for (const [group, members] of Object.entries(groups)) {
      if (members.includes(calendar)) {
        grouped[group].push(calendar);
        placed = true;
        break;
      }
    }

    if (!placed) {
      grouped.other.push(calendar);
    }
  });

  return grouped;
}

const grouped = groupCalendars();
console.log(grouped);
// Output:
// {
//   solar: ["gregory", "iso8601", "persian", "ethiopic", "coptic"],
//   lunar: ["islamic", "islamic-civil", "islamic-rgsa", ...],
//   lunisolar: ["hebrew", "chinese", "dangi"],
//   erasBased: ["japanese", "roc", "buddhist"],
//   other: ["ethioaa", "indian"]
// }

Esta organización ayuda a los usuarios a comprender las características de los diferentes sistemas de calendario y encontrar el que necesitan.

Manejo de entornos no compatibles

El método Intl.supportedValuesOf() se añadió a JavaScript en 2022. Los navegadores más antiguos no lo admiten. Verifica si el método existe antes de utilizarlo:

function getCalendars() {
  if (typeof Intl.supportedValuesOf === "function") {
    return Intl.supportedValuesOf("calendar");
  }

  return ["gregory"];
}

const calendars = getCalendars();
console.log(calendars);

Esto devuelve la lista completa de calendarios compatibles en navegadores modernos y recurre solo al calendario gregoriano en entornos más antiguos.

Para una mejor compatibilidad con versiones anteriores, proporciona una lista de respaldo más completa:

function getCalendars() {
  if (typeof Intl.supportedValuesOf === "function") {
    return Intl.supportedValuesOf("calendar");
  }

  return [
    "buddhist",
    "chinese",
    "coptic",
    "ethiopic",
    "gregory",
    "hebrew",
    "indian",
    "islamic",
    "japanese",
    "persian",
    "roc"
  ];
}

Esto proporciona un conjunto razonable de calendarios para navegadores más antiguos, aunque no puedes garantizar que todos funcionen en cada entorno.

Comprendiendo la diferencia entre calendario y configuración regional

Calendario y configuración regional son conceptos relacionados pero separados. La configuración regional determina el idioma y las convenciones de formato regionales, mientras que el calendario determina qué sistema de calendario utilizar.

Una sola configuración regional puede usar múltiples calendarios. Por ejemplo, los hablantes de árabe en Arabia Saudita típicamente usan el calendario islámico para propósitos religiosos y el calendario gregoriano para propósitos civiles. Puedes formatear fechas en árabe usando cualquiera de los calendarios:

const date = new Date("2025-10-15");

const arabicGregorian = new Intl.DateTimeFormat("ar-SA", {
  calendar: "gregory",
  year: "numeric",
  month: "long",
  day: "numeric"
});

const arabicIslamic = new Intl.DateTimeFormat("ar-SA", {
  calendar: "islamic",
  year: "numeric",
  month: "long",
  day: "numeric"
});

console.log(arabicGregorian.format(date));
// Output: "١٥ أكتوبر ٢٠٢٥"

console.log(arabicIslamic.format(date));
// Output: "١٦ ربيع الآخر ١٤٤٧ هـ"

Ambos usan texto y numeración árabe, pero muestran diferentes fechas según sus respectivos calendarios.

A la inversa, puedes formatear el mismo calendario en diferentes idiomas:

const date = new Date("2025-10-15");

const englishIslamic = new Intl.DateTimeFormat("en-US", {
  calendar: "islamic",
  year: "numeric",
  month: "long",
  day: "numeric"
});

const arabicIslamic = new Intl.DateTimeFormat("ar-SA", {
  calendar: "islamic",
  year: "numeric",
  month: "long",
  day: "numeric"
});

console.log(englishIslamic.format(date));
// Output: "Rabi' II 16, 1447 AH"

console.log(arabicIslamic.format(date));
// Output: "١٦ ربيع الآخر ١٤٤٧ هـ"

Ambos muestran la fecha islámica, pero utilizan diferentes idiomas y sistemas numéricos.

Cuándo consultar los calendarios disponibles

Consulta los calendarios disponibles en estas situaciones:

Cuando construyas una interfaz de selección de calendario, llama a Intl.supportedValuesOf("calendar") para poblar las opciones. Esto asegura que solo muestres calendarios que funcionen en el entorno actual.

Cuando implementes características basadas en calendarios, verifica si el calendario requerido es compatible antes de usarlo. Esto previene errores y permite una alternativa elegante a calendarios alternativos.

Cuando almacenes preferencias de usuario, valida las selecciones de calendario contra la lista de compatibles. Esto asegura que las preferencias guardadas permanezcan válidas en diferentes dispositivos y navegadores.

Cuando migres entre entornos, verifica la compatibilidad del calendario tanto en el entorno de origen como en el de destino. La compatibilidad de calendarios puede variar entre versiones de navegadores, versiones de Node.js y diferentes entornos de ejecución de JavaScript.

Cuando cargues datos dependientes del calendario, verifica que el calendario esté disponible antes de intentar analizar o formatear fechas. Esto previene errores de ejecución cuando se trabaja con fechas en sistemas de calendario específicos.