dayjs-hijri-plus/README.md
Aric Camarata 96dd9c5688 feat: initial release of dayjs-hijri-plus v1.0.0
Day.js plugin adding Hijri calendar support via hijri-core. Adds
toHijri(), fromHijri(), hijriYear/Month/Day(), isValidHijri(), and
formatHijri() to all Day.js instances. Supports UAQ and FCNA calendars
via ConversionOptions. Format token escaping wraps substituted values
in Day.js bracket syntax to prevent re-interpretation as format tokens.
14 ESM + 8 CJS tests passing. Dual CJS/ESM build.
2026-02-25 14:15:07 -05:00

190 lines
6.4 KiB
Markdown

# dayjs-hijri-plus
[![npm version](https://img.shields.io/npm/v/dayjs-hijri-plus)](https://www.npmjs.com/package/dayjs-hijri-plus)
[![CI](https://github.com/acamarata/dayjs-hijri-plus/actions/workflows/ci.yml/badge.svg)](https://github.com/acamarata/dayjs-hijri-plus/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
A Day.js plugin that adds Hijri calendar support. Converts Gregorian dates to and from Hijri, provides Hijri-aware formatting, and delegates all calendar logic to [hijri-core](https://github.com/acamarata/hijri-core) — keeping this package thin and testable.
Supports Umm al-Qura (UAQ) and FCNA/ISNA calendars out of the box. Custom calendar engines can be registered at runtime.
## Installation
```sh
pnpm add dayjs dayjs-hijri-plus hijri-core
```
Both `dayjs` and `hijri-core` are peer dependencies and must be installed alongside this plugin.
## Quick Start
```ts
import dayjs from 'dayjs';
import hijriPlugin from 'dayjs-hijri-plus';
dayjs.extend(hijriPlugin);
// Convert a Gregorian date to Hijri
const d = dayjs(new Date(2023, 2, 23));
const hijri = d.toHijri();
// => { hy: 1444, hm: 9, hd: 1 } (1 Ramadan 1444 AH)
// Format using Hijri tokens mixed with standard Day.js tokens
d.formatHijri('iYYYY-iMM-iDD'); // => '1444-09-01'
d.formatHijri('iD iMMMM iYYYY'); // => '1 Ramadan 1444'
d.formatHijri('iD iMMMM iYYYY [at] HH:mm'); // => '1 Ramadan 1444 at 00:00'
// Individual Hijri components
d.hijriYear(); // => 1444
d.hijriMonth(); // => 9
d.hijriDay(); // => 1
// Construct a Day.js instance from a Hijri date
const eid = dayjs.fromHijri(1444, 10, 1);
eid.format('YYYY-MM-DD'); // => '2023-04-21'
// FCNA/ISNA calendar variant
d.toHijri({ calendar: 'fcna' }); // => { hy: 1444, hm: 9, hd: 2 } (varies by month)
```
## API
### dayjs.extend(hijriPlugin)
Register the plugin with your Day.js instance. Call once before using any plugin methods.
### Instance Methods
#### `.toHijri(opts?)`
Convert the Day.js date to a Hijri date object.
| Parameter | Type | Description |
| --- | --- | --- |
| `opts` | `ConversionOptions` | Optional. `{ calendar: 'uaq' \| 'fcna' \| string }` |
Returns `HijriDate | null`. Returns `null` if the date is outside the supported range (approximately 1900-2077 CE for UAQ).
```ts
dayjs('2023-03-23').toHijri();
// => { hy: 1444, hm: 9, hd: 1 }
```
#### `.isValidHijri(opts?)`
Check whether the date maps to a valid Hijri date in the supported range.
Returns `boolean`.
#### `.hijriYear(opts?)`
Returns the Hijri year as a `number`, or `null` if out of range.
#### `.hijriMonth(opts?)`
Returns the Hijri month (1-12) as a `number`, or `null` if out of range.
#### `.hijriDay(opts?)`
Returns the Hijri day (1-30) as a `number`, or `null` if out of range.
#### `.formatHijri(formatStr, opts?)`
Format the date using a mix of Hijri tokens and standard Day.js tokens.
| Parameter | Type | Description |
| --- | --- | --- |
| `formatStr` | `string` | Format string — see token table below |
| `opts` | `ConversionOptions` | Optional calendar selection |
Returns `string`. Returns an empty string if the date is out of range.
Hijri tokens are replaced first. The resulting string is then passed to Day.js `.format()`, so all standard tokens (YYYY, MM, DD, HH, mm, ss, etc.) resolve normally.
### Static Methods
#### `dayjs.fromHijri(hy, hm, hd, opts?)`
Construct a Day.js instance from a Hijri date.
| Parameter | Type | Description |
| --- | --- | --- |
| `hy` | `number` | Hijri year |
| `hm` | `number` | Hijri month (1-12) |
| `hd` | `number` | Hijri day (1-30) |
| `opts` | `ConversionOptions` | Optional calendar selection |
Returns a `dayjs.Dayjs` instance. Throws `Error` if the Hijri date is invalid or outside the table range.
## Format Tokens
All Hijri-specific tokens use the `i` prefix.
| Token | Example | Description |
| --- | --- | --- |
| `iYYYY` | `1444` | 4-digit Hijri year |
| `iYY` | `44` | 2-digit Hijri year |
| `iMMMM` | `Ramadan` | Full Hijri month name |
| `iMMM` | `Ramadan` | Medium Hijri month name |
| `iMM` | `09` | Zero-padded Hijri month number |
| `iM` | `9` | Hijri month number |
| `iDD` | `01` | Zero-padded Hijri day |
| `iD` | `1` | Hijri day number |
| `iEEEE` | `Yawm al-Khamis` | Full weekday name |
| `iEEE` | `Kham` | Short weekday name |
| `iE` | `5` | Weekday number (1=Sunday ... 7=Saturday) |
| `ioooo` | `AH` | Era (Anno Hegirae) |
| `iooo` | `AH` | Era (short form, same as ioooo) |
Standard Day.js tokens pass through untouched. Square-bracket escaping (`[literal text]`) also works as expected.
## Calendar Systems
Two calendars ship with hijri-core:
- **`uaq`** (default) — Umm al-Qura, the official calendar of Saudi Arabia. Table-based, covers approximately 1318-1500 AH (1900-2077 CE).
- **`fcna`** — Fiqh Council of North America calendar. Uses an astronomical calculation with fixed criteria, independent of moon sighting.
Select a calendar by passing `{ calendar: 'fcna' }` to any method. The default is `'uaq'` when no option is provided.
Custom calendar engines can be registered:
```ts
import { registerCalendar } from 'dayjs-hijri-plus';
import type { CalendarEngine } from 'dayjs-hijri-plus';
const myEngine: CalendarEngine = { ... };
registerCalendar('my-calendar', myEngine);
dayjs().toHijri({ calendar: 'my-calendar' });
```
See the [hijri-core CalendarEngine interface](https://github.com/acamarata/hijri-core) for the full contract.
## TypeScript
Full TypeScript support is included. The plugin augments the Day.js module to add types for all instance and static methods.
```ts
import type { HijriDate, ConversionOptions } from 'dayjs-hijri-plus';
const h: HijriDate = dayjs().toHijri()!;
const opts: ConversionOptions = { calendar: 'fcna' };
```
No `@types` package is needed.
## Documentation
Full API reference, architecture notes, and calendar system comparisons are on the [GitHub Wiki](https://github.com/acamarata/dayjs-hijri-plus/wiki).
## Related
- [hijri-core](https://github.com/acamarata/hijri-core) — the zero-dependency Hijri calendar engine this plugin wraps
- [luxon-hijri](https://github.com/acamarata/luxon-hijri) — the same Hijri conversion for Luxon users
- [pray-calc](https://github.com/acamarata/pray-calc) — Islamic prayer time calculation
- [nrel-spa](https://github.com/acamarata/nrel-spa) — NREL Solar Position Algorithm in pure JavaScript
## License
MIT. Copyright (c) 2026 Aric Camarata.