Fechas Hijri (Umm al-Qura)
El calendario Hijri oficial de Arabia Saudita es Umm al-Qura (أم القرى), un calendario calculado. Otros calendarios "islámicos" utilizan reglas diferentes y a menudo difieren en un día, por lo que siempre debes nombrar el calendario tanto en el código como en la interfaz de usuario.
Reglas
- Almacena fechas ISO gregorianas (
2026-11-03, una columnaDATEo una marca de tiempo UTC). Convierte a Hijri solo para mostrar. Cuando un usuario ingrese una fecha Hijri, conviértela a Gregoriano al recibirla y almacena esa. - Siempre etiqueta qué calendario usa una fecha mostrada: «23 جمادى الأولى 1448هـ» y «3 noviembre 2026م».
- Los meses Hijri tienen 29 o 30 días y un año tiene 354 o 355. Nunca uses longitudes fijas de mes ni "añadir 30 días" para "el próximo mes".
- Una cadena Hijri como
1448-05-23no es ISO 8601. Nunca la pases anew Date(); se interpretaría como el año 1448 d.C. - Las fechas religiosas (inicio de Ramadán, Eid) son anunciadas por avistamiento lunar y pueden diferir de la fecha impresa de Umm al-Qura. Presenta las fechas calculadas como «حسب تقويم أم القرى» o «متوقع», nunca como seguras.
JavaScript: formato con Intl
const d = new Date(Date.UTC(2026, 10, 3)); // 3 Nov 2026
new Intl.DateTimeFormat('ar-SA-u-ca-islamic-umalqura', { dateStyle: 'full', timeZone: 'UTC' }).format(d);
// "الثلاثاء، ٢٣ جمادى الأولى ١٤٤٨ هـ"
new Intl.DateTimeFormat('ar-SA-u-ca-islamic-umalqura-nu-latn',
{ day: 'numeric', month: 'long', year: 'numeric', timeZone: 'UTC' }).format(d);
// "23 جمادى الأولى 1448 هـ"
new Intl.DateTimeFormat('en-u-ca-islamic-umalqura-nu-latn',
{ day: 'numeric', month: 'long', year: 'numeric', timeZone: 'UTC' }).format(d);
// "Jumada I 23, 1448 AH"
- Siempre escribe
ca-islamic-umalquraexplícitamente. No confíes en quear-SAsignifique Hijri: en ICU/CLDR recientes (Node 24, Chrome actual) el calendario predeterminado paraar-SAes gregoriano. - Establece los dígitos explícitamente con
nu-latn(0-9) onu-arab(٠-٩). Los valores predeterminados varían según la configuración regional y la versión:ar-SAda ٠-٩,arsimple ahora da 0-9. - Las cadenas exactas (espaciado antes de «هـ», "AH", "Jumada I" vs "Jumada al-Ula") varían entre motores. Nunca analices texto formateado ni hagas pruebas de instantáneas entre entornos. Usa
formatToParts. - La zona horaria determina el día.
new Date('2026-11-03')es medianoche UTC, así que formatéalo contimeZone: 'UTC'. Para "hoy en Arabia Saudita" usatimeZone: 'Asia/Riyadh'. El instante2026-11-03T22:30Zya es 24 جمادى الأولى en Riad.
Conversión de Gregoriano a Hijri (números)
const hijriParts = new Intl.DateTimeFormat('en-u-ca-islamic-umalqura-nu-latn', {
day: 'numeric', month: 'numeric', year: 'numeric', timeZone: 'UTC',
});
export function toHijri(date) {
const p = {};
for (const { type, value } of hijriParts.formatToParts(date)) p[type] = value;
return { year: parseInt(p.year, 10), month: parseInt(p.month, 10), day: parseInt(p.day, 10) };
}
toHijri(new Date(Date.UTC(2026, 10, 3))); // { year: 1448, month: 5, day: 23 }
Conversión de Hijri a Gregoriano: escaneo de días
Intl no puede analizar fechas Hijri, así que estima la fecha gregoriana y escanea los días cercanos hasta que toHijri coincida.
const DAY = 86400000;
export function hijriToGregorian(y, m, d) {
// 1 Muharram 1 AH es aproximadamente el 19 de julio de 622 (Gregoriano proléptico); mes medio 29.530589 días
const est = Date.UTC(622, 6, 19) + Math.round((y - 1) * 354.36667 + (m - 1) * 29.530589 + (d - 1)) * DAY;
for (let off = -20; off <= 20; off++) {
const t = new Date(est + off * DAY);
const h = toHijri(t);
if (h.year === y && h.month === m && h.day === d) return t.toISOString().slice(0, 10);
}
return null; // día inexistente, ej. día 30 de un mes de 29 días
}
hijriToGregorian(1447, 9, 1); // "2026-02-18"
hijriToGregorian(1448, 1, 1); // "2026-06-16"
hijriToGregorian(1448, 1, 30); // null (Muharram 1448 tiene 29 días)
- Un resultado
nulles cómo validas la entrada del usuario; muestra «هذا اليوم غير موجود في هذا الشهر». - Longitud del mes:
hijriToGregorian(y, m, 30) ? 30 : 29. - La tabla Umm al-Qura de ICU cubre de 1300 a 1600 AH. Fuera de ese rango, los motores recurren al calendario tabular, por lo que los resultados allí no son Umm al-Qura.
- Acepta dígitos arábigo-indios escritos por el usuario: convierte ٠-٩ a 0-9 antes de analizar (consulta
arabic-rtl-web).
Python: hijridate
# pip install hijridate (sucesor de hijri-converter, misma API)
from hijridate import Hijri, Gregorian
h = Gregorian(2026, 11, 3).to_hijri() # Hijri(1448, 5, 23)
h.isoformat() # '1448-05-23'
h.dmyformat() # '23/05/1448'
h.month_name() # 'Jumada al-Ula'
h.month_name('ar') # 'جمادى الأولى'
h.day_name('ar') # 'الثلاثاء'
h.notation('ar') # 'هـ'
h.month_length() # 30
g = Hijri(1447, 9, 1).to_gregorian() # Gregorian(2026, 2, 18), una subclase de datetime.date
Hijri.today()
- El código antiguo usa
pip install hijri-converteryfrom hijri_converter import Hijri, Gregorian. Todavía funciona pero ahora emite un DeprecationWarning; cambia la importación ahijridate. - Rango soportado: 1 Muharram 1343 AH a 30 Dhu al-Hijjah 1500 AH (1924-08-01 a 2077-11-16 d.C.). Fuera de él, se produce
OverflowError: date out of range. - Un día imposible genera
ValueError, por ejemploHijri(1448, 1, 30): "day must be in 1..29 for month". - En .NET, usa
UmAlQuraCalendar, noHijriCalendar(que es el algoritmo tabular kuwaití).
Nombres de los meses
1 محرم، 2 صفر، 3 ربيع الأول، 4 ربيع الآخر، 5 جمادى الأولى، 6 جمادى الآخرة، 7 رجب، 8 شعبان، 9 رمضان، 10 شوال، 11 ذو القعدة، 12 ذو الحجة.
La ortografía difiere entre bibliotecas: ICU imprime «ربيع الآخر» mientras que hijridate imprime «ربيع الثاني»; el inglés también varía ("Rabiʻ II", "Rabi' al-Thani"). Para una interfaz de usuario consistente, asigna los números de mes a tu propia lista en lugar de mezclar cadenas de bibliotecas.
Errores comunes
- Calendario incorrecto. Para el 3 de noviembre de 2026, Node 24 da 23 con
islamic-umalqura, 22 conislamic-civily 24 conislamic. Excel y el calendario "Hijri" de Windows usan el algoritmo tabular kuwaití. Usa Umm al-Qura para fechas saudíes. - Diferencia de un día por zonas horarias: formatea en la misma zona en que se almacenó la fecha.
- Aritmética de fechas en Hijri. Para "el próximo mes", incrementa el número del mes, ajusta el día a la longitud de ese mes y luego convierte. Calcula edades y duraciones en Gregoriano.
- Fechas sin etiquetar. Un «1/5/1448» o «5/1» sin más es ambiguo; siempre añade هـ o م.
- Dígitos mezclados. Mantén un solo sistema de dígitos por página.
Pruebas con pares conocidos (Umm al-Qura)
| Hijri | Gregoriano |
|---|---|
| 1 Ramadán 1447 | 2026-02-18 |
| 1 Muharram 1448 | 2026-06-16 |
| 23 Jumada al-Ula 1448 | 2026-11-03 |
| 10 Dhu al-Hijjah 1446 | 2025-06-06 |