How to check which calendar or numbering system a locale uses

Detect and validate calendar systems and numbering formats for any locale with JavaScript

Introduction

When someone in Thailand views a date on your web app, they expect to see dates in the Buddhist calendar, not the Gregorian calendar used in Western countries. Similarly, Arabic speakers expect to see digits rendered as ١٢٣ instead of 123. Different cultures use different calendar systems and numbering systems, and JavaScript provides tools to detect which ones apply to specific locales.

The Intl.Locale API includes properties and methods that reveal which calendar and numbering systems a locale uses. This information helps you format dates and numbers correctly without hardcoding assumptions about which systems different cultures prefer.

This guide explains how to check calendar and numbering systems for locales, understand what the different systems mean, and use this information to format content appropriately.

Understanding calendar systems

A calendar system is a way of organizing time into years, months, and days. While the Gregorian calendar is widespread, many cultures use different calendar systems for religious, historical, or cultural purposes.

The most common calendar systems include:

  • gregory for the Gregorian calendar, used in most Western countries
  • buddhist for the Buddhist calendar, used in Thailand, Cambodia, and Myanmar
  • islamic for the Islamic lunar calendar, used for religious purposes in Muslim countries
  • hebrew for the Hebrew calendar, used in Israel and for Jewish religious observances
  • japanese for the Japanese calendar, which uses imperial era names
  • chinese for the Chinese lunisolar calendar, used for traditional holidays
  • persian for the Persian solar calendar, used in Iran and Afghanistan
  • indian for the Indian national calendar
  • coptic for the Coptic calendar, used in Egypt by Coptic Christians

Different regions use different calendars as their default, and some regions commonly use multiple calendar systems.

Understanding numbering systems

A numbering system is a set of symbols used to represent digits. While Western countries use Latin digits (0, 1, 2, 3, 4, 5, 6, 7, 8, 9), other cultures use different symbols to represent the same numeric values.

Common numbering systems include:

  • latn for Latin digits: 0 1 2 3 4 5 6 7 8 9
  • arab for Arabic-Indic digits: ٠ ١ ٢ ٣ ٤ ٥ ٦ ٧ ٨ ٩
  • arabext for Eastern Arabic-Indic digits: ۰ ۱ ۲ ۳ ۴ ۵ ۶ ۷ ۸ ۹
  • deva for Devanagari digits: ० १ २ ३ ४ ५ ६ ७ ८ ९
  • beng for Bengali digits: ০ ১ ২ ৩ ৪ ৫ ৬ ৭ ৮ ৯
  • thai for Thai digits: ๐ ๑ ๒ ๓ ๔ ๕ ๖ ๗ ๘ ๙
  • hanidec for Chinese decimal numbers
  • fullwide for full-width digits used in East Asian typography

All numbering systems represent the same numeric values but use different visual symbols based on the writing system of the language.

Check the default calendar for a locale

The getCalendars() method returns an array of calendar systems commonly used for a locale, sorted by preference. The first element is the default calendar.

const locale = new Intl.Locale("th-TH");
const calendars = locale.getCalendars();
console.log(calendars);
// ["buddhist", "gregory"]

Thai locales default to the Buddhist calendar but also commonly use the Gregorian calendar. This tells you that when formatting dates for Thai users, the Buddhist calendar is preferred.

Different locales return different calendar preferences:

const usLocale = new Intl.Locale("en-US");
console.log(usLocale.getCalendars());
// ["gregory"]

const saLocale = new Intl.Locale("ar-SA");
console.log(saLocale.getCalendars());
// ["gregory", "islamic", "islamic-civil"]

const jpLocale = new Intl.Locale("ja-JP");
console.log(jpLocale.getCalendars());
// ["gregory", "japanese"]

American English uses only the Gregorian calendar. Saudi Arabian Arabic commonly uses both Gregorian and Islamic calendars. Japanese locales use both Gregorian and Japanese imperial calendars.

The array contains all calendars commonly used in that locale, allowing you to offer multiple calendar options when appropriate.

Check the default numbering system for a locale

The getNumberingSystems() method returns an array of numbering systems commonly used for a locale. The first element is the default numbering system.

const locale = new Intl.Locale("ar-EG");
const numberingSystems = locale.getNumberingSystems();
console.log(numberingSystems);
// ["arab"]

