hijri-core

Zero-dependency Hijri calendar conversion. Supports Umm al-Qura (Saudi official) and FCNA/ISNA (astronomical) systems with unlimited date range.

Overview

hijri-core converts dates between the Gregorian and Islamic Hijri calendars. It is the core engine used by luxon-hijri and directly by pray-calc for Hijri date display.

  • Zero runtime dependencies
  • Umm al-Qura table (1318–1500 AH, Saudi Arabia)
  • FCNA/ISNA astronomical calculation (unlimited range)
  • Accurate to within ±1 day of the official Saudi calendar
  • TypeScript-first, ESM + CJS

GitHub: github.com/acamarata/hijri-core

Installation

<span><span style="color: var(--shiki-token-function)">pnpm</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">add</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">hijri-core</span></span>
<span></span>

API

toHijri

toHijri(date: Date, system?: HijriSystem): HijriDate — converts a Gregorian date to Hijri.

<span><span style="color: var(--shiki-token-keyword)">import</span><span style="color: var(--shiki-color-text)"> { toHijri } </span><span style="color: var(--shiki-token-keyword)">from</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">&#39;hijri-core&#39;</span></span>
<span></span>
<span><span style="color: var(--shiki-token-keyword)">const</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">hijri</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">toHijri</span><span style="color: var(--shiki-color-text)">(</span><span style="color: var(--shiki-token-keyword)">new</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">Date</span><span style="color: var(--shiki-color-text)">(</span><span style="color: var(--shiki-token-string-expression)">&#39;2025-03-29&#39;</span><span style="color: var(--shiki-color-text)">))</span></span>
<span><span style="color: var(--shiki-token-constant)">console</span><span style="color: var(--shiki-token-function)">.log</span><span style="color: var(--shiki-color-text)">(hijri)</span></span>
<span><span style="color: var(--shiki-token-comment)">// { year: 1446, month: 9, day: 29, monthName: &#39;Ramadan&#39;, system: &#39;ummAlQura&#39; }</span></span>
<span></span>
<span><span style="color: var(--shiki-token-keyword)">const</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">astro</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">toHijri</span><span style="color: var(--shiki-color-text)">(</span><span style="color: var(--shiki-token-keyword)">new</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">Date</span><span style="color: var(--shiki-color-text)">(</span><span style="color: var(--shiki-token-string-expression)">&#39;2025-03-29&#39;</span><span style="color: var(--shiki-color-text)">)</span><span style="color: var(--shiki-token-punctuation)">,</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">&#39;fcna&#39;</span><span style="color: var(--shiki-color-text)">)</span></span>
<span><span style="color: var(--shiki-token-constant)">console</span><span style="color: var(--shiki-token-function)">.log</span><span style="color: var(--shiki-color-text)">(astro)</span></span>
<span><span style="color: var(--shiki-token-comment)">// { year: 1446, month: 9, day: 29, monthName: &#39;Ramadan&#39;, system: &#39;fcna&#39; }</span></span>
<span></span>

toGregorian

toGregorian(hijri: HijriDate, system?: HijriSystem): Date — converts a Hijri date to Gregorian.

<span><span style="color: var(--shiki-token-keyword)">import</span><span style="color: var(--shiki-color-text)"> { toGregorian } </span><span style="color: var(--shiki-token-keyword)">from</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">&#39;hijri-core&#39;</span></span>
<span></span>
<span><span style="color: var(--shiki-token-keyword)">const</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">date</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">toGregorian</span><span style="color: var(--shiki-color-text)">({ year</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">1446</span><span style="color: var(--shiki-token-punctuation)">,</span><span style="color: var(--shiki-color-text)"> month</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">10</span><span style="color: var(--shiki-token-punctuation)">,</span><span style="color: var(--shiki-color-text)"> day</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">1</span><span style="color: var(--shiki-color-text)"> })</span></span>
<span><span style="color: var(--shiki-token-constant)">console</span><span style="color: var(--shiki-token-function)">.log</span><span style="color: var(--shiki-color-text)">(</span><span style="color: var(--shiki-token-constant)">date</span><span style="color: var(--shiki-token-function)">.toISOString</span><span style="color: var(--shiki-color-text)">()</span><span style="color: var(--shiki-token-function)">.slice</span><span style="color: var(--shiki-color-text)">(</span><span style="color: var(--shiki-token-constant)">0</span><span style="color: var(--shiki-token-punctuation)">,</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">10</span><span style="color: var(--shiki-color-text)">))  </span><span style="color: var(--shiki-token-comment)">// &quot;2025-03-30&quot;</span></span>
<span></span>

getHijriMonthLength

<span><span style="color: var(--shiki-token-function)">getHijriMonthLength</span><span style="color: var(--shiki-color-text)">(year: number</span><span style="color: var(--shiki-token-punctuation)">,</span><span style="color: var(--shiki-color-text)"> month: number</span><span style="color: var(--shiki-token-punctuation)">,</span><span style="color: var(--shiki-color-text)"> system</span><span style="color: var(--shiki-token-keyword)">?:</span><span style="color: var(--shiki-color-text)"> HijriSystem): number</span></span>
<span></span>

Returns the number of days in a Hijri month (29 or 30).

Calendar systems

hijri-core supports two Hijri calendar systems:

Umm al-Qura ('ummAlQura', default):

  • Saudi Arabia's official Hijri calendar
  • Based on a pre-computed table (1318–1500 AH = 1900–2077 CE)
  • Months begin on the day after astronomical conjunction
  • Used throughout the Arab world for official dates
  • Deviates from astronomical observation by 0–2 days due to the table calculation

FCNA / ISNA ('fcna'):

  • Used by Fiqh Council of North America and ISNA
  • Based on astronomical new moon calculation
  • Not limited to a specific date range
  • Often differs from Umm al-Qura by 1–2 days
  • See Hijri Calendar Systems for a full comparison

Custom calendars

<span><span style="color: var(--shiki-token-keyword)">import</span><span style="color: var(--shiki-color-text)"> { registerCalendar } </span><span style="color: var(--shiki-token-keyword)">from</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">&#39;hijri-core&#39;</span></span>
<span></span>
<span><span style="color: var(--shiki-token-function)">registerCalendar</span><span style="color: var(--shiki-color-text)">(</span><span style="color: var(--shiki-token-string-expression)">&#39;myCalendar&#39;</span><span style="color: var(--shiki-token-punctuation)">,</span><span style="color: var(--shiki-color-text)"> {</span></span>
<span><span style="color: var(--shiki-color-text)">  </span><span style="color: var(--shiki-token-function)">toHijri</span><span style="color: var(--shiki-color-text)">(date</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">Date</span><span style="color: var(--shiki-color-text)">)</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">HijriDate</span><span style="color: var(--shiki-color-text)"> {</span></span>
<span><span style="color: var(--shiki-color-text)">    </span><span style="color: var(--shiki-token-comment)">// your conversion logic</span></span>
<span><span style="color: var(--shiki-color-text)">  }</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)">  </span><span style="color: var(--shiki-token-function)">toGregorian</span><span style="color: var(--shiki-color-text)">(hijri</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">HijriDate</span><span style="color: var(--shiki-color-text)">)</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">Date</span><span style="color: var(--shiki-color-text)"> {</span></span>
<span><span style="color: var(--shiki-color-text)">    </span><span style="color: var(--shiki-token-comment)">// your conversion logic</span></span>
<span><span style="color: var(--shiki-color-text)">  }</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)">})</span></span>
<span></span>
<span><span style="color: var(--shiki-token-keyword)">const</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">result</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">toHijri</span><span style="color: var(--shiki-color-text)">(</span><span style="color: var(--shiki-token-keyword)">new</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">Date</span><span style="color: var(--shiki-color-text)">()</span><span style="color: var(--shiki-token-punctuation)">,</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">&#39;myCalendar&#39;</span><span style="color: var(--shiki-color-text)">)</span></span>
<span></span>

This allows integrating observation-based calendars, regional variants, or future astronomical models.