How do you format dates in different calendar systems?

Use JavaScript's calendar option to display dates in Islamic, Hebrew, Japanese, Chinese, and other calendar systems for users worldwide

Introduction

Most developers assume dates work the same everywhere. You create a Date object for March 15, 2025, format it, and display it to users. However, this assumption breaks down when your users follow different calendar systems.

In many cultures, the date March 15, 2025 in the Gregorian calendar has a completely different representation. For users following the Islamic calendar, that same moment occurs on Ramadan 16, 1447. For Hebrew calendar users, it falls on Adar II 14, 5785. For Japanese users in official contexts, it appears as Reiwa 7, March 15.

Calendar systems determine how societies count time. They define when years start, how months are organized, and how dates are numbered. JavaScript's Intl.DateTimeFormat API supports over 17 different calendar systems, allowing you to display dates according to each user's cultural and religious context.

This lesson explains what calendar systems are, why they exist, and how to format dates using different calendar systems in JavaScript.

What calendar systems are

A calendar system defines the rules for organizing and counting time. Each system establishes when the year begins, how many months exist, how days are numbered, and what epoch serves as the starting point for year numbering.

The Gregorian calendar, used widely in international contexts, counts years from the estimated birth of Jesus Christ. It uses 12 months with lengths ranging from 28 to 31 days, creating a 365-day year with leap years every four years.

Other calendar systems use different structures and starting points. The Islamic calendar uses 12 lunar months totaling 354 or 355 days per year. The Hebrew calendar combines lunar months with solar year alignment. The Japanese calendar uses era names that change with each emperor's reign.

These systems exist because different cultures developed their own ways of tracking time based on religious significance, astronomical observations, and historical events. Many cultures continue using traditional calendars alongside the Gregorian calendar for religious observances, official documents, and cultural events.

Why calendar systems matter for applications

Applications serving users from different cultural backgrounds need to display dates in formats those users understand and expect. A prayer time app for Muslim users should display dates in the Islamic calendar. An app for Jewish religious observances needs Hebrew calendar dates. Japanese government-related applications require Japanese era formatting.

Using the wrong calendar system creates confusion and can make your application unusable for its intended audience. Displaying Islamic holiday dates in the Gregorian calendar forces users to manually convert dates. Showing Hebrew calendar events in Gregorian format obscures the religious significance of those dates.

The same Date object represents the same moment in time regardless of calendar system. What changes is how you format that moment for display. JavaScript allows you to format any date in any supported calendar system without complex conversion logic.

Using the calendar option

The Intl.DateTimeFormat constructor accepts a calendar option that specifies which calendar system to use when formatting dates. Pass the calendar identifier as a string value.

const date = new Date('2025-03-15');

const gregorianFormatter = new Intl.DateTimeFormat('en-US', {
  calendar: 'gregory',
  dateStyle: 'long'
});

const islamicFormatter = new Intl.DateTimeFormat('en-US', {
  calendar: 'islamic',
  dateStyle: 'long'
});

console.log(gregorianFormatter.format(date));
// Output: "March 15, 2025"

console.log(islamicFormatter.format(date));
// Output: "Ramadan 16, 1447 AH"

The same Date object produces different formatted strings based on the calendar system. The Gregorian calendar shows March 15, 2025. The Islamic calendar shows Ramadan 16, 1447 AH.

The calendar option works independently of the locale. You can format Islamic dates in English, Arabic, French, or any other language by combining the calendar option with the appropriate locale.

const date = new Date('2025-03-15');

const arabicFormatter = new Intl.DateTimeFormat('ar-SA', {
  calendar: 'islamic',
  dateStyle: 'long'
});

const englishFormatter = new Intl.DateTimeFormat('en-US', {
  calendar: 'islamic',
  dateStyle: 'long'
});

console.log(arabicFormatter.format(date));
// Output: "١٦ رمضان ١٤٤٧ هـ"