Egyptian Arabic defaults to Arabic-Indic digits. When formatting numbers for Egyptian Arabic users, use the Arabic-Indic numbering system unless the user has specified otherwise.

Different locales use different default numbering systems:

const usLocale = new Intl.Locale("en-US");
console.log(usLocale.getNumberingSystems());
// ["latn"]

const inLocale = new Intl.Locale("hi-IN");
console.log(inLocale.getNumberingSystems());
// ["latn"]

const thLocale = new Intl.Locale("th-TH");
console.log(thLocale.getNumberingSystems());
// ["latn"]

American English uses Latin digits. Hindi in India also uses Latin digits by default in modern contexts, though Devanagari digits exist. Thai uses Latin digits by default in most modern contexts.

Many modern locales default to Latin digits even when traditional numbering systems exist, reflecting current usage patterns.

Read the active calendar from a locale

The calendar property returns the calendar system explicitly set for a locale. If no calendar is specified, it returns undefined.

const locale = new Intl.Locale("en-US");
console.log(locale.calendar);
// undefined

A basic locale without calendar extensions returns undefined. The locale will use its default calendar when formatting dates.

You can create locales with explicit calendar preferences using Unicode extensions:

const locale = new Intl.Locale("en-US-u-ca-buddhist");
console.log(locale.calendar);
// "buddhist"

The -u-ca-buddhist extension specifies the Buddhist calendar. The calendar property returns "buddhist".

You can also set the calendar when creating the locale:

const locale = new Intl.Locale("en-US", { calendar: "islamic" });
console.log(locale.calendar);
// "islamic"

The options object takes priority over any calendar specified in the locale string.

Read the active numbering system from a locale

The numberingSystem property returns the numbering system explicitly set for a locale. If no numbering system is specified, it returns undefined.

const locale = new Intl.Locale("en-US");
console.log(locale.numberingSystem);
// undefined

A basic locale without numbering system extensions returns undefined. The locale will use its default numbering system when formatting numbers.

You can create locales with explicit numbering system preferences:

const locale = new Intl.Locale("en-US-u-nu-arab");
console.log(locale.numberingSystem);
// "arab"

The -u-nu-arab extension specifies Arabic-Indic digits. The numberingSystem property returns "arab".

You can also set the numbering system when creating the locale:

const locale = new Intl.Locale("ar-SA", { numberingSystem: "latn" });
console.log(locale.numberingSystem);
// "latn"

This creates an Arabic locale that uses Latin digits instead of the default Arabic-Indic digits.

Detect when a locale has an explicit calendar

To check whether a locale has an explicitly set calendar versus using its default, check if the calendar property is defined:

function hasExplicitCalendar(localeString) {
  const locale = new Intl.Locale(localeString);
  return locale.calendar !== undefined;
}

console.log(hasExplicitCalendar("en-US"));
// false

console.log(hasExplicitCalendar("en-US-u-ca-buddhist"));
// true

This distinction matters when you need to determine whether the user has explicitly chosen a calendar preference or whether you should use the locale's default.

Detect when a locale has an explicit numbering system

Similarly, check if the numberingSystem property is defined to detect explicit numbering system preferences:

function hasExplicitNumberingSystem(localeString) {
  const locale = new Intl.Locale(localeString);
  return locale.numberingSystem !== undefined;
}

console.log(hasExplicitNumberingSystem("ar-EG"));
// false

console.log(hasExplicitNumberingSystem("ar-EG-u-nu-latn"));
// true

The first locale will use the default numbering system for Egyptian Arabic. The second locale explicitly requests Latin digits.

Use calendar information to format dates

Once you know which calendar a locale uses, apply it when formatting dates with Intl.DateTimeFormat:

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

const gregorianLocale = new Intl.Locale("en-US");
const gregorianFormatter = new Intl.DateTimeFormat(gregorianLocale, {
  year: "numeric",
  month: "long",
  day: "numeric"
});
console.log(gregorianFormatter.format(date));
// "March 15, 2025"

const buddhistLocale = new Intl.Locale("th-TH");
const buddhistFormatter = new Intl.DateTimeFormat(buddhistLocale, {
  year: "numeric",
  month: "long",
  day: "numeric"
});
console.log(buddhistFormatter.format(date));
// "15 มีนาคม 2568"

