ヒジュラ暦(ウム・アル=クラ) は何をしますか?
サウジアラビアの公式ヒジュラ暦はウム・アル=クラ(أم القرى)であり、計算によって求められる暦です。他の「イスラム暦」は異なるルールを使用し、しばしば1日ずれるため、コードとUIで常に暦の名前を明示してください。
ルール
- ISOグレゴリオ暦の日付(
2026-11-03、DATE型カラム、またはUTCタイムスタンプ)を保存します。ヒジュラ暦への変換は表示のためだけに行います。ユーザーがヒジュラ暦の日付を入力した場合は、入力時にグレゴリオ暦に変換して保存します。 - 表示される日付には、どの暦を使用しているかを常にラベル表示します:「23 جمادى الأولى 1448هـ」および「3 نوفمبر 2026م」。
- ヒジュラ暦の月は29日または30日、年は354日または355日です。固定の月の長さを使用したり、「次の月」のために「30日を加算」したりしないでください。
1448-05-23のようなヒジュラ暦の文字列はISO 8601ではありません。これをnew Date()に渡さないでください。西暦1448年として解釈されます。- 宗教的な日付(ラマダンの開始、イード)は月の観測によって発表され、印刷されたウム・アル=クラの日付と異なる場合があります。計算上の日付は、「حسب تقويم أم القرى」または「متوقع」として表示し、確定的なものとして表示しないでください。
JavaScript: Intl を使用した書式設定
const d = new Date(Date.UTC(2026, 10, 3)); // 2026年11月3日
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"
- 常に
ca-islamic-umalquraを明示的に指定してください。ar-SAがヒジュラ暦を意味すると想定しないでください。最近のICU/CLDR(Node 24、現在のChrome)では、ar-SAのデフォルトのカレンダーはグレゴリオ暦です。 - 数字は
nu-latn(0-9)またはnu-arab(٠-٩)で明示的に設定します。デフォルトはロケールとバージョンによって異なります:ar-SAは ٠-٩、プレーンなarは現在 0-9 を返します。 - 正確な文字列(「هـ」の前のスペース、「AH」、「Jumada I」と「Jumada al-Ula」の違い)はエンジンによって異なります。フォーマットされたテキストを解析したり、環境間でスナップショットテストを行ったりしないでください。
formatToPartsを使用してください。 - タイムゾーンが日を決定します。
new Date('2026-11-03')はUTCの真夜中なので、timeZone: 'UTC'を指定してフォーマットします。「サウジアラビアの今日」の場合はtimeZone: 'Asia/Riyadh'を使用します。時刻2026-11-03T22:30Zは、リヤドではすでに24 جمادى الأولىです。
グレゴリオ暦からヒジュラ暦の数値へ
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 }
ヒジュラ暦からグレゴリオ暦へ:日数のスキャン
Intl はヒジュラ暦の日付を解析できないため、グレゴリオ暦の日付を推定し、toHijri が一致するまで近くの日をスキャンします。
const DAY = 86400000;
export function hijriToGregorian(y, m, d) {
// ヒジュラ暦1年1月1日は西暦622年7月19日頃(先発グレゴリオ暦); 平均月数29.530589日
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; // そのような日は存在しない(例:29日の月に30日を指定)
}
hijriToGregorian(1447, 9, 1); // "2026-02-18"
hijriToGregorian(1448, 1, 1); // "2026-06-16"
hijriToGregorian(1448, 1, 30); // null(ムハッラム月1448年は29日)
nullの結果はユーザー入力を検証する方法です。「هذا اليوم غير موجود في هذا الشهر」と表示します。- 月の長さ:
hijriToGregorian(y, m, 30) ? 30 : 29。 - ICUのウム・アル=クラテーブルはヒジュラ暦1300年から1600年までをカバーしています。その範囲外では、エンジンはタブラー暦にフォールバックするため、結果はウム・アル=クラではありません。
- ユーザーが入力したアラビア・インド数字を受け入れます:解析前に ٠-٩ を 0-9 に変換します(
arabic-rtl-webを参照)。
Python: hijridate
# pip install hijridate (hijri-converter の後継、同じ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), datetime.date のサブクラス
Hijri.today()
- 古いコードでは
pip install hijri-converterを使用し、from hijri_converter import Hijri, Gregorianとします。まだ動作しますが、DeprecationWarning が表示されるようになったので、インポートをhijridateに切り替えてください。 - 対応範囲:ヒジュラ暦1343年1月1日から1500年12月30日まで(西暦1924年8月1日から2077年11月16日まで)。範囲外では
OverflowError: date out of rangeが発生します。 - 存在しない日を指定すると
ValueErrorが発生します。例:Hijri(1448, 1, 30):「月の日は1~29でなければなりません」。 - .NET では、
UmAlQuraCalendarを使用してください。HijriCalendar(クウェートのタブラーアルゴリズム)は使用しないでください。
月名
1 محرم、2 صفر、3 ربيع الأول、4 ربيع الآخر、5 جمادى الأولى、6 جمادى الآخرة、7 رجب、8 شعبان、9 رمضان、10 شوال、11 ذو القعدة、12 ذو الحجة。
綴りはライブラリによって異なります:ICU は「ربيع الآخر」、hijridate は「ربيع الثاني」と出力します。英語も同様に異なります(「Rabiʻ II」、「Rabi' al-Thani」)。一貫性のあるUIのためには、ライブラリの文字列を混在させるのではなく、月番号を独自のリストにマッピングしてください。
落とし穴
- 間違った暦。 2026年11月3日について、Node 24 は
islamic-umalquraで23日、islamic-civilで22日、islamicで24日を返します。Excel と Windows の「ヒジュラ暦」カレンダーはクウェートのタブラーアルゴリズムを使用します。サウジの日付にはウム・アル=クラを使用してください。 - タイムゾーンによる1日のずれ: 日付が保存されたのと同じタイムゾーンでフォーマットしてください。
- ヒジュラ暦での日付演算。 「次の月」については、月番号をインクリメントし、日をその月の長さにクランプしてから変換します。年齢や期間はグレゴリオ暦で計算してください。
- ラベルのない日付。 「1/5/1448」や「5/1」だけでは曖昧です。常に هـ または م を追加してください。
- 数字の混在。 1ページにつき1つの数字システムを維持してください。
既知のペアでテスト(ウム・アル=クラ)
| ヒジュラ暦 | グレゴリオ暦 |
|---|---|
| 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 |