3.7 KiB
Advanced Usage
Null handling and range validation
toHijriDate returns null for dates outside the UAQ table range (1318-1500 AH, approximately 1900-2076 CE). Guard against null before using the result.
import { toHijriDate } from 'date-fns-hijri';
function safeConvert(date: Date) {
const hijri = toHijriDate(date);
if (hijri === null) {
throw new RangeError(`Date ${date.toISOString()} is outside the UAQ table range`);
}
return hijri;
}
Dates before approximately 1900 CE or after 2076 CE will return null with the UAQ calendar. Switch to FCNA for unbounded range:
const hijri = toHijriDate(date, { calendar: 'fcna' }); // never null
FCNA uses astronomical calculation and has no hard range limit, though accuracy degrades for dates far from the present.
Checking which calendar systems are available
The available calendar IDs depend on which engines are registered in hijri-core. UAQ and FCNA are always registered. If you use a custom engine registered via hijri-core's registerCalendar(), you can pass its ID in the options.
import { toHijriDate } from 'date-fns-hijri';
const hijri = toHijriDate(date, { calendar: 'my-custom-calendar' });
Formatting with zero padding
formatHijriDate pads single-digit days and months with a leading zero when you use the two-character tokens (iDD, iMM). To get unpadded values, use the single-character equivalents (iD, iM).
import { formatHijriDate } from 'date-fns-hijri';
const date = new Date(2023, 2, 23); // 1 Ramadan 1444
formatHijriDate(date, 'iD/iM/iYYYY'); // '1/9/1444'
formatHijriDate(date, 'iDD/iMM/iYYYY'); // '01/09/1444'
Month arithmetic edge cases
addHijriMonths accounts for variable month lengths. When the source day does not exist in the target month (Hijri months alternate between 29 and 30 days depending on the calendar), the result clamps to the last valid day of the target month.
import { addHijriMonths, toHijriDate } from 'date-fns-hijri';
// Suppose source is 30 Rajab and the following month (Sha'ban) has 29 days.
// addHijriMonths clamps the result to 29 Sha'ban.
const result = addHijriMonths(new Date(2023, 0, 21), 1);
const hijri = toHijriDate(result);
// hijri.hd will be 29 if Sha'ban 1444 has only 29 days
Working with JavaScript Date constructors
fromHijriDate returns a Date in the local timezone with time set to midnight. If you need UTC midnight, convert explicitly:
import { fromHijriDate } from 'date-fns-hijri';
const local = fromHijriDate(1444, 9, 1);
// New Date at midnight in the local timezone
const utc = new Date(Date.UTC(
local.getFullYear(),
local.getMonth(),
local.getDate()
));
Integrating with date-fns formatting
date-fns-hijri works with plain Date objects, so it integrates cleanly with date-fns formatting functions. Use date-fns for Gregorian formatting and this package for Hijri-specific tokens.
import { format } from 'date-fns';
import { formatHijriDate } from 'date-fns-hijri';
const date = new Date(2023, 2, 23);
// Gregorian day of week from date-fns
const dayOfWeek = format(date, 'EEEE'); // 'Thursday'
// Hijri date from date-fns-hijri
const hijriLabel = formatHijriDate(date, 'iD iMMMM iYYYY'); // '1 Ramadan 1444'
const combined = `${dayOfWeek}, ${hijriLabel}`;
// 'Thursday, 1 Ramadan 1444'
TypeScript: narrowing the return type
When you know the date is within the UAQ range, you can assert non-null:
import { toHijriDate, HijriDate } from 'date-fns-hijri';
function convert(date: Date): HijriDate {
const result = toHijriDate(date);
if (result === null) throw new RangeError('Out of UAQ range');
return result;
}