The Thai Buddhist calendar displays the same date as year 2568, which is 543 years ahead of the Gregorian calendar.

You can also explicitly override the calendar:

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

const locale = new Intl.Locale("en-US", { calendar: "hebrew" });
const formatter = new Intl.DateTimeFormat(locale, {
  year: "numeric",
  month: "long",
  day: "numeric"
});
console.log(formatter.format(date));
// "15 Adar II 5785"

This formats the date in the Hebrew calendar, displaying the corresponding Hebrew year and month.

Use numbering system information to format numbers

Apply numbering system information when formatting numbers with Intl.NumberFormat:

const number = 123456;

const latinLocale = new Intl.Locale("ar-EG", { numberingSystem: "latn" });
const latinFormatter = new Intl.NumberFormat(latinLocale);
console.log(latinFormatter.format(number));
// "123,456"

const arabicLocale = new Intl.Locale("ar-EG", { numberingSystem: "arab" });
const arabicFormatter = new Intl.NumberFormat(arabicLocale);
console.log(arabicFormatter.format(number));
// "١٢٣٬٤٥٦"

The same number renders with different digit symbols based on the numbering system.

Build a calendar selector

Use calendar information to build user interfaces that let users choose their preferred calendar:

function getCalendarOptions(localeString) {
  const locale = new Intl.Locale(localeString);
  const calendars = locale.getCalendars();

  return calendars.map(calendar => ({
    value: calendar,
    label: calendar.charAt(0).toUpperCase() + calendar.slice(1)
  }));
}

const options = getCalendarOptions("ar-SA");
console.log(options);
// [
//   { value: "gregory", label: "Gregory" },
//   { value: "islamic", label: "Islamic" },
//   { value: "islamic-civil", label: "Islamic-civil" }
// ]

This creates a list of calendar options appropriate for Saudi Arabian Arabic users, who commonly use multiple calendars.

Build a numbering system selector

Create user interfaces for numbering system preferences:

function getNumberingSystemOptions(localeString) {
  const locale = new Intl.Locale(localeString);
  const systems = locale.getNumberingSystems();

  const labels = {
    latn: "Western (0-9)",
    arab: "Arabic-Indic (٠-٩)",
    arabext: "Eastern Arabic (۰-۹)",
    deva: "Devanagari (०-९)",
    beng: "Bengali (০-৯)"
  };

  return systems.map(system => ({
    value: system,
    label: labels[system] || system
  }));
}

const options = getNumberingSystemOptions("ar-EG");
console.log(options);
// [{ value: "arab", label: "Arabic-Indic (٠-٩)" }]

This provides clear labels for numbering system options, showing users what each choice looks like.

Validate calendar compatibility

Before applying a calendar to a locale, verify that the locale supports that calendar:

function supportsCalendar(localeString, calendar) {
  const locale = new Intl.Locale(localeString);
  const supportedCalendars = locale.getCalendars();
  return supportedCalendars.includes(calendar);
}

console.log(supportsCalendar("th-TH", "buddhist"));
// true

console.log(supportsCalendar("en-US", "buddhist"));
// false

Thai locales support the Buddhist calendar, but American English locales do not commonly use it.

Validate numbering system compatibility

Check if a locale supports a specific numbering system:

function supportsNumberingSystem(localeString, numberingSystem) {
  const locale = new Intl.Locale(localeString);
  const supportedSystems = locale.getNumberingSystems();
  return supportedSystems.includes(numberingSystem);
}

console.log(supportsNumberingSystem("ar-EG", "arab"));
// true

console.log(supportsNumberingSystem("en-US", "arab"));
// false

Egyptian Arabic supports Arabic-Indic digits, but American English does not use them.

Determine the effective calendar for formatting

When formatting dates, determine which calendar will actually be used:

function getEffectiveCalendar(localeString) {
  const locale = new Intl.Locale(localeString);

  if (locale.calendar) {
    return locale.calendar;
  }

  const defaultCalendars = locale.getCalendars();
  return defaultCalendars[0];
}

console.log(getEffectiveCalendar("th-TH"));
// "buddhist"

