luxon-hijri/.github/wiki/guides/advanced.md

126 lines
3.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Advanced Usage
## Format tokens
All Hijri-specific tokens use the `i` prefix. For the full token table, see the [API Reference](../API-Reference).
Common tokens:
| Token | Example | Description |
|-------|---------|-------------|
| `iD` | `1``30` | Hijri day, no padding |
| `iDD` | `01``30` | Hijri day, zero-padded |
| `iM` | `1``12` | Hijri month number, no padding |
| `iMM` | `01``12` | Hijri month number, zero-padded |
| `iMMMM` | `Ramadan` | Full Hijri month name |
| `iYY` | `46` | Last two digits of Hijri year |
| `iYYYY` | `1446` | Full Hijri year |
| `ioooo` | `AH` | Hijri era |
```js
import { toHijri, formatHijriDate } from 'luxon-hijri';
const h = toHijri(new Date('2025-03-20'));
console.log(formatHijriDate(h, 'iDD/iMM/iYYYY')); // 20/09/1446
console.log(formatHijriDate(h, 'iD iMMMM iYYYY')); // 20 Ramadan 1446
console.log(formatHijriDate(h, 'iD iMMMM iYYYY ioooo')); // 20 Ramadan 1446 AH
```
## Hijri date arithmetic with Luxon
Luxon handles Gregorian arithmetic. Use `toGregorian` to convert Hijri endpoints, then work in Gregorian:
```js
import { DateTime } from 'luxon';
import { toHijri, toGregorian } from 'luxon-hijri';
// Find when Eid al-Fitr (1 Shawwal) starts for this year
const today = new Date();
const h = toHijri(today);
if (h) {
const eidStart = toGregorian(h.hy, 10, 1); // 1 Shawwal
const eid = DateTime.fromJSDate(eidStart);
console.log(`Eid al-Fitr ${h.hy}: ${eid.toFormat('MMMM d, yyyy')}`);
}
```
## Generating a Hijri month calendar
The UAQ table encodes day counts per month in a bitmask. To iterate a month, convert each Hijri day to Gregorian and stop when `toGregorian` throws:
```js
import { toGregorian } from 'luxon-hijri';
import { DateTime } from 'luxon';
const HY = 1446;
const HM = 9; // Ramadan
// Determine the month length (29 or 30 days)
let days = 29;
try { toGregorian(HY, HM, 30); days = 30; } catch (_) {}
const NAMES = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
console.log(`Ramadan ${HY}\n`);
console.log(NAMES.join(' '));
const firstGreg = DateTime.fromJSDate(toGregorian(HY, HM, 1));
let line = ' '.repeat(firstGreg.weekday % 7); // Sunday = 0
for (let d = 1; d <= days; d++) {
const greg = DateTime.fromJSDate(toGregorian(HY, HM, d));
line += String(d).padStart(3) + ' ';
if (greg.weekday === 6) { // Saturday ends row
console.log(line);
line = '';
}
}
if (line.trim()) console.log(line);
```
## FCNA vs UAQ differences
FCNA and UAQ can differ by a day around month transitions:
```js
import { toHijri } from 'luxon-hijri';
const borderDates = [
new Date('2025-02-28'),
new Date('2025-03-01'),
new Date('2025-03-02'),
];
for (const d of borderDates) {
const uaq = toHijri(d, { calendar: 'uaq' });
const fcna = toHijri(d, { calendar: 'fcna' });
const fmt = h => h ? `${h.hd}/${h.hm}/${h.hy}` : 'null';
console.log(`${d.toISOString().slice(0, 10)} UAQ: ${fmt(uaq)} FCNA: ${fmt(fcna)}`);
}
```
## Batch conversion
```js
import { toHijri } from 'luxon-hijri';
const isoList = [
'2025-01-01', '2025-03-01', '2025-03-30',
'2025-06-06', '2025-12-31',
];
for (const iso of isoList) {
const h = toHijri(new Date(iso));
const result = h ? `${h.hd}/${h.hm}/${h.hy} AH` : 'out of range';
console.log(`${iso}${result}`);
}
```
## Related pages
- [API Reference](../API-Reference) — all functions, format tokens, types
- [Hijri Calendar](../Hijri-Calendar) — background on UAQ and FCNA calendar systems
- [Architecture](../Architecture) — internals, conversion engine, accuracy