console.log(englishFormatter.format(date));
// Output: "Ramadan 16, 1447 AH"

The calendar system determines which date to display, while the locale determines the language and formatting conventions.

Formatting dates with the Islamic calendar

The Islamic calendar is a lunar calendar containing 12 months of 29 or 30 days. A complete lunar year is approximately 354 days, which is 10 to 11 days shorter than the solar Gregorian year. This causes Islamic dates to shift backward through the Gregorian calendar over time.

JavaScript supports multiple Islamic calendar variants. The islamic identifier uses an algorithm-based calculation. The islamic-umalqura identifier uses the Umm al-Qura calendar used in Saudi Arabia. The islamic-civil identifier uses a predictable tabular calculation.

const date = new Date('2025-03-15');

const islamicFormatter = new Intl.DateTimeFormat('en-US', {
  calendar: 'islamic',
  year: 'numeric',
  month: 'long',
  day: 'numeric'
});

const umalquraFormatter = new Intl.DateTimeFormat('en-US', {
  calendar: 'islamic-umalqura',
  year: 'numeric',
  month: 'long',
  day: 'numeric'
});

console.log(islamicFormatter.format(date));
// Output: "Ramadan 16, 1447 AH"

console.log(umalquraFormatter.format(date));
// Output: "Ramadan 16, 1447 AH"

For most applications serving Muslim users, any of these Islamic calendar variants work correctly. The differences between them are small and primarily matter for determining exact dates of religious observances.

Formatting dates with the Hebrew calendar

The Hebrew calendar is a lunisolar calendar used for Jewish religious observances. It synchronizes lunar months with the solar year by adding a leap month in certain years. This keeps holidays aligned with seasons.

const date = new Date('2025-03-15');

const hebrewFormatter = new Intl.DateTimeFormat('en-US', {
  calendar: 'hebrew',
  year: 'numeric',
  month: 'long',
  day: 'numeric'
});

console.log(hebrewFormatter.format(date));
// Output: "14 Adar II 5785"

The Hebrew calendar uses Hebrew month names like Nisan, Iyar, Sivan, and Tammuz. In leap years, the calendar includes Adar I and Adar II. The year count represents years since creation according to Jewish tradition.

You can format Hebrew dates in Hebrew language for native speakers.

const date = new Date('2025-03-15');

const hebrewFormatter = new Intl.DateTimeFormat('he-IL', {
  calendar: 'hebrew',
  year: 'numeric',
  month: 'long',
  day: 'numeric'
});

console.log(hebrewFormatter.format(date));
// Output: "י״ד באדר ב׳ ה׳תשפ״ה"

The Hebrew language output uses Hebrew letters for numbers and Hebrew script for month names.

Formatting dates with the Japanese calendar

The Japanese calendar uses era names based on the reigning emperor. The current era, Reiwa, began on May 1, 2019, when Emperor Naruhito ascended to the throne. Years are numbered from the start of each era.

const date = new Date('2025-03-15');

const japaneseFormatter = new Intl.DateTimeFormat('en-US', {
  calendar: 'japanese',
  year: 'numeric',
  month: 'long',
  day: 'numeric'
});

console.log(japaneseFormatter.format(date));
// Output: "March 15, 7 Reiwa"

The year appears as 7 Reiwa, indicating the seventh year of the Reiwa era. This format is used in official Japanese documents, government forms, and formal contexts.

Formatting in Japanese language produces the traditional Japanese date format.

const date = new Date('2025-03-15');

const japaneseFormatter = new Intl.DateTimeFormat('ja-JP', {
  calendar: 'japanese',
  era: 'long',
  year: 'numeric',
  month: 'long',
  day: 'numeric'
});

console.log(japaneseFormatter.format(date));
// Output: "令和7年3月15日"

The output shows the era name (令和), year (7年), month (3月), and day (15日) using Japanese characters.

Formatting dates with the Chinese calendar

