¿Cómo formatear fechas en diferentes sistemas de calendario?
Utiliza la opción de calendario de JavaScript para mostrar fechas en sistemas de calendario islámico, hebreo, japonés, chino y otros para usuarios de todo el mundo
Introducción
La mayoría de los desarrolladores asumen que las fechas funcionan igual en todas partes. Creas un objeto Date para el 15 de marzo de 2025, lo formateas y lo muestras a los usuarios. Sin embargo, esta suposición falla cuando tus usuarios siguen diferentes sistemas de calendario.
En muchas culturas, la fecha 15 de marzo de 2025 en el calendario gregoriano tiene una representación completamente diferente. Para los usuarios que siguen el calendario islámico, ese mismo momento ocurre el 16 de Ramadán de 1447. Para los usuarios del calendario hebreo, cae el 14 de Adar II de 5785. Para los usuarios japoneses en contextos oficiales, aparece como 15 de marzo, Reiwa 7.
Los sistemas de calendario determinan cómo las sociedades cuentan el tiempo. Definen cuándo comienzan los años, cómo se organizan los meses y cómo se numeran las fechas. La API Intl.DateTimeFormat de JavaScript admite más de 17 sistemas de calendario diferentes, permitiéndote mostrar fechas según el contexto cultural y religioso de cada usuario.
Esta lección explica qué son los sistemas de calendario, por qué existen y cómo formatear fechas usando diferentes sistemas de calendario en JavaScript.
Qué son los sistemas de calendario
Un sistema de calendario define las reglas para organizar y contar el tiempo. Cada sistema establece cuándo comienza el año, cuántos meses existen, cómo se numeran los días y qué época sirve como punto de partida para la numeración de los años.
El calendario gregoriano, ampliamente utilizado en contextos internacionales, cuenta los años desde el nacimiento estimado de Jesucristo. Utiliza 12 meses con duraciones que van desde 28 hasta 31 días, creando un año de 365 días con años bisiestos cada cuatro años.
Otros sistemas de calendario utilizan diferentes estructuras y puntos de partida. El calendario islámico usa 12 meses lunares que suman 354 o 355 días por año. El calendario hebreo combina meses lunares con alineación al año solar. El calendario japonés utiliza nombres de era que cambian con el reinado de cada emperador.
Estos sistemas existen porque diferentes culturas desarrollaron sus propias formas de seguir el tiempo basadas en significados religiosos, observaciones astronómicas y eventos históricos. Muchas culturas continúan usando calendarios tradicionales junto con el calendario gregoriano para celebraciones religiosas, documentos oficiales y eventos culturales.
Por qué los sistemas de calendario son importantes para las aplicaciones
Las aplicaciones que atienden a usuarios de diferentes orígenes culturales necesitan mostrar fechas en formatos que estos usuarios entiendan y esperen. Una aplicación de horarios de oración para usuarios musulmanes debe mostrar fechas en el calendario islámico. Una aplicación para observancias religiosas judías necesita fechas del calendario hebreo. Las aplicaciones relacionadas con el gobierno japonés requieren el formato de era japonesa.
Usar el sistema de calendario incorrecto crea confusión y puede hacer que tu aplicación sea inutilizable para su audiencia prevista. Mostrar fechas de festividades islámicas en el calendario gregoriano obliga a los usuarios a convertir fechas manualmente. Mostrar eventos del calendario hebreo en formato gregoriano oculta el significado religioso de esas fechas.
El mismo objeto Date representa el mismo momento en el tiempo independientemente del sistema de calendario. Lo que cambia es cómo formateas ese momento para mostrarlo. JavaScript te permite formatear cualquier fecha en cualquier sistema de calendario compatible sin lógica de conversión compleja.
Usando la opción de calendario
El constructor Intl.DateTimeFormat acepta una opción calendar que especifica qué sistema de calendario usar al formatear fechas. Pasa el identificador del calendario como un valor de cadena.
const date = new Date('2025-03-15');
const gregorianFormatter = new Intl.DateTimeFormat('en-US', {
calendar: 'gregory',
dateStyle: 'long'
});
const islamicFormatter = new Intl.DateTimeFormat('en-US', {
calendar: 'islamic',
dateStyle: 'long'
});
console.log(gregorianFormatter.format(date));
// Output: "March 15, 2025"
console.log(islamicFormatter.format(date));
// Output: "Ramadan 16, 1447 AH"
El mismo objeto Date produce diferentes cadenas formateadas según el sistema de calendario. El calendario gregoriano muestra el 15 de marzo de 2025. El calendario islámico muestra el 16 de Ramadán de 1447 AH.
La opción de calendario funciona independientemente del idioma. Puedes formatear fechas islámicas en inglés, árabe, francés o cualquier otro idioma combinando la opción de calendario con el idioma apropiado.
const date = new Date('2025-03-15');
const arabicFormatter = new Intl.DateTimeFormat('ar-SA', {
calendar: 'islamic',
dateStyle: 'long'
});
const englishFormatter = new Intl.DateTimeFormat('en-US', {
calendar: 'islamic',
dateStyle: 'long'
});
console.log(arabicFormatter.format(date));
// Output: "١٦ رمضان ١٤٤٧ هـ"
console.log(englishFormatter.format(date));
// Output: "Ramadan 16, 1447 AH"
El sistema de calendario determina qué fecha mostrar, mientras que el idioma determina el lenguaje y las convenciones de formato.
Formateo de fechas con el calendario islámico
El calendario islámico es un calendario lunar que contiene 12 meses de 29 o 30 días. Un año lunar completo tiene aproximadamente 354 días, lo que es de 10 a 11 días más corto que el año gregoriano solar. Esto hace que las fechas islámicas se desplacen hacia atrás a través del calendario gregoriano con el tiempo.
JavaScript admite múltiples variantes del calendario islámico. El identificador islamic utiliza un cálculo basado en algoritmos. El identificador islamic-umalqura utiliza el calendario Umm al-Qura usado en Arabia Saudita. El identificador islamic-civil utiliza un cálculo tabular predecible.
const date = new Date('2025-03-15');
const islamicFormatter = new Intl.DateTimeFormat('en-US', {
calendar: 'islamic',
year: 'numeric',
month: 'long',
day: 'numeric'
});
const umalquraFormatter = new Intl.DateTimeFormat('en-US', {
calendar: 'islamic-umalqura',
year: 'numeric',
month: 'long',
day: 'numeric'
});
console.log(islamicFormatter.format(date));
// Output: "Ramadan 16, 1447 AH"
console.log(umalquraFormatter.format(date));
// Output: "Ramadan 16, 1447 AH"
Para la mayoría de las aplicaciones que sirven a usuarios musulmanes, cualquiera de estas variantes del calendario islámico funciona correctamente. Las diferencias entre ellas son pequeñas y principalmente importan para determinar fechas exactas de observancias religiosas.
Formateo de fechas con el calendario hebreo
El calendario hebreo es un calendario lunisolar utilizado para las observancias religiosas judías. Sincroniza los meses lunares con el año solar añadiendo un mes bisiesto en ciertos años. Esto mantiene las festividades alineadas con las estaciones.
const date = new Date('2025-03-15');
const hebrewFormatter = new Intl.DateTimeFormat('en-US', {
calendar: 'hebrew',
year: 'numeric',
month: 'long',
day: 'numeric'
});
console.log(hebrewFormatter.format(date));
// Output: "14 Adar II 5785"
El calendario hebreo utiliza nombres de meses hebreos como Nisan, Iyar, Sivan y Tammuz. En años bisiestos, el calendario incluye Adar I y Adar II. El conteo de años representa los años desde la creación según la tradición judía.
Puedes formatear fechas hebreas en idioma hebreo para hablantes nativos.
const date = new Date('2025-03-15');
const hebrewFormatter = new Intl.DateTimeFormat('he-IL', {
calendar: 'hebrew',
year: 'numeric',
month: 'long',
day: 'numeric'
});
console.log(hebrewFormatter.format(date));
// Output: "י״ד באדר ב׳ ה׳תשפ״ה"
La salida en idioma hebreo utiliza letras hebreas para números y escritura hebrea para los nombres de los meses.
Formateo de fechas con el calendario japonés
El calendario japonés utiliza nombres de eras basados en el emperador reinante. La era actual, Reiwa, comenzó el 1 de mayo de 2019, cuando el Emperador Naruhito ascendió al trono. Los años se numeran desde el inicio de cada era.
const date = new Date('2025-03-15');
const japaneseFormatter = new Intl.DateTimeFormat('en-US', {
calendar: 'japanese',
year: 'numeric',
month: 'long',
day: 'numeric'
});
console.log(japaneseFormatter.format(date));
// Output: "March 15, 7 Reiwa"
El año aparece como 7 Reiwa, indicando el séptimo año de la era Reiwa. Este formato se utiliza en documentos oficiales japoneses, formularios gubernamentales y contextos formales.
El formateo en idioma japonés produce el formato de fecha tradicional japonés.
const date = new Date('2025-03-15');
const japaneseFormatter = new Intl.DateTimeFormat('ja-JP', {
calendar: 'japanese',
era: 'long',
year: 'numeric',
month: 'long',
day: 'numeric'
});
console.log(japaneseFormatter.format(date));
// Output: "令和7年3月15日"
La salida muestra el nombre de la era (令和), año (7年), mes (3月) y día (15日) utilizando caracteres japoneses.
Formateo de fechas con el calendario chino
El calendario chino es un calendario lunisolar utilizado para determinar festividades tradicionales chinas como el Año Nuevo Chino y el Festival del Medio Otoño. El calendario combina meses lunares con términos solares.
const date = new Date('2025-03-15');
const chineseFormatter = new Intl.DateTimeFormat('en-US', {
calendar: 'chinese',
year: 'numeric',
month: 'long',
day: 'numeric'
});
console.log(chineseFormatter.format(date));
// Output: "Second Month 16, 2025(yi-si)"
El año del calendario chino incluye un nombre cíclico (yi-si en este caso) junto con el año numérico. Los nombres de los meses utilizan designaciones numéricas como "Primer Mes" y "Segundo Mes".
El formateo en idioma chino muestra la fecha utilizando caracteres chinos.
const date = new Date('2025-03-15');
const chineseFormatter = new Intl.DateTimeFormat('zh-CN', {
calendar: 'chinese',
year: 'numeric',
month: 'long',
day: 'numeric'
});
console.log(chineseFormatter.format(date));
// Output: "2025乙巳年二月十六"
Formateo de fechas con el calendario persa
El calendario persa, también llamado calendario Solar Hijri, es el calendario oficial de Irán y Afganistán. Utiliza un año solar con 12 meses, similar en estructura al calendario gregoriano pero con diferentes duraciones de meses y una época diferente.
const date = new Date('2025-03-15');
const persianFormatter = new Intl.DateTimeFormat('en-US', {
calendar: 'persian',
year: 'numeric',
month: 'long',
day: 'numeric'
});
console.log(persianFormatter.format(date));
// Output: "Esfand 24, 1403 AP"
El año persa 1403 corresponde al año gregoriano 2025. La abreviatura AP significa Anno Persico.
El formateo en idioma persa utiliza dígitos y nombres de meses persas.
const date = new Date('2025-03-15');
const persianFormatter = new Intl.DateTimeFormat('fa-IR', {
calendar: 'persian',
year: 'numeric',
month: 'long',
day: 'numeric'
});
console.log(persianFormatter.format(date));
// Output: "۲۴ اسفند ۱۴۰۳ ه.ش."
Otros sistemas de calendario compatibles
JavaScript admite sistemas de calendario adicionales para diversos contextos culturales y religiosos.
El calendario buddhist añade 543 años al año gregoriano, utilizado en Tailandia y otros países budistas Theravada.
const date = new Date('2025-03-15');
const buddhistFormatter = new Intl.DateTimeFormat('en-US', {
calendar: 'buddhist',
year: 'numeric',
month: 'long',
day: 'numeric'
});
console.log(buddhistFormatter.format(date));
// Output: "March 15, 2568 BE"
El calendario indian es el calendario civil oficial de India.
const date = new Date('2025-03-15');
const indianFormatter = new Intl.DateTimeFormat('en-US', {
calendar: 'indian',
year: 'numeric',
month: 'long',
day: 'numeric'
});
console.log(indianFormatter.format(date));
// Output: "Phalguna 24, 1946 Saka"
El calendario coptic es utilizado por la Iglesia Ortodoxa Copta. El calendario ethiopic se utiliza en Etiopía.
const date = new Date('2025-03-15');
const copticFormatter = new Intl.DateTimeFormat('en-US', {
calendar: 'coptic',
year: 'numeric',
month: 'long',
day: 'numeric'
});
const ethiopicFormatter = new Intl.DateTimeFormat('en-US', {
calendar: 'ethiopic',
year: 'numeric',
month: 'long',
day: 'numeric'
});
console.log(copticFormatter.format(date));
// Output: "Amshir 6, 1741 ERA1"
console.log(ethiopicFormatter.format(date));
// Output: "Yekatit 6, 2017 ERA1"
Descubriendo calendarios compatibles
El método Intl.supportedValuesOf() devuelve un array de todos los identificadores de calendario compatibles con la implementación de JavaScript.
const calendars = Intl.supportedValuesOf('calendar');
console.log(calendars);
// Salida: ["buddhist", "chinese", "coptic", "dangi", "ethioaa", "ethiopic",
// "gregory", "hebrew", "indian", "islamic", "islamic-civil",
// "islamic-tbla", "islamic-umalqura", "japanese", "persian", "roc"]
La lista exacta varía según el motor de JavaScript y la versión del navegador. El método siempre devuelve los calendarios en orden alfabético.
Puedes verificar si un calendario específico es compatible antes de usarlo.
const calendars = Intl.supportedValuesOf('calendar');
const supportsIslamic = calendars.includes('islamic');
if (supportsIslamic) {
const formatter = new Intl.DateTimeFormat('en-US', {
calendar: 'islamic',
dateStyle: 'long'
});
console.log(formatter.format(new Date()));
}
Esta verificación previene errores en entornos que podrían no ser compatibles con todos los sistemas de calendario.
Especificando el calendario con extensión Unicode
Puedes especificar el sistema de calendario utilizando una clave de extensión Unicode en el identificador de localización en lugar de usar el parámetro de opciones. Añade -u-ca- seguido del identificador del calendario a la cadena de localización.
const date = new Date('2025-03-15');
const formatter = new Intl.DateTimeFormat('en-US-u-ca-islamic', {
dateStyle: 'long'
});
console.log(formatter.format(date));
// Salida: "Ramadan 16, 1447 AH"
La extensión -u-ca-islamic indica al formateador que use el calendario islámico. Esto produce el mismo resultado que pasar calendar: 'islamic' en el objeto de opciones.
Cuando especificas el calendario tanto en la cadena de localización como en el objeto de opciones, el objeto de opciones tiene prioridad.
const date = new Date('2025-03-15');
const formatter = new Intl.DateTimeFormat('en-US-u-ca-islamic', {
calendar: 'hebrew',
dateStyle: 'long'
});
console.log(formatter.format(date));
// Salida: "14 Adar II 5785"
El calendario hebreo del objeto de opciones anula el calendario islámico de la cadena de localización. Utiliza el parámetro de opciones cuando necesites controlar programáticamente el sistema de calendario. Utiliza la extensión Unicode cuando trabajes con identificadores de localización de preferencias de usuario o configuración.
Cómo los locales determinan los calendarios predeterminados
Cuando no especificas un calendario, el formateador utiliza el calendario predeterminado para el locale. La mayoría de los locales utilizan por defecto el calendario gregoriano, pero algunos locales utilizan diferentes valores predeterminados.
const date = new Date('2025-03-15');
const usFormatter = new Intl.DateTimeFormat('en-US', {
dateStyle: 'long'
});
const saFormatter = new Intl.DateTimeFormat('ar-SA', {
dateStyle: 'long'
});
const ilFormatter = new Intl.DateTimeFormat('he-IL', {
dateStyle: 'long'
});
console.log(usFormatter.format(date));
// Output: "March 15, 2025"
console.log(saFormatter.format(date));
// Output: "١٦ رمضان ١٤٤٧ هـ"
console.log(ilFormatter.format(date));
// Output: "15 במרץ 2025"
El locale de inglés estadounidense utiliza el calendario gregoriano por defecto. El locale árabe de Arabia Saudita utiliza el calendario islámico por defecto. El locale hebreo israelí utiliza el calendario gregoriano por defecto a pesar de tener fuertes tradiciones de calendario hebreo.
Puedes descubrir qué calendario está utilizando un formateador llamando al método resolvedOptions().
const formatter = new Intl.DateTimeFormat('ar-SA', {
dateStyle: 'long'
});
const options = formatter.resolvedOptions();
console.log(options.calendar);
// Output: "islamic-umalqura"
Las opciones resueltas muestran que el locale ar-SA utiliza por defecto la variante de calendario islamic-umalqura.
Cuándo establecer explícitamente el calendario
Deja que el locale determine el sistema de calendario cuando formatees fechas para mostrarlas a los usuarios en su locale nativo. Los usuarios de Arabia Saudita esperan fechas del calendario islámico. Los usuarios de Japón esperan el formato de era japonesa en contextos oficiales. Los valores predeterminados del locale manejan estas expectativas automáticamente.
const date = new Date('2025-03-15');
const formatter = new Intl.DateTimeFormat(navigator.language, {
dateStyle: 'long'
});
console.log(formatter.format(date));
// El resultado varía según el locale del usuario y el calendario predeterminado
Establece explícitamente el calendario cuando necesites mostrar fechas en un sistema de calendario específico independientemente del locale del usuario. Una aplicación de horarios de oración siempre debe mostrar fechas del calendario islámico. Una aplicación de calendario hebreo siempre debe mostrar fechas hebreas.
const date = new Date('2025-03-15');
const formatter = new Intl.DateTimeFormat(navigator.language, {
calendar: 'islamic',
dateStyle: 'long'
});
console.log(formatter.format(date));
// El resultado muestra la fecha del calendario islámico en el idioma del usuario
Esto asegura que el sistema de calendario coincida con el propósito de tu aplicación mientras sigue respetando la preferencia de idioma del usuario.
Establece explícitamente el calendario cuando muestres fechas en un sistema de calendario diferente al predeterminado del locale. Es posible que desees mostrar fechas gregorianas a usuarios hebreos o fechas islámicas a hablantes de inglés.
const date = new Date('2025-03-15');
const formatter = new Intl.DateTimeFormat('en-US', {
calendar: 'hebrew',
dateStyle: 'long'
});
console.log(formatter.format(date));
// Output: "14 Adar II 5785"
Combinando calendario con otras opciones
La opción de calendario funciona con todas las demás opciones de Intl.DateTimeFormat. Puedes combinarla con dateStyle, timeStyle, opciones de componentes como weekday y month, y otras opciones como timeZone.
const date = new Date('2025-03-15T14:30:00');
const formatter = new Intl.DateTimeFormat('en-US', {
calendar: 'islamic',
dateStyle: 'full',
timeStyle: 'long',
timeZone: 'America/New_York'
});
console.log(formatter.format(date));
// Output: "Saturday, Ramadan 16, 1447 AH at 2:30:00 PM EST"
El formateador utiliza el calendario islámico para la fecha mientras aplica el estilo de fecha completo, el estilo de hora largo y la zona horaria especificada.
También puedes usar la opción de calendario con opciones de componentes individuales.
const date = new Date('2025-03-15');
const formatter = new Intl.DateTimeFormat('en-US', {
calendar: 'japanese',
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric',
era: 'long'
});
console.log(formatter.format(date));
// Output: "Saturday, March 15, 7 Reiwa"
La opción de era se vuelve particularmente relevante cuando se utilizan calendarios como el japonés o el budista que usan nombres de era.
Formateando rangos de fechas con diferentes calendarios
El método formatRange() funciona con la opción de calendario para formatear rangos de fechas en cualquier sistema de calendario.
const startDate = new Date('2025-03-15');
const endDate = new Date('2025-03-25');
const formatter = new Intl.DateTimeFormat('en-US', {
calendar: 'islamic',
year: 'numeric',
month: 'long',
day: 'numeric'
});
console.log(formatter.formatRange(startDate, endDate));
// Output: "Ramadan 16 – 26, 1447 AH"
El formateador aplica el calendario islámico a ambas fechas y las formatea como un rango, omitiendo inteligentemente la información repetida.
Reutilizando formateadores para mejorar el rendimiento
Crear instancias de Intl.DateTimeFormat implica procesar datos de localización e información del sistema de calendario. Cuando formatees múltiples fechas con el mismo calendario y localización, crea el formateador una vez y reutilízalo.
const formatter = new Intl.DateTimeFormat('en-US', {
calendar: 'islamic',
dateStyle: 'long'
});
const dates = [
new Date('2025-03-15'),
new Date('2025-04-20'),
new Date('2025-06-10')
];
dates.forEach(date => {
console.log(formatter.format(date));
});
// Output:
// "Ramadan 16, 1447 AH"
// "Dhuʻl-Qiʻdah 22, 1447 AH"
// "Dhuʻl-Hijjah 15, 1447 AH"
Este enfoque mejora el rendimiento cuando se formatean arrays de fechas o se muestran muchas marcas de tiempo en tu aplicación.
Qué recordar
Los sistemas de calendario definen cómo las culturas organizan y cuentan el tiempo. JavaScript admite más de 17 sistemas de calendario diferentes, incluyendo los calendarios islámico, hebreo, japonés, chino, persa, budista y copto a través de la API Intl.DateTimeFormat.
Especifica un sistema de calendario utilizando la opción calendar en el objeto de opciones o añadiendo una extensión Unicode a la cadena de configuración regional. La opción de calendario determina qué sistema de calendario formatea la fecha, mientras que la configuración regional determina el idioma y las convenciones de formato.
Permite que la configuración regional determine el calendario predeterminado cuando se muestran fechas para uso general. Establece explícitamente el calendario cuando tu aplicación requiere un sistema de calendario específico, independientemente de las preferencias de configuración regional del usuario.
La opción de calendario funciona con todas las demás opciones de formato de fecha, incluyendo estilos, opciones de componentes, zonas horarias y rangos de fechas. Reutiliza las instancias del formateador cuando formatees múltiples fechas para obtener un mejor rendimiento.