Communitygithub.com

ヒジュラ暦(ウム・アル=クラ)

サウジアラビアで使用されるウム・アル=クラ暦に基づき、ヒジュラ暦(イスラム暦)の日付をコードで扱うためのスキルです。JavaScript Intl による書式設定、グレゴリオ暦との変換、Python ライブラリ hijridate を使用した変換、バリデーション、保存、ラベル表示をサポートします。アプリ、フォーム、レポート、データベースでヒジュラ暦(التاريخ الهجري, تقويم أم القرى)やイスラム月名、日付変換、サウジの日付表示が必要な場合に使用します。

ヒジュラ暦(ウム・アル=クラ) とは?

このスキルは、サウジアラビアの公式暦であるウム・アル=クラ(Umm al-Qura)暦に基づいたヒジュラ暦(イスラム暦)の日付処理を提供します。JavaScript の `Intl.DateTimeFormat` を使用した書式設定、グレゴリオ暦との相互変換、Python の `hijridate` ライブラリ(旧 `hijri-converter`)を用いた変換、日付のバリデーション、保存、ラベル表示をカバーしています。特に、ヒジュラ暦の文字列を `new Date()` に渡さない、グレゴリオ暦で保存して表示時に変換する、常に使用する暦を明示するといった重要なルールを詳しく説明しています。また、宗教的な日付(ラマダン開始、イード)は実際の月の観測に依存するため、計算上の日付は確定的でないことを明示する必要がある点も強調しています。テスト用の既知の日付ペア(ヒジュラ暦とグレゴリオ暦の対応表)も提供しており、実装の検証に役立ちます。対応プラットフォームは JavaScript(Node.js、ブラウザ)および Python です。

対応~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/hosam382/arabic-claude-skills/tree/HEAD/hijri-dates

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

ヒジュラ暦(ウム・アル=クラ) は何をしますか?

サウジアラビアの公式ヒジュラ暦はウム・アル=クラ(أم القرى)であり、計算によって求められる暦です。他の「イスラム暦」は異なるルールを使用し、しばしば1日ずれるため、コードとUIで常に暦の名前を明示してください。

ルール

  1. ISOグレゴリオ暦の日付(2026-11-03、DATE 型カラム、またはUTCタイムスタンプ)を保存します。ヒジュラ暦への変換は表示のためだけに行います。ユーザーがヒジュラ暦の日付を入力した場合は、入力時にグレゴリオ暦に変換して保存します。
  2. 表示される日付には、どの暦を使用しているかを常にラベル表示します:「23 جمادى الأولى 1448هـ」および「3 نوفمبر 2026م」。
  3. ヒジュラ暦の月は29日または30日、年は354日または355日です。固定の月の長さを使用したり、「次の月」のために「30日を加算」したりしないでください。
  4. 1448-05-23 のようなヒジュラ暦の文字列はISO 8601ではありません。これを new Date() に渡さないでください。西暦1448年として解釈されます。
  5. 宗教的な日付(ラマダンの開始、イード)は月の観測によって発表され、印刷されたウム・アル=クラの日付と異なる場合があります。計算上の日付は、「حسب تقويم أم القرى」または「متوقع」として表示し、確定的なものとして表示しないでください。

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 14472026-02-18
1 Muharram 14482026-06-16
23 Jumada al-Ula 14482026-11-03
10 Dhu al-Hijjah 14462025-06-06

Individual skills in this repo

This repo contains 3 individual skills — each has its own dedicated page.

関連スキル