No description
Find a file
2026-05-15 15:27:00 -04:00
.github chore: align repository structure with portfolio documentation standards 2026-05-15 15:27:00 -04:00
src refactor: code quality improvements across the board 2026-03-08 11:38:10 -04:00
.editorconfig feat: initial release of hijri-core v1.0.0 2026-02-25 14:06:02 -05:00
.gitignore refactor: code quality improvements across the board 2026-03-08 11:38:10 -04:00
.npmrc chore: clear .npmrc to remove pnpm-only key that warns on npm publish 2026-02-25 15:08:47 -05:00
.nvmrc feat: initial release of hijri-core v1.0.0 2026-02-25 14:06:02 -05:00
.prettierrc refactor: code quality improvements across the board 2026-03-08 11:38:10 -04:00
CHANGELOG.md feat: initial release of hijri-core v1.0.0 2026-02-25 14:06:02 -05:00
eslint.config.mjs refactor: code quality improvements across the board 2026-03-08 11:38:10 -04:00
LICENSE feat: initial release of hijri-core v1.0.0 2026-02-25 14:06:02 -05:00
package.json ci: pin pnpm to version 10 in all CI jobs 2026-03-08 16:37:33 -04:00
pnpm-lock.yaml refactor: code quality improvements across the board 2026-03-08 11:38:10 -04:00
pnpm-workspace.yaml feat: initial release of hijri-core v1.0.0 2026-02-25 14:06:02 -05:00
README.md style: replace em dashes with colons in docs 2026-03-08 17:28:03 -04:00
test-cjs.cjs refactor: code quality improvements across the board 2026-03-08 11:38:10 -04:00
test.mjs refactor: code quality improvements across the board 2026-03-08 11:38:10 -04:00
tsconfig.json refactor: code quality improvements across the board 2026-03-08 11:38:10 -04:00
tsup.config.ts feat: initial release of hijri-core v1.0.0 2026-02-25 14:06:02 -05:00

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 Returns null on invalid input
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.

Architecture

The UAQ engine performs a binary search over the 184-entry table: O(log 183) per conversion. The FCNA engine computes new moon times using the Meeus Ch. 49 algorithm (3 to 5 trigonometric evaluations per call). The registry pattern lets any consumer add custom calendar systems at runtime without modifying the core.

For more detail see the Architecture wiki page.

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

Acknowledgments

The Umm al-Qura calendar table is derived from data published by the King Abdulaziz City for Science and Technology (KACST), Saudi Arabia. The FCNA new moon algorithm follows Jean Meeus, "Astronomical Algorithms," 2nd ed., Chapter 49.

License

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