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

2.9 KiB

Advanced Usage

Custom calendar engines

Any engine registered in hijri-core can be wrapped in a Temporal calendar:

import { HijriCalendar } from 'temporal-hijri';
import { registerCalendar, getCalendar } from 'hijri-core';
import type { CalendarEngine } from 'hijri-core';

const myEngine: CalendarEngine = {
  id: 'local-sighting',
  toHijri(date) { /* ... */ return { hy, hm, hd }; },
  toGregorian(hy, hm, hd) { /* ... */ return new Date(...); },
  isValid(hy, hm, hd) { /* ... */ return true; },
  daysInMonth(hy, hm) { /* ... */ return 29; },
};

registerCalendar('local-sighting', myEngine);
const cal = new HijriCalendar(getCalendar('local-sighting'));
// cal.id === 'hijri-local-sighting'

DateUntil with different largestUnit values

dateUntil respects the largestUnit option:

import { Temporal } from '@js-temporal/polyfill';
import { uaqCalendar } from 'temporal-hijri';

const start = Temporal.PlainDate.from('2023-01-01');
const end   = Temporal.PlainDate.from('2023-12-31');

const inYears  = uaqCalendar.dateUntil(start, end, { largestUnit: 'years' });
const inMonths = uaqCalendar.dateUntil(start, end, { largestUnit: 'months' });
const inDays   = uaqCalendar.dateUntil(start, end, { largestUnit: 'days' });

console.log(inYears.years, inYears.months, inYears.days);
console.log(inMonths.months, inMonths.days);
console.log(inDays.days);

Note: the result measures in Hijri units. One Hijri year is 354 or 355 days, so inYears.days may differ from what you would expect in Gregorian.

PlainYearMonth and PlainMonthDay

import { Temporal } from '@js-temporal/polyfill';
import { uaqCalendar } from 'temporal-hijri';

// Year-month in Hijri
const ym = uaqCalendar.yearMonthFromFields({ year: 1444, month: 9 });
console.log(ym.toString()); // ISO year-month of 1 Ramadan 1444

// Month-day in Hijri
const md = uaqCalendar.monthDayFromFields({ month: 9, day: 1 });
console.log(md.toString()); // ISO month-day of Ramadan 1st

Out-of-range behavior

UAQ covers 1318-1500 AH (1900-2076 CE). Requesting dates outside that range throws RangeError:

const earlyDate = Temporal.PlainDate.from('1800-01-01');
try {
  uaqCalendar.year(earlyDate); // throws RangeError
} catch (e) {
  if (e instanceof RangeError) {
    // Use FCNA for unbounded coverage
    import { fcnaCalendar } from 'temporal-hijri';
    console.log(fcnaCalendar.year(earlyDate));
  }
}

Using with native Temporal

When native Temporal is available (future Node.js or browsers), you can use it directly without the polyfill:

// No import from @js-temporal/polyfill
import { uaqCalendar } from 'temporal-hijri';

const isoDate = Temporal.PlainDate.from('2023-03-23');
console.log(uaqCalendar.year(isoDate)); // 1444

The uaqCalendar and fcnaCalendar objects implement the Temporal.CalendarProtocol interface and work with any spec-conforming implementation.