No description
Find a file
Aric Camarata 3c762bd694
Some checks failed
CI / Test (Node 20) (push) Failing after 32s
CI / Test (Node 22) (push) Failing after 33s
CI / Test (Node 24) (push) Failing after 38s
CI / Lint (push) Failing after 40s
CI / Typecheck (push) Failing after 29s
CI / Pack check (push) Failing after 34s
CI / Coverage (push) Failing after 3s
add opt-in anonymous telemetry (#1)
* add opt-in telemetry via @acamarata/telemetry (off by default)

* chore: update lockfile for @acamarata/telemetry devDep

* chore: fix prettier formatting on telemetry import
2026-06-30 15:56:49 -04:00
.github chore: P1 compliance updates (AGENTS.md symlink, docs, types) 2026-05-30 18:38:10 -04:00
src add opt-in anonymous telemetry (#1) 2026-06-30 15:56:49 -04:00
.editorconfig feat: initial release of hijri-core v1.0.0 2026-02-25 14:06:02 -05:00
.gitignore chore: corepack migration + typedoc config + ADR-015 CI updates (P1) 2026-05-29 07:15:57 -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
CHANGELOG.md chore: bump to v1.0.4 2026-06-13 11:52:20 -04:00
eslint.config.mjs ci: fix eslint config, add missing ts-eslint devDeps, format src 2026-05-31 08:47:31 -04:00
hijri-core.test.ts fix: interpret Dates by UTC calendar day in UAQ engine for exact round-trips 2026-06-10 16:32:01 -04:00
LICENSE feat: initial release of hijri-core v1.0.0 2026-02-25 14:06:02 -05:00
package.json add opt-in anonymous telemetry (#1) 2026-06-30 15:56:49 -04:00
pnpm-lock.yaml add opt-in anonymous telemetry (#1) 2026-06-30 15:56:49 -04:00
pnpm-workspace.yaml feat: initial release of hijri-core v1.0.0 2026-02-25 14:06:02 -05:00
README.md fix: interpret Dates by UTC calendar day in UAQ engine for exact round-trips 2026-06-10 16:32:01 -04:00
TELEMETRY.md add opt-in anonymous telemetry (#1) 2026-06-30 15:56:49 -04:00
test-cjs.cjs fix: interpret Dates by UTC calendar day in UAQ engine for exact round-trips 2026-06-10 16:32:01 -04:00
test.mjs fix: interpret Dates by UTC calendar day in UAQ engine for exact round-trips 2026-06-10 16:32:01 -04:00
tsconfig.json chore: adopt shared config packages (tsconfig, eslint, prettier) 2026-05-30 15:07:38 -04:00
tsup.config.ts feat: initial release of hijri-core v1.0.0 2026-02-25 14:06:02 -05:00
typedoc.json docs: add TypeDoc API generation (typedoc@0.28.19 + typedoc-plugin-markdown@4.11.0) 2026-05-30 16:41:58 -04:00
vitest.config.ts fix: interpret Dates by UTC calendar day in UAQ engine for exact round-trips 2026-06-10 16:32:01 -04:00

hijri-core

npm CI license wiki

Zero-dependency Hijri calendar engine for JavaScript and TypeScript. Supports the Umm al-Qura (UAQ) and FCNA/ISNA calendars out of the box. A pluggable registry lets you add custom calendar implementations at runtime.

Installation

npm install 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
const greg = toGregorian(1446, 9, 1);
// Date: 2025-03-01

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

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

Day boundaries and time zones

hijri-core maps civil calendar days one-to-one (tabular UAQ, computed FCNA). The religious Hijri day beginning at sunset is intentionally out of scope.

toHijri reads the input Date's UTC calendar day (getUTCFullYear, getUTCMonth, getUTCDate). toGregorian returns a UTC-midnight Date. This means round-trips are exact and results are identical on every machine regardless of local time zone:

// Safe on any host — UTC-explicit construction
const greg = toGregorian(1446, 9, 1);          // 2025-03-01T00:00:00.000Z
const back = toHijri(greg!);                   // { hy: 1446, hm: 9, hd: 1 } — always exact

// ISO date-only strings parse as UTC midnight — correct
toHijri(new Date('2025-03-01'));               // { hy: 1446, hm: 9, hd: 1 }

// For a local wall-clock date, construct explicitly in UTC
toHijri(new Date(Date.UTC(2025, 2, 1)));       // { hy: 1446, hm: 9, hd: 1 }

// Avoid local Date constructor for date-only conversions — breaks on UTC+13
// toHijri(new Date(2025, 2, 1))  ← do NOT do this

Custom Calendars

Implement CalendarEngine and call registerCalendar('my-id', engine). Pass { calendar: 'my-id' } to any conversion function.

TypeScript

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

Documentation

Full API reference, architecture notes, and calendar background: GitHub Wiki

Acknowledgments

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

License

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