hijri-core/README.md
Aric Camarata bb326d071c feat: initial release of hijri-core v1.0.0
Zero-dependency Hijri calendar engine with pluggable calendar registry.
Built-in Umm al-Qura (UAQ) and FCNA/ISNA calendar engines. Supports N
additional calendars via registerCalendar(). Pure Date.UTC arithmetic,
binary search on 184-entry UAQ table, Meeus Ch.49 new moon formula for
FCNA. 39 ESM + 20 CJS tests passing. Dual CJS/ESM build with full TypeScript
declarations.
2026-02-25 14:06:02 -05:00

4.3 KiB

hijri-core

npm CI license

Zero-dependency Hijri calendar engine. Supports the Umm al-Qura (UAQ) and FCNA/ISNA calendars out of the box. Extensible via a calendar registry for custom implementations.

Installation

npm install hijri-core
# or
pnpm add hijri-core

Quick Start

import { toHijri, toGregorian, isValidHijriDate, daysInHijriMonth } from 'hijri-core';

// Gregorian to Hijri (UAQ, default)
const hijri = toHijri(new Date(2025, 2, 1));
// { hy: 1446, hm: 9, hd: 1 }

// Hijri to Gregorian (UAQ)
const greg = toGregorian(1446, 9, 1);
// Date: 2025-03-01

// FCNA/ISNA calendar
const hijriFcna = toHijri(new Date('2025-03-01'), { calendar: 'fcna' });
const gregFcna  = toGregorian(1446, 9, 1, { calendar: 'fcna' });

// Validation and month length
isValidHijriDate(1444, 9, 1);  // true
daysInHijriMonth(1444, 9);     // 29

Custom Calendar

import { registerCalendar, toHijri, type CalendarEngine } from 'hijri-core';

const myEngine: CalendarEngine = {
  id: 'my-calendar',
  toHijri: (date) => { /* your logic */ return { hy: 1446, hm: 1, hd: 1 }; },
  toGregorian: (hy, hm, hd) => { /* your logic */ return new Date(); },
  isValid: (hy, hm, hd) => hy > 0 && hm >= 1 && hm <= 12 && hd >= 1,
  daysInMonth: (hy, hm) => 30,
};

registerCalendar('my-calendar', myEngine);

const result = toHijri(new Date(), { calendar: 'my-calendar' });

API

Conversion functions

Function Parameters Returns Notes
toHijri(date, opts?) Date, ConversionOptions? HijriDate | null Throws on invalid Date
toGregorian(hy, hm, hd, opts?) number, number, number, ConversionOptions? Date | null Throws on invalid Hijri
isValidHijriDate(hy, hm, hd, opts?) number, number, number, ConversionOptions? boolean
daysInHijriMonth(hy, hm, opts?) number, number, ConversionOptions? number

ConversionOptions.calendar defaults to 'uaq'. Pass 'fcna' or any registered calendar name.

Registry functions

Function Parameters Returns
registerCalendar(name, engine) string, CalendarEngine void
getCalendar(name) string CalendarEngine
listCalendars() none string[]

Data exports

Export Type Description
hDatesTable HijriYearRecord[] Full Umm al-Qura reference table (184 entries)
hmLong string[] Long month names (e.g., "Ramadan")
hmMedium string[] Medium month names (e.g., "Ramadan")
hmShort string[] Short month names (e.g., "Ram")
hwLong string[] Long weekday names
hwShort string[] Short weekday names
hwNumeric number[] Weekday numbers (1 = Sunday)

Custom Calendars

Implement the CalendarEngine interface to add any calendar system:

interface CalendarEngine {
  readonly id: string;
  toHijri(date: Date): HijriDate | null;
  toGregorian(hy: number, hm: number, hd: number): Date | null;
  isValid(hy: number, hm: number, hd: number): boolean;
  daysInMonth(hy: number, hm: number): number;
}

Register with registerCalendar('my-id', myEngine). Then pass { calendar: 'my-id' } to any conversion function.

Compatibility

  • Node.js 20, 22, 24
  • Modern browsers (ESM build)
  • CommonJS and ESM

TypeScript

import type { HijriDate, HijriYearRecord, CalendarEngine, ConversionOptions } from 'hijri-core';

Documentation

Full API reference and architecture notes: GitHub Wiki

License

MIT. Copyright (c) 2024-2026 Aric Camarata.