The Chinese calendar is a lunisolar calendar used for determining traditional Chinese holidays like Chinese New Year and Mid-Autumn Festival. The calendar combines lunar months with solar terms.

const date = new Date('2025-03-15');

const chineseFormatter = new Intl.DateTimeFormat('en-US', {
  calendar: 'chinese',
  year: 'numeric',
  month: 'long',
  day: 'numeric'
});

console.log(chineseFormatter.format(date));
// Output: "Second Month 16, 2025(yi-si)"

The Chinese calendar year includes a cyclical name (yi-si in this case) along with the numeric year. The month names use numeric designations like "First Month" and "Second Month."

Chinese language formatting displays the date using Chinese characters.

const date = new Date('2025-03-15');

const chineseFormatter = new Intl.DateTimeFormat('zh-CN', {
  calendar: 'chinese',
  year: 'numeric',
  month: 'long',
  day: 'numeric'
});

console.log(chineseFormatter.format(date));
// Output: "2025乙巳年二月十六"

Formatting dates with the Persian calendar

The Persian calendar, also called the Solar Hijri calendar, is the official calendar of Iran and Afghanistan. It uses a solar year with 12 months, similar in structure to the Gregorian calendar but with different month lengths and a different epoch.

const date = new Date('2025-03-15');

const persianFormatter = new Intl.DateTimeFormat('en-US', {
  calendar: 'persian',
  year: 'numeric',
  month: 'long',
  day: 'numeric'
});

console.log(persianFormatter.format(date));
// Output: "Esfand 24, 1403 AP"

The Persian year 1403 corresponds to Gregorian year 2025. The abbreviation AP stands for Anno Persico.

Persian language formatting uses Persian digits and month names.

const date = new Date('2025-03-15');

const persianFormatter = new Intl.DateTimeFormat('fa-IR', {
  calendar: 'persian',
  year: 'numeric',
  month: 'long',
  day: 'numeric'
});

console.log(persianFormatter.format(date));
// Output: "۲۴ اسفند ۱۴۰۳ ه‍.ش."

Other supported calendar systems

JavaScript supports additional calendar systems for various cultural and religious contexts.

The buddhist calendar adds 543 years to the Gregorian year, used in Thailand and other Theravada Buddhist countries.

const date = new Date('2025-03-15');

const buddhistFormatter = new Intl.DateTimeFormat('en-US', {
  calendar: 'buddhist',
  year: 'numeric',
  month: 'long',
  day: 'numeric'
});

console.log(buddhistFormatter.format(date));
// Output: "March 15, 2568 BE"

The indian calendar is the official civil calendar of India.

const date = new Date('2025-03-15');

const indianFormatter = new Intl.DateTimeFormat('en-US', {
  calendar: 'indian',
  year: 'numeric',
  month: 'long',
  day: 'numeric'
});

console.log(indianFormatter.format(date));
// Output: "Phalguna 24, 1946 Saka"

The coptic calendar is used by the Coptic Orthodox Church. The ethiopic calendar is used in Ethiopia.

const date = new Date('2025-03-15');

const copticFormatter = new Intl.DateTimeFormat('en-US', {
  calendar: 'coptic',
  year: 'numeric',
  month: 'long',
  day: 'numeric'
});

const ethiopicFormatter = new Intl.DateTimeFormat('en-US', {
  calendar: 'ethiopic',
  year: 'numeric',
  month: 'long',
  day: 'numeric'
});

console.log(copticFormatter.format(date));
// Output: "Amshir 6, 1741 ERA1"

console.log(ethiopicFormatter.format(date));
// Output: "Yekatit 6, 2017 ERA1"

Discovering supported calendars

The Intl.supportedValuesOf() method returns an array of all calendar identifiers supported by the JavaScript implementation.