console.log(getEffectiveCalendar("en-US-u-ca-islamic"));
// "islamic"

This function returns the explicitly set calendar if one exists, otherwise returns the default calendar for the locale.

Determine the effective numbering system for formatting

Determine which numbering system will be used when formatting numbers:

function getEffectiveNumberingSystem(localeString) {
  const locale = new Intl.Locale(localeString);

  if (locale.numberingSystem) {
    return locale.numberingSystem;
  }

  const defaultSystems = locale.getNumberingSystems();
  return defaultSystems[0];
}

console.log(getEffectiveNumberingSystem("ar-EG"));
// "arab"

console.log(getEffectiveNumberingSystem("ar-EG-u-nu-latn"));
// "latn"

This returns the explicitly set numbering system if present, otherwise the default for the locale.

Store user calendar preferences

When users select a calendar preference, store it as a locale string with extensions:

function setUserCalendarPreference(baseLocale, calendar) {
  const locale = new Intl.Locale(baseLocale, { calendar });
  return locale.toString();
}

const preference = setUserCalendarPreference("en-US", "buddhist");
console.log(preference);
// "en-US-u-ca-buddhist"

This creates a complete locale string that preserves the calendar preference. Store this string in user settings or cookies.

Store user numbering system preferences

Store numbering system preferences the same way:

function setUserNumberingPreference(baseLocale, numberingSystem) {
  const locale = new Intl.Locale(baseLocale, { numberingSystem });
  return locale.toString();
}

const preference = setUserNumberingPreference("ar-SA", "latn");
console.log(preference);
// "ar-SA-u-nu-latn"

The locale string includes the numbering system preference and can be used directly with formatting APIs.

Handle multiple preferences simultaneously

Users can have both calendar and numbering system preferences:

function createLocaleWithPreferences(baseLocale, options) {
  const locale = new Intl.Locale(baseLocale, {
    calendar: options.calendar,
    numberingSystem: options.numberingSystem
  });
  return locale.toString();
}

const preference = createLocaleWithPreferences("ar-SA", {
  calendar: "islamic",
  numberingSystem: "latn"
});
console.log(preference);
// "ar-SA-u-ca-islamic-nu-latn"

This combines multiple formatting preferences into a single locale string.

Check resolved formatting options

After creating a formatter, verify which calendar and numbering system it uses:

const locale = new Intl.Locale("th-TH");
const formatter = new Intl.DateTimeFormat(locale, {
  year: "numeric",
  month: "long",
  day: "numeric"
});

const options = formatter.resolvedOptions();
console.log(options.calendar);
// "buddhist"
console.log(options.numberingSystem);
// "latn"

The resolvedOptions() method shows which calendar and numbering system the formatter actually uses after resolving defaults and user preferences.

Browser support

The Intl.Locale API is supported in all modern browsers. The getCalendars() and getNumberingSystems() methods require recent browser versions. Chrome 99, Firefox 99, Safari 15.4, and Edge 99 support these methods. Node.js supports them starting from version 18.

The calendar and numberingSystem properties have broader support, available since the introduction of Intl.Locale in Chrome 74, Firefox 75, Safari 14, and Node.js 12.

Check for method support before using:

const locale = new Intl.Locale("th-TH");

if (typeof locale.getCalendars === "function") {
  const calendars = locale.getCalendars();
  console.log(calendars);
}

This ensures your code works in environments that support Intl.Locale but lack the newer methods.

Summary

JavaScript provides tools to detect which calendar and numbering systems a locale uses through the Intl.Locale API. These tools help you format dates and numbers correctly for different cultures without hardcoding assumptions.

Key concepts:

  • Use getCalendars() to get an array of commonly used calendars for a locale
  • Use getNumberingSystems() to get an array of commonly used numbering systems for a locale
  • The calendar property returns the explicitly set calendar or undefined
  • The numberingSystem property returns the explicitly set numbering system or undefined
  • Different locales default to different calendars and numbering systems
  • Apply calendar and numbering system information when creating formatters
  • Store user preferences as locale strings with Unicode extensions
  • Validate that locales support specific calendars and numbering systems before applying them

Use these methods when building locale selectors, storing user preferences, validating formatting options, or creating internationalized applications that respect cultural conventions for dates and numbers.