Datas Hijri (Umm al-Qura)
O calendário Hijri oficial da Arábia Saudita é Umm al-Qura (أم القرى), um calendário calculado. Outros calendários "Islâmicos" usam regras diferentes e frequentemente diferem por um dia, portanto nomeie sempre o calendário no código e na interface do usuário.
Regras
- Armazene datas ISO Gregoriano (
2026-11-03, uma colunaDATEou um timestamp UTC). Converta para Hijri apenas para exibição. Quando um usuário inserir uma data Hijri, converta-a para Gregoriano na entrada e armazene essa data. - Sempre rotule qual calendário uma data exibida usa: «23 جمادى الأولى 1448هـ» e «3 نوفمبر 2026م».
- Os meses Hijri têm 29 ou 30 dias e um ano tem 354 ou 355 dias. Nunca use comprimentos fixos de mês ou "adicione 30 dias" para "próximo mês".
- Uma string Hijri como
1448-05-23não é ISO 8601. Nunca a passe paranew Date(); ela seria interpretada como o ano 1448 EC. - Datas religiosas (início do Ramadã, Eid) são anunciadas pela observação da lua e podem diferir da data impressa do Umm al-Qura. Apresente datas computadas para elas como «حسب تقويم أم القرى» ou «متوقع», nunca como certas.
JavaScript: formatação com 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"
- Sempre escreva
ca-islamic-umalquraexplicitamente. Não confie emar-SAsignificar Hijri: em ICU/CLDR recentes (Node 24, Chrome atual) o calendário padrão paraar-SAé Gregoriano. - Defina os dígitos explicitamente com
nu-latn(0-9) ounu-arab(٠-٩). Os padrões diferem por localidade e versão:ar-SAfornece ٠-٩,arsimples agora fornece 0-9. - Strings exatas (espaçamento antes de «هـ», "AH", "Jumada I" versus "Jumada al-Ula") variam entre motores. Nunca analise texto formatado e nunca faça snapshot-testes entre ambientes. Use
formatToParts. - O fuso horário decide o dia.
new Date('2026-11-03')é meia-noite UTC, então formate-o comtimeZone: 'UTC'. Para "hoje na Arábia Saudita" usetimeZone: 'Asia/Riyadh'. O instante2026-11-03T22:30Zjá é 24 جمادى الأولى em Riade.
Gregoriano para 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 }
Hijri para Gregoriano: escaneie dias
Intl não consegue analisar datas Hijri, então estime a data Gregoriana e escaneie os dias próximos até que toHijri corresponda.
const DAY = 86400000;
export function hijriToGregorian(y, m, d) {
// 1 Muharram 1 AH é aproximadamente 19 de julho de 622 (Gregoriano proléptico); mês médio 29.530589 dias
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; // esse dia não existe, ex. dia 30 de um mês de 29 dias
}
hijriToGregorian(1447, 9, 1); // "2026-02-18"
hijriToGregorian(1448, 1, 1); // "2026-06-16"
hijriToGregorian(1448, 1, 30); // null (Muharram 1448 tem 29 dias)
- Um resultado
nullé como você valida a entrada do usuário; mostre «هذا اليوم غير موجود في هذا الشهر». - Comprimento do mês:
hijriToGregorian(y, m, 30) ? 30 : 29. - A tabela Umm al-Qura da ICU cobre de 1300 a 1600 AH. Fora desse intervalo, os motores recorrem ao calendário tabular, então os resultados não são Umm al-Qura.
- Aceite dígitos arábico-índicos digitados pelos usuários: converta ٠-٩ para 0-9 antes de analisar (veja
arabic-rtl-web).
Python: hijridate
# pip install hijridate (sucessor do hijri-converter, mesma 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), uma subclasse de datetime.date
Hijri.today()
- Código antigo usa
pip install hijri-converterefrom hijri_converter import Hijri, Gregorian. Ainda funciona, mas agora emite um DeprecationWarning; mude a importação parahijridate. - Intervalo suportado: 1 Muharram 1343 AH a 30 Dhu al-Hijjah 1500 AH (1924-08-01 a 2077-11-16 EC). Fora disso,
OverflowError: date out of range. - Um dia impossível levanta
ValueError, por exemploHijri(1448, 1, 30): "day must be in 1..29 for month". - Em .NET, use
UmAlQuraCalendar, nãoHijriCalendar(que é o algoritmo tabular kuwaitiano).
Nomes dos meses
1 محرم، 2 صفر، 3 ربيع الأول، 4 ربيع الآخر، 5 جمادى الأولى، 6 جمادى الآخرة، 7 رجب، 8 شعبان، 9 رمضان، 10 شوال، 11 ذو القعدة، 12 ذو الحجة.
A grafia difere entre bibliotecas: ICU imprime «ربيع الآخر» enquanto hijridate imprime «ربيع الثاني»; o inglês também varia ("Rabiʻ II", "Rabi' al-Thani"). Para uma interface de usuário consistente, mapeie os números dos meses para sua própria lista em vez de misturar strings de bibliotecas.
Armadilhas
- Calendário errado. Para 3 de novembro de 2026, Node 24 fornece 23 com
islamic-umalqura, 22 comislamic-civile 24 comislamic. Excel e o calendário "Hijri" do Windows usam o algoritmo tabular kuwaitiano. Use Umm al-Qura para datas sauditas. - Diferença de um dia devido a fusos horários: formate no mesmo fuso em que a data foi armazenada.
- Aritmética de datas em Hijri. Para "próximo mês", incremente o número do mês, limite o dia ao comprimento desse mês, depois converta. Calcule idades e durações em Gregoriano.
- Datas não rotuladas. Uma data simples «1/5/1448» ou «5/1» é ambígua; sempre adicione هـ ou م.
- Dígitos misturados. Mantenha um sistema de dígitos por página.
Teste com pares conhecidos (Umm al-Qura)
| Hijri | Gregorian |
|---|---|
| 1 Ramadan 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 |