const calendars = Intl.supportedValuesOf('calendar');
console.log(calendars);
// Output: ["buddhist", "chinese", "coptic", "dangi", "ethioaa", "ethiopic",
//          "gregory", "hebrew", "indian", "islamic", "islamic-civil",
//          "islamic-tbla", "islamic-umalqura", "japanese", "persian", "roc"]

The exact list varies by JavaScript engine and browser version. The method always returns calendars in alphabetical order.

You can check if a specific calendar is supported before using it.

const calendars = Intl.supportedValuesOf('calendar');
const supportsIslamic = calendars.includes('islamic');

if (supportsIslamic) {
  const formatter = new Intl.DateTimeFormat('en-US', {
    calendar: 'islamic',
    dateStyle: 'long'
  });
  console.log(formatter.format(new Date()));
}

This check prevents errors in environments that might not support all calendar systems.

Specifying calendar with Unicode extension

You can specify the calendar system using a Unicode extension key in the locale identifier instead of using the options parameter. Add -u-ca- followed by the calendar identifier to the locale string.

const date = new Date('2025-03-15');

const formatter = new Intl.DateTimeFormat('en-US-u-ca-islamic', {
  dateStyle: 'long'
});

console.log(formatter.format(date));
// Output: "Ramadan 16, 1447 AH"

The -u-ca-islamic extension tells the formatter to use the Islamic calendar. This produces the same result as passing calendar: 'islamic' in the options object.

When you specify the calendar in both the locale string and the options object, the options object takes precedence.

const date = new Date('2025-03-15');

const formatter = new Intl.DateTimeFormat('en-US-u-ca-islamic', {
  calendar: 'hebrew',
  dateStyle: 'long'
});

console.log(formatter.format(date));
// Output: "14 Adar II 5785"

The Hebrew calendar from the options object overrides the Islamic calendar from the locale string. Use the options parameter when you need to programmatically control the calendar system. Use the Unicode extension when working with locale identifiers from user preferences or configuration.

How locales determine default calendars

When you do not specify a calendar, the formatter uses the default calendar for the locale. Most locales default to the Gregorian calendar, but some locales use different defaults.

const date = new Date('2025-03-15');

const usFormatter = new Intl.DateTimeFormat('en-US', {
  dateStyle: 'long'
});

const saFormatter = new Intl.DateTimeFormat('ar-SA', {
  dateStyle: 'long'
});

const ilFormatter = new Intl.DateTimeFormat('he-IL', {
  dateStyle: 'long'
});

console.log(usFormatter.format(date));
// Output: "March 15, 2025"

console.log(saFormatter.format(date));
// Output: "١٦ رمضان ١٤٤٧ هـ"

console.log(ilFormatter.format(date));
// Output: "15 במרץ 2025"

The US English locale uses the Gregorian calendar by default. The Saudi Arabian Arabic locale uses the Islamic calendar by default. The Israeli Hebrew locale uses the Gregorian calendar by default despite having strong Hebrew calendar traditions.

You can discover which calendar a formatter is using by calling the resolvedOptions() method.

const formatter = new Intl.DateTimeFormat('ar-SA', {
  dateStyle: 'long'
});

const options = formatter.resolvedOptions();
console.log(options.calendar);
// Output: "islamic-umalqura"

The resolved options show that the ar-SA locale defaults to the islamic-umalqura calendar variant.

When to explicitly set the calendar

Let the locale determine the calendar system when formatting dates for general display to users in their native locale. Users from Saudi Arabia expect Islamic calendar dates. Users from Japan expect Japanese era formatting in official contexts. The locale defaults handle these expectations automatically.

const date = new Date('2025-03-15');

const formatter = new Intl.DateTimeFormat(navigator.language, {
  dateStyle: 'long'
});

console.log(formatter.format(date));
// Output varies by user's locale and default calendar

Explicitly set the calendar when you need to display dates in a specific calendar system regardless of the user's locale. A prayer time app should always show Islamic calendar dates. A Hebrew calendar app should always show Hebrew dates.

const date = new Date('2025-03-15');

const formatter = new Intl.DateTimeFormat(navigator.language, {
  calendar: 'islamic',
  dateStyle: 'long'
});

console.log(formatter.format(date));
// Output shows Islamic calendar date in user's language

This ensures the calendar system matches your application's purpose while still respecting the user's language preference.

Explicitly set the calendar when displaying dates in a calendar system different from the locale's default. You might want to show Gregorian dates to Hebrew users or Islamic dates to English speakers.

const date = new Date('2025-03-15');

const formatter = new Intl.DateTimeFormat('en-US', {
  calendar: 'hebrew',
  dateStyle: 'long'
});

console.log(formatter.format(date));
// Output: "14 Adar II 5785"

Combining calendar with other options

The calendar option works with all other Intl.DateTimeFormat options. You can combine it with dateStyle, timeStyle, component options like weekday and month, and other options like timeZone.

const date = new Date('2025-03-15T14:30:00');

const formatter = new Intl.DateTimeFormat('en-US', {
  calendar: 'islamic',
  dateStyle: 'full',
  timeStyle: 'long',
  timeZone: 'America/New_York'
});

console.log(formatter.format(date));
// Output: "Saturday, Ramadan 16, 1447 AH at 2:30:00 PM EST"

The formatter uses the Islamic calendar for the date while applying the full date style, long time style, and specified time zone.

You can also use the calendar option with individual component options.

const date = new Date('2025-03-15');

const formatter = new Intl.DateTimeFormat('en-US', {
  calendar: 'japanese',
  weekday: 'long',
  year: 'numeric',
  month: 'long',
  day: 'numeric',
  era: 'long'
});

console.log(formatter.format(date));
// Output: "Saturday, March 15, 7 Reiwa"

The era option becomes particularly relevant when using calendars like Japanese or Buddhist that use era names.

Formatting date ranges with different calendars

The formatRange() method works with the calendar option to format date ranges in any calendar system.

const startDate = new Date('2025-03-15');
const endDate = new Date('2025-03-25');

const formatter = new Intl.DateTimeFormat('en-US', {
  calendar: 'islamic',
  year: 'numeric',
  month: 'long',
  day: 'numeric'
});

console.log(formatter.formatRange(startDate, endDate));
// Output: "Ramadan 16 – 26, 1447 AH"

The formatter applies the Islamic calendar to both dates and formats them as a range, intelligently omitting repeated information.

Reusing formatters for performance

Creating Intl.DateTimeFormat instances involves processing locale data and calendar system information. When formatting multiple dates with the same calendar and locale, create the formatter once and reuse it.

const formatter = new Intl.DateTimeFormat('en-US', {
  calendar: 'islamic',
  dateStyle: 'long'
});

const dates = [
  new Date('2025-03-15'),
  new Date('2025-04-20'),
  new Date('2025-06-10')
];

dates.forEach(date => {
  console.log(formatter.format(date));
});
// Output:
// "Ramadan 16, 1447 AH"
// "Dhuʻl-Qiʻdah 22, 1447 AH"
// "Dhuʻl-Hijjah 15, 1447 AH"

This approach improves performance when formatting arrays of dates or displaying many timestamps in your application.

What to remember

Calendar systems define how cultures organize and count time. JavaScript supports over 17 different calendar systems including Islamic, Hebrew, Japanese, Chinese, Persian, Buddhist, and Coptic calendars through the Intl.DateTimeFormat API.

Specify a calendar system using the calendar option in the options object or by adding a Unicode extension to the locale string. The calendar option determines which calendar system formats the date, while the locale determines the language and formatting conventions.

Let the locale determine the default calendar when displaying dates for general use. Explicitly set the calendar when your application requires a specific calendar system regardless of the user's locale preferences.

The calendar option works with all other date formatting options including styles, component options, time zones, and date ranges. Reuse formatter instances when formatting multiple dates for better performance.