npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

temporal-hijri

v1.0.0

Published

Temporal Calendar Protocol implementation for the Hijri calendar system. Supports Umm al-Qura and FCNA calendars via hijri-core.

Readme

npm version CI License: MIT

temporal-hijri

Temporal Calendar Protocol implementation for the Hijri calendar. Works with the TC39 Temporal proposal and @js-temporal/polyfill.

Provides UaqCalendar (Umm al-Qura) and FcnaCalendar (FCNA/ISNA) as plug-in calendars for Temporal.PlainDate and related types. The underlying conversion logic comes from hijri-core, a zero-dependency Hijri engine with table-driven UAQ data and astronomical FCNA calculations.


Installation

pnpm add temporal-hijri hijri-core

If you are using the polyfill instead of the native Temporal API:

pnpm add temporal-hijri hijri-core @js-temporal/polyfill

Quick Start

import { Temporal } from '@js-temporal/polyfill'; // or use native Temporal
import { uaqCalendar } from 'temporal-hijri';

// Convert an ISO date to Hijri coordinates
const isoDate = Temporal.PlainDate.from('2023-03-23');

console.log(uaqCalendar.year(isoDate));      // 1444
console.log(uaqCalendar.month(isoDate));     // 9  (Ramadan)
console.log(uaqCalendar.day(isoDate));       // 1
console.log(uaqCalendar.monthCode(isoDate)); // "M09"
console.log(uaqCalendar.inLeapYear(isoDate)); // false (1444 is 354 days)

// Convert Hijri coordinates back to ISO
const ramadan = uaqCalendar.dateFromFields({ year: 1444, month: 9, day: 1 });
console.log(ramadan.toString()); // "2023-03-23"

// Arithmetic in Hijri space
const { Duration } = Temporal;
const nextMonth = uaqCalendar.dateAdd(isoDate, new Duration(0, 1));
console.log(uaqCalendar.month(nextMonth)); // 10 (Shawwal)
console.log(nextMonth.toString());          // "2023-04-21"

Calendar Classes

UaqCalendar

Implements the Umm al-Qura calendar, the official calendar of Saudi Arabia. Month boundaries come from pre-calculated tables covering 1318-1500 AH (Gregorian 1900-2076). The most widely used Hijri calendar standard for civil and religious purposes.

import { UaqCalendar } from 'temporal-hijri';
const cal = new UaqCalendar(); // cal.id === 'hijri-uaq'

FcnaCalendar

Implements the FCNA/ISNA calendar used by the Fiqh Council of North America and the Islamic Society of North America. Month starts are determined by astronomical new moon calculation (Meeus Chapter 49): if conjunction occurs before 12:00 UTC, the month begins the next day; if at or after noon, it begins the day after that.

import { FcnaCalendar } from 'temporal-hijri';
const cal = new FcnaCalendar(); // cal.id === 'hijri-fcna'

HijriCalendar (base class)

The base implementation. Accepts any CalendarEngine from hijri-core. Use this to build a Temporal calendar from a custom engine registered via hijri-core's registerCalendar().

import { HijriCalendar } from 'temporal-hijri';
import { getCalendar, registerCalendar } from 'hijri-core';

// Register a custom engine first
registerCalendar('my-calendar', myEngine);
const cal = new HijriCalendar(getCalendar('my-calendar'));
// cal.id === 'hijri-my-calendar'

Convenience singletons

uaqCalendar and fcnaCalendar are pre-constructed instances. They are shared objects and safe to reuse across calls.

import { uaqCalendar, fcnaCalendar } from 'temporal-hijri';

API

All methods receive a Temporal.PlainDate with an ISO (Gregorian) calendar. The PlainDate carries the ISO year/month/day; the calendar object interprets those coordinates.

| Method | Returns | Description | |---|---|---| | year(date) | number | Hijri year | | month(date) | number | Hijri month (1-12) | | monthCode(date) | string | Month code: "M01" through "M12" | | day(date) | number | Day of the Hijri month (1-29 or 1-30) | | daysInMonth(date) | number | Length of the Hijri month (29 or 30) | | daysInYear(date) | number | Days in the Hijri year (354 or 355) | | monthsInYear(date) | number | Always 12 | | inLeapYear(date) | boolean | true if the year has 355 days | | dayOfWeek(date) | number | ISO weekday: 1=Monday, 7=Sunday | | dayOfYear(date) | number | Day position within the Hijri year | | weekOfYear(date) | number | Week position within the Hijri year | | daysInWeek(date) | number | Always 7 | | dateFromFields(fields) | Temporal.PlainDate | Construct ISO PlainDate from {year, month, day} in Hijri | | yearMonthFromFields(fields) | Temporal.PlainYearMonth | Construct from {year, month} in Hijri | | monthDayFromFields(fields) | Temporal.PlainMonthDay | Construct from {month, day} in Hijri | | dateAdd(date, duration) | Temporal.PlainDate | Add a duration; years/months applied in Hijri space, days in ISO space | | dateUntil(one, two, options) | Temporal.Duration | Difference between two dates; supports largestUnit: 'years'|'months'|'days'|'weeks' | | mergeFields(fields, additional) | Record | Merge field objects (Temporal protocol requirement) | | toString() | string | Calendar identifier ("hijri-uaq" or "hijri-fcna") |


Calendar Systems

| System | ID | Authority | Method | Coverage | |---|---|---|---|---| | Umm al-Qura | hijri-uaq | KACST / Saudi Arabia | Pre-calculated tables | 1318-1500 AH (1900-2076 CE) | | FCNA/ISNA | hijri-fcna | Fiqh Council of North America | Astronomical new moon (Meeus) | Unlimited (calculated) |

UAQ dates outside 1318-1500 AH throw RangeError. FCNA is unbounded but loses precision for very early dates.


Custom Calendars

Any engine registered in hijri-core can be wrapped in a Temporal calendar:

import { HijriCalendar } from 'temporal-hijri';
import { registerCalendar, getCalendar } from 'hijri-core';
import type { CalendarEngine } from 'hijri-core';

const myEngine: CalendarEngine = {
  id: 'local-sighting',
  toHijri(date) { /* ... */ return { hy, hm, hd }; },
  toGregorian(hy, hm, hd) { /* ... */ return new Date(...); },
  isValid(hy, hm, hd) { /* ... */ return true; },
  daysInMonth(hy, hm) { /* ... */ return 29; },
};

registerCalendar('local-sighting', myEngine);
const cal = new HijriCalendar(getCalendar('local-sighting'));
// cal.id === 'hijri-local-sighting'

TypeScript

All types are exported:

import type { HijriDate, ConversionOptions, HijriCalendarOptions } from 'temporal-hijri';

The package ships dual CJS/ESM builds with full .d.ts and .d.mts declarations.


Compatibility

  • Node.js 20, 22, 24
  • Any bundler supporting exports field (Vite, Webpack 5, Rollup, esbuild)
  • ESM (import) and CommonJS (require): both provided
  • No native Temporal required: works entirely with @js-temporal/polyfill

Documentation

Full reference, architecture notes, and algorithmic detail in the wiki.


Related


License

MIT. Copyright (c) 2026 Aric Camarata. See LICENSE.