Skip to content

advanced

github-actions[bot] edited this page May 29, 2026 · 1 revision

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;
}

Clone this wiki locally