feat: v2.1.0 - delegate engine to hijri-core

Extract conversion logic to hijri-core. All Hijri algorithms now
live in that package and are re-exported with identical signatures.
Fix weekday, era, and time token bugs. Dual CJS/ESM build. Full
test suite. CI and wiki workflows. Zero breaking API changes.
This commit is contained in:
Aric Camarata 2026-02-25 15:26:28 -05:00
parent 3332c912f1
commit 20dc36541b
20 changed files with 79 additions and 88 deletions

View file

@ -20,7 +20,7 @@ jobs:
with:
node-version: ${{ matrix.node }}
cache: pnpm
- run: pnpm install
- run: pnpm install --frozen-lockfile
- run: pnpm run build
- run: node test.mjs
- run: node test-cjs.cjs
@ -35,7 +35,7 @@ jobs:
with:
node-version: 24
cache: pnpm
- run: pnpm install
- run: pnpm install --frozen-lockfile
- run: pnpm run typecheck
pack-check:
@ -48,7 +48,7 @@ jobs:
with:
node-version: 24
cache: pnpm
- run: pnpm install
- run: pnpm install --frozen-lockfile
- run: pnpm run build
- name: Verify pack contents
run: |

View file

@ -42,7 +42,7 @@ toHijri(new Date(1800, 0, 1), { calendar: 'uaq' }) // null (before table range)
Converts a Hijri date to a Gregorian `Date`.
```typescript
function toGregorian(hy: number, hm: number, hd: number, options?: ConversionOptions): Date | null
function toGregorian(hy: number, hm: number, hd: number, options?: ConversionOptions): Date
```
**Parameters**
@ -54,9 +54,9 @@ function toGregorian(hy: number, hm: number, hd: number, options?: ConversionOpt
| `hd` | `number` | Hijri day (129 or 130 depending on the month) |
| `options` | `ConversionOptions` | Optional. `{ calendar: 'uaq' }` (default) or `{ calendar: 'fcna' }`. |
**Returns** `Date | null`
**Returns** `Date`
Returns a UTC Date at midnight. Returns `null` if no table entry matches (UAQ only; for valid input that passes `isValidHijriDate` this should not occur).
Returns a UTC Date at midnight.
**Throws** `Error("Invalid Hijri date")` if the date fails validation.
@ -66,7 +66,7 @@ Returns a UTC Date at midnight. Returns `null` if no table entry matches (UAQ on
toGregorian(1444, 9, 1) // 2023-03-23T00:00:00.000Z
toGregorian(1446, 9, 1, { calendar: 'fcna' }) // 2025-03-01T00:00:00.000Z
toGregorian(1446, 10, 1, { calendar: 'fcna' }) // 2025-03-30T00:00:00.000Z
toGregorian(1444, 0, 1) // throws month 0 is invalid
toGregorian(1444, 0, 1) // throws: month 0 is invalid
```
---
@ -165,11 +165,11 @@ For FCNA: `hy` must be ≥ 1, `hm` must be 112, and `hd` must not exceed the
```javascript
isValidHijriDate(1444, 9, 1) // true
isValidHijriDate(1444, 9, 30) // false Ramadan 1444 has 29 days (UAQ)
isValidHijriDate(1317, 1, 1) // false before table range
isValidHijriDate(1501, 1, 1) // false sentinel boundary
isValidHijriDate(1, 1, 1, { calendar: 'fcna' }) // true FCNA supports all years
isValidHijriDate(1600, 1, 1, { calendar: 'fcna' }) // true beyond UAQ table, FCNA computed
isValidHijriDate(1444, 9, 30) // false - Ramadan 1444 has 29 days (UAQ)
isValidHijriDate(1317, 1, 1) // false - before table range
isValidHijriDate(1501, 1, 1) // false - sentinel boundary
isValidHijriDate(1, 1, 1, { calendar: 'fcna' }) // true - FCNA supports all years
isValidHijriDate(1600, 1, 1, { calendar: 'fcna' }) // true - beyond UAQ table, FCNA computed
```
---
@ -184,8 +184,8 @@ interface HijriDate {
}
// Calendar system selector.
// 'uaq' Umm al-Qura (default): table-based, covers 13181500 H.
// 'fcna' — FCNA/ISNA: astronomical calculation, works for all Hijri years ≥ 1 AH.
// 'uaq': Umm al-Qura (default): table-based, covers 13181500 H.
// 'fcna': FCNA/ISNA: astronomical calculation, works for all Hijri years >= 1 AH.
type CalendarSystem = 'uaq' | 'fcna';
interface ConversionOptions {
@ -218,14 +218,14 @@ import type {
```javascript
import {
hDatesTable, // HijriYearRecord[] 184 entries (183 real years + 1 sentinel)
hmLong, // string[12] full month names
hmMedium, // string[12] medium month names
hmShort, // string[12] abbreviated month names
hwLong, // string[7] full weekday names (Sunday-first order)
hwShort, // string[7] abbreviated weekday names
hwNumeric, // number[7] — weekday numbers (17, Sunday=1)
formatPatterns, // Record<string, string> token reference map
hDatesTable, // HijriYearRecord[] - 184 entries (183 real years + 1 sentinel)
hmLong, // string[12] - full month names
hmMedium, // string[12] - medium month names
hmShort, // string[12] - abbreviated month names
hwLong, // string[7] - full weekday names (Sunday-first order)
hwShort, // string[7] - abbreviated weekday names
hwNumeric, // number[7] - weekday numbers (1-7, Sunday=1)
formatPatterns, // Record<string, string> - token reference map
} from 'luxon-hijri';
```
@ -244,7 +244,7 @@ import {
| 8 | Ramadan | Ramadan | Ram |
| 9 | Shawwal | Shawwal | Shw |
| 10 | Dhul Qi'dah | Dhul-Qidah | DhQ |
| 11 | Dhul Hijjah | Dhul-Hijah | DhH |
| 11 | Dhul Hijjah | Dhul-Hijjah | DhH |
**Weekday arrays** (index 0 = Sunday, index 6 = Saturday)

View file

@ -2,13 +2,13 @@
## Overview
luxon-hijri is a pure table lookup implementation. It does not perform any astronomical calculation at runtime. Instead it ships the official Umm al-Qura calendar table — 183 Hijri years of precomputed data — and does binary search to navigate it.
luxon-hijri v2.1 delegates all calendar engine logic to [hijri-core](https://github.com/acamarata/hijri-core), a zero-dependency package that houses the Umm al-Qura table, FCNA algorithm, and calendar registry. This package re-exports the conversion functions and data with identical signatures, then adds Luxon-based date formatting on top.
Luxon is used only for two things: computing the equivalent Gregorian DateTime when format tokens like `iEEEE` (weekday) or time tokens need it, and for date arithmetic in `toGregorian` when adding days to the Muharram start date.
Luxon is used for one thing only: computing the equivalent Gregorian DateTime inside `formatHijriDate` when tokens like `iEEEE` (weekday) or time/timezone tokens are used. All conversion arithmetic (`toHijri`, `toGregorian`, `isValidHijriDate`) runs through hijri-core without Luxon.
## The Umm al-Qura Table
The table in [src/hDates.ts](../src/hDates.ts) has 184 rows. The first 183 are real Hijri years (13181500). The 184th is a sentinel entry (year 1501, `dpm: 0`) that records the Gregorian start date of 1 Muharram 1501 used as an upper boundary when converting Gregorian dates near the end of the table.
The table lives in `hijri-core` and is re-exported from this package as `hDatesTable`. It has 184 rows. The first 183 are real Hijri years (13181500). The 184th is a sentinel entry (year 1501, `dpm: 0`) that records the Gregorian start date of 1 Muharram 1501, used as an upper boundary when converting Gregorian dates near the end of the table.
Each row stores:
@ -20,7 +20,7 @@ Each row stores:
| `gm` | number | Gregorian month of 1 Muharram (1-based) |
| `gd` | number | Gregorian day of 1 Muharram |
Example entry: `{ hy: 1444, dpm: 0x0555, gy: 2022, gm: 7, gd: 30 }` — year 1444 started on July 30, 2022 (Gregorian). The `dpm` bitmask tells us which months have 30 days vs 29.
Example entry: `{ hy: 1444, dpm: 0x0555, gy: 2022, gm: 7, gd: 30 }`. Year 1444 started on July 30, 2022 (Gregorian). The `dpm` bitmask tells us which months have 30 days vs 29.
Reading `dpm`: for month `m` (1-based), the day count is `((dpm >> (m - 1)) & 1) ? 30 : 29`.
@ -48,7 +48,7 @@ Returns `null` for input before the first entry or if the sentinel is hit (input
3. Sum the day counts for months 1 through `hm - 1` using the `dpm` bitmask. Add `hd - 1` for the day within the current month. This gives `totalDays` elapsed since 1 Muharram of that year.
4. Use `DateTime.utc(gy, gm, gd).plus({ days: totalDays }).toJSDate()` to produce the Gregorian date as a UTC Date.
4. Sum days elapsed from 1 Muharram, then offset from the entry's UTC start date to produce a UTC midnight `Date`.
### Validation (`isValidHijriDate`)
@ -68,7 +68,7 @@ let _gregDt: DateTime | undefined;
function getGregDt(): DateTime {
if (!_gregDt) {
const greg = toGregorian(hijriDate.hy, hijriDate.hm, hijriDate.hd);
_gregDt = DateTime.fromJSDate(greg as Date, { zone: 'UTC' });
_gregDt = DateTime.fromJSDate(greg, { zone: 'UTC' });
}
return _gregDt;
}
@ -78,7 +78,7 @@ This avoids the Gregorian lookup entirely when only pure Hijri tokens are used.
**Weekday index mapping**: Luxon's `weekday` runs 1 (Monday) through 7 (Sunday). The weekday arrays (`hwLong`, `hwShort`, `hwNumeric`) are indexed 06 with Sunday at index 0. The mapping is:
```
```text
arrayIndex = luxonWeekday % 7
// Monday=1 → 1, Tuesday=2 → 2, ..., Saturday=6 → 6, Sunday=7 → 0
```
@ -87,11 +87,11 @@ arrayIndex = luxonWeekday % 7
All three functions (`toHijri`, `toGregorian`, `isValidHijriDate`) use binary search on a 184-entry table. This gives O(log 184) ≈ 8 comparisons worst case, compared to the O(184) linear scan used in v1.
For typical usage — converting a handful of dates per request — the difference is negligible. For batch workloads converting thousands of dates, the reduction is meaningful.
For typical usage, converting a handful of dates per request, the difference is negligible. For batch workloads converting thousands of dates, the reduction is meaningful.
## FCNA Calendar Engine (`src/fcna.ts`)
## FCNA Calendar Engine
The FCNA/ISNA calendar is computed astronomically rather than looked up from a table. It works for all Hijri years, not just the 13181500 range covered by the UAQ table.
The FCNA/ISNA calendar is computed astronomically rather than looked up from a table. It works for all Hijri years, not just the 13181500 range covered by the UAQ table. The implementation lives in [hijri-core](https://github.com/acamarata/hijri-core) and is accessed through the calendar registry.
### FCNA Criterion
@ -105,15 +105,15 @@ New moon times come from Jean Meeus, *Astronomical Algorithms* (2nd ed.), Chapte
For years within the UAQ table (13181500 H), the UAQ month start date is used as the anchor for the nearest-new-moon search. This ensures the FCNA computation is consistent with the validated UAQ dataset for the date range where both systems overlap.
For years outside the table, the anchor comes from the Islamic epoch (1 Muharram 1 AH JDE 1948438.5) plus the mean number of synodic months elapsed. Meeus corrections then adjust the mean estimate to the actual conjunction time.
For years outside the table, the anchor comes from the Islamic epoch (1 Muharram 1 AH approximately JDE 1948438.5) plus the mean number of synodic months elapsed. Meeus corrections then adjust the mean estimate to the actual conjunction time.
### Nearest New Moon Search
Given an anchor UTC timestamp, the engine estimates k, then checks k2 through k+2 (five candidates) for the corrected new moon closest to the anchor. This handles any estimation error from the anchor strategy.
Given an anchor UTC timestamp, the engine estimates k, then checks k-2 through k+2 (five candidates) for the corrected new moon closest to the anchor. This handles any estimation error from the anchor strategy.
### Calendar Conversion
`fcnaToGregorian(hy, hm, hd)`: sum the FCNA month-start offsets and add hd1 days.
`fcnaToGregorian(hy, hm, hd)`: sum the FCNA month-start offsets and add hd-1 days.
`fcnaToHijri(date)`: shift back ~15 days to ensure kApprox points to the current month's conjunction rather than the next. Try three adjacent k values; for each, compute the FCNA month start and next month start, then check whether the input falls within that window. Map the matching k to (hy, hm) via the K_EPOCH offset, and compute hd from the day offset.
@ -121,17 +121,15 @@ FCNA uses UTC date components (`getUTCFullYear`, `getUTCMonth`, `getUTCDate`) be
### Performance
FCNA conversion calls `newMoonJDE` (the Meeus formula) 35 times per call. Each call is a fixed set of floating-point trig operations sub-millisecond in any modern JS engine. Month length computation (`fcnaDaysInMonth`) calls it twice more. No caching is done since usage patterns are typically small-batch.
FCNA conversion calls `newMoonJDE` (the Meeus formula) 35 times per call. Each call is a fixed set of floating-point trig operations, sub-millisecond in any modern JS engine. Month length computation calls it twice more. No caching is done since usage patterns are typically small-batch.
## Why Luxon
Luxon is used for two narrow purposes:
Luxon is used for one purpose only in this package:
1. `DateTime.utc(gy, gm, gd).plus({ days: n }).toJSDate()` in `toGregorian` — cleaner than manual day arithmetic across month/year boundaries.
`DateTime.fromJSDate(greg, { zone: 'UTC' })` in `formatHijriDate` provides `.weekday` and `.toFormat()` for time/timezone tokens.
2. `DateTime.fromJSDate(greg, { zone: 'UTC' })` in `formatHijriDate` — provides `.weekday` and `.toFormat()` for time/timezone tokens.
Neither use requires Luxon's timezone database for standard Hijri date formatting. If you only use Hijri date tokens (no time/timezone tokens), the Gregorian DateTime is never constructed.
All conversion arithmetic (`toHijri`, `toGregorian`, `isValidHijriDate`) runs through hijri-core without Luxon. Neither Luxon's timezone database nor its date arithmetic is needed for standard Hijri date formatting. If you only use Hijri date tokens (no time/timezone tokens), the Gregorian DateTime is never constructed.
---

View file

@ -4,7 +4,7 @@
The Islamic calendar (also called the Hijri calendar) is a lunar calendar consisting of 12 months in a year of 354 or 355 days. Because the lunar year is roughly 11 days shorter than the solar year, the Islamic calendar cycles through all seasons over a period of approximately 33 years.
The calendar begins from the year of the Hijra the migration of the Prophet Muhammad from Mecca to Medina in 622 CE. That year is 1 AH (Anno Hegirae). The Hijri year is written with the suffix "H" or "AH."
The calendar begins from the year of the Hijra: the migration of the Prophet Muhammad from Mecca to Medina in 622 CE. That year is 1 AH (Anno Hegirae). The Hijri year is written with the suffix "H" or "AH."
Each month begins with the sighting of the crescent moon (hilal). Because actual lunar visibility depends on atmospheric conditions and geographic location, two methods exist for determining month start:

View file

@ -35,7 +35,7 @@ formatHijriDate({ hy: 1444, hm: 9, hd: 1 }, 'iEEEE, iD iMMMM iYYYY ioooo');
- Two calendars: Umm al-Qura (default, table-based, 13181500 H) and FCNA/ISNA (astronomical, all years)
- FCNA criterion: conjunction before 12:00 UTC → month starts D+1, else D+2 (Meeus Ch.49 algorithm)
- Zero runtime dependencies beyond Luxon
- Synchronous no async, no loading delay
- Synchronous: no async, no loading delay
- Dual CJS and ESM, full TypeScript definitions
- Weekday format bug from v1 is fixed in v2 (weekday tokens now use correct Gregorian conversion)

View file

@ -11,7 +11,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
### Changed
- Engine logic extracted to `hijri-core` (new dependency). All Hijri conversion algorithms now live in that package and are re-exported from `luxon-hijri` with identical signatures. Zero breaking changes to the public API.
- `src/hDates.ts`, `src/hMonths.ts`, `src/hWeekdays.ts`, `src/fcna.ts`, `src/utils.ts`, `src/toHijri.ts`, `src/toGregorian.ts` all now delegate to `hijri-core`. The UAQ table, FCNA engine, month/weekday names, and conversion functions have a single source of truth across the hijri ecosystem.
- `src/hDates.ts`, `src/hMonths.ts`, `src/hWeekdays.ts`, `src/fcna.ts`, `src/utils.ts`, `src/toHijri.ts`, `src/toGregorian.ts`: all now delegate to `hijri-core`. The UAQ table, FCNA engine, month/weekday names, and conversion functions have a single source of truth across the hijri ecosystem.
- `hijri-core ^1.0.0` added as a runtime dependency. `luxon` stays as a runtime dependency (still needed by `formatHijriDate` for time and timezone tokens).
## [2.0.0] - 2026-02-25
@ -20,7 +20,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
- **FCNA/ISNA calendar support**: `toHijri`, `toGregorian`, and `isValidHijriDate` now accept an optional `{ calendar: 'fcna' }` option. The FCNA criterion: if the astronomical conjunction occurs before 12:00 UTC the month begins D+1, otherwise D+2. New moon times use the full Meeus Chapter 49 formula (accurate to within a few minutes for 10003000 CE). The FCNA calendar works for all Hijri years, not just the 13181500 H range covered by the UAQ table.
- New exported types: `CalendarSystem` (`'uaq' | 'fcna'`) and `ConversionOptions` (`{ calendar?: CalendarSystem }`).
- `src/fcna.ts`: standalone FCNA engine — Meeus Ch.49 new moon algorithm, UAQ anchor lookup, FCNA criterion, and full Hijri↔Gregorian conversion without external dependencies beyond the existing hDatesTable.
- `src/fcna.ts`: standalone FCNA engine. Meeus Ch.49 new moon algorithm, UAQ anchor lookup, FCNA criterion, and full Hijri/Gregorian conversion without external dependencies beyond the existing hDatesTable.
- Dual CJS and ESM build via tsup (`dist/index.cjs`, `dist/index.mjs`)
- Full TypeScript declarations for both module formats (`dist/index.d.ts`, `dist/index.d.mts`)
- `src/types.ts` with named exported `HijriDate` and `HijriYearRecord` interfaces

View file

@ -53,7 +53,7 @@ Throws `Error("Invalid Gregorian date")` if `date` is not a valid `Date`.
```javascript
toHijri(new Date(2024, 6, 7, 12)) // { hy: 1446, hm: 1, hd: 1 } (UAQ)
toHijri(new Date(2025, 2, 1, 12), { calendar: 'fcna' }) // { hy: 1446, hm: 9, hd: 1 } (FCNA)
toHijri(new Date(1800, 0, 1)) // null before UAQ table range
toHijri(new Date(1800, 0, 1)) // null - before UAQ table range
```
### `toGregorian(hy, hm, hd, options?)`
@ -61,7 +61,7 @@ toHijri(new Date(1800, 0, 1)) // null — before U
Converts a Hijri date to a Gregorian `Date` at UTC midnight.
```typescript
function toGregorian(hy: number, hm: number, hd: number, options?: ConversionOptions): Date | null
function toGregorian(hy: number, hm: number, hd: number, options?: ConversionOptions): Date
```
Throws `Error("Invalid Hijri date")` if the date is invalid for the selected calendar.
@ -142,14 +142,14 @@ interface HijriYearRecord {
```javascript
import {
hDatesTable, // HijriYearRecord[] the full Umm al-Qura table (184 entries)
hmLong, // string[12] full month names
hmMedium, // string[12] medium month names
hmShort, // string[12] abbreviated month names
hwLong, // string[7] full weekday names (Sunday first)
hwShort, // string[7] abbreviated weekday names
hwNumeric, // number[7] — weekday numbers (17, Sunday=1)
formatPatterns, // Record<string, string> token reference
hDatesTable, // HijriYearRecord[] - the full Umm al-Qura table (184 entries)
hmLong, // string[12] - full month names
hmMedium, // string[12] - medium month names
hmShort, // string[12] - abbreviated month names
hwLong, // string[7] - full weekday names (Sunday first)
hwShort, // string[7] - abbreviated weekday names
hwNumeric, // number[7] - weekday numbers (1-7, Sunday=1)
formatPatterns, // Record<string, string> - token reference
} from 'luxon-hijri';
```
@ -161,7 +161,7 @@ import {
## Architecture
The UAQ engine is a pure table lookup with binary search (O(log 183)). The FCNA engine computes new moon times astronomically using the Meeus Ch.49 formula 3 to 5 trigonometric evaluations per call, sub-millisecond on any modern JS engine.
The UAQ engine is a pure table lookup with binary search (O(log 183)). The FCNA engine computes new moon times astronomically using the Meeus Ch.49 formula: 3 to 5 trigonometric evaluations per call, sub-millisecond on any modern JS engine.
For more detail see the [Architecture wiki page](https://github.com/acamarata/luxon-hijri/wiki/Architecture).
@ -178,7 +178,7 @@ import { toHijri, toGregorian, formatHijriDate, isValidHijriDate } from 'luxon-h
import type { HijriDate, HijriYearRecord, CalendarSystem, ConversionOptions } from 'luxon-hijri';
const h: HijriDate | null = toHijri(new Date());
const g: Date | null = toGregorian(1444, 9, 1, { calendar: 'fcna' });
const g: Date = toGregorian(1444, 9, 1, { calendar: 'fcna' });
```
## Documentation
@ -188,9 +188,9 @@ Full API reference, architecture notes, calendar background, and format token gu
## Related
- [nrel-spa](https://www.npmjs.com/package/nrel-spa) NREL Solar Position Algorithm (pure JS)
- [pray-calc](https://www.npmjs.com/package/pray-calc) Islamic prayer times, depends on nrel-spa
- [solar-spa](https://www.npmjs.com/package/solar-spa) NREL SPA compiled to WebAssembly
- [nrel-spa](https://www.npmjs.com/package/nrel-spa): NREL Solar Position Algorithm (pure JS)
- [pray-calc](https://www.npmjs.com/package/pray-calc): Islamic prayer times, depends on nrel-spa
- [solar-spa](https://www.npmjs.com/package/solar-spa): NREL SPA compiled to WebAssembly
## License

View file

@ -53,7 +53,7 @@
"typescript"
],
"dependencies": {
"hijri-core": "file:../hijri-core",
"hijri-core": "^1.0.0",
"luxon": "^3.5.0"
},
"devDependencies": {

View file

@ -9,8 +9,8 @@ importers:
.:
dependencies:
hijri-core:
specifier: file:../hijri-core
version: file:../hijri-core
specifier: ^1.0.0
version: 1.0.0
luxon:
specifier: ^3.5.0
version: 3.7.2
@ -410,8 +410,8 @@ packages:
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
hijri-core@file:../hijri-core:
resolution: {directory: ../hijri-core, type: directory}
hijri-core@1.0.0:
resolution: {integrity: sha512-wImBZLBKbEWEEUE1nrc1CFY/uvx4XjGNWYChImJZlswXIVhrBCzSVaj6DP1AU2gUMJ6KDh2ygXo/u/Qx232CXA==}
engines: {node: '>=20'}
joycon@3.1.1:
@ -801,7 +801,7 @@ snapshots:
fsevents@2.3.3:
optional: true
hijri-core@file:../hijri-core: {}
hijri-core@1.0.0: {}
joycon@3.1.1: {}

View file

@ -10,15 +10,14 @@ const TOKEN_RE =
/iYYYY|iYY|iMMMM|iMMM|iMM|iM|iDD|iD|iEEEE|iEEE|iE|ioooo|iooo|HH|H|hh|h|mm|m|ss|s|a|z{1,3}|ZZ|Z/g;
export function formatHijriDate(hijriDate: HijriDate, format: string): string {
// Lazy Gregorian DateTime computed at most once per format call,
// Lazy Gregorian DateTime, computed at most once per format call,
// only when a token that needs it is encountered.
let _gregDt: DateTime | undefined;
function getGregDt(): DateTime {
if (!_gregDt) {
const greg = toGregorian(hijriDate.hy, hijriDate.hm, hijriDate.hd);
// toGregorian throws for invalid input, so greg is non-null here.
_gregDt = DateTime.fromJSDate(greg as Date, { zone: 'UTC' });
_gregDt = DateTime.fromJSDate(greg, { zone: 'UTC' });
}
return _gregDt;
}

View file

@ -40,8 +40,10 @@ export const formatPatterns = {
// Timezone
z: 'Timezone (abbreviated)',
zz: 'Timezone (full)',
Z: 'Timezone offset from UTC',
zz: 'Timezone (medium)',
zzz: 'Timezone (full)',
Z: 'Timezone offset from UTC (+HH:MM)',
ZZ: 'Timezone offset from UTC (condensed)',
};
// Export the patterns for use in the rest of the package

View file

@ -1,3 +1,3 @@
// hDates.ts re-exports from hijri-core; table is maintained in the core package
// hDates.ts: re-exports from hijri-core; table is maintained in the core package
export { hDatesTable } from 'hijri-core';
export type { HijriYearRecord } from 'hijri-core';

View file

@ -1,2 +1,2 @@
// hMonths.ts re-exports from hijri-core
// hMonths.ts: re-exports from hijri-core
export { hmLong, hmMedium, hmShort } from 'hijri-core';

View file

@ -1,2 +1,2 @@
// hWeekdays.ts re-exports from hijri-core
// hWeekdays.ts: re-exports from hijri-core
export { hwLong, hwShort, hwNumeric } from 'hijri-core';

View file

@ -1,4 +0,0 @@
{
"months": ["محرم", "صفر", "..."],
"weekdays": ["الأحد", "الاثنين", "..."]
}

View file

@ -1,4 +0,0 @@
{
"months": ["Muharram", "Safar", "..."],
"weekdays": ["Sunday", "Monday", "..."]
}

View file

@ -1,8 +1,8 @@
// toGregorian.ts thin wrapper over hijri-core; preserves throw-on-invalid behavior
// toGregorian.ts: thin wrapper over hijri-core; preserves throw-on-invalid behavior
import { toGregorian as coreToGregorian } from 'hijri-core';
import type { ConversionOptions } from './types';
export function toGregorian(hy: number, hm: number, hd: number, options?: ConversionOptions): Date | null {
export function toGregorian(hy: number, hm: number, hd: number, options?: ConversionOptions): Date {
const result = coreToGregorian(hy, hm, hd, options);
if (result === null) throw new Error('Invalid Hijri date');
return result;

View file

@ -1,2 +1,2 @@
// toHijri.ts delegates to hijri-core
// toHijri.ts: delegates to hijri-core
export { toHijri } from 'hijri-core';

View file

@ -1,4 +1,4 @@
// types.ts re-exports from hijri-core for backward compatibility
// types.ts: re-exports from hijri-core for backward compatibility
export type { HijriDate, HijriYearRecord, ConversionOptions } from 'hijri-core';
// CalendarSystem documents the built-in calendar identifiers.

View file

@ -1,2 +1,2 @@
// utils.ts delegates to hijri-core
// utils.ts: delegates to hijri-core
export { isValidHijriDate } from 'hijri-core';