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:
gregoryfor the Gregorian calendar, used in most Western countriesbuddhistfor the Buddhist calendar, used in Thailand, Cambodia, and Myanmarislamicfor the Islamic lunar calendar, used for religious purposes in Muslim countrieshebrewfor the Hebrew calendar, used in Israel and for Jewish religious observancesjapanesefor the Japanese calendar, which uses imperial era nameschinesefor the Chinese lunisolar calendar, used for traditional holidayspersianfor the Persian solar calendar, used in Iran and Afghanistanindianfor the Indian national calendarcopticfor 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:
latnfor Latin digits: 0 1 2 3 4 5 6 7 8 9arabfor Arabic-Indic digits: ٠ ١ ٢ ٣ ٤ ٥ ٦ ٧ ٨ ٩arabextfor Eastern Arabic-Indic digits: ۰ ۱ ۲ ۳ ۴ ۵ ۶ ۷ ۸ ۹devafor Devanagari digits: ० १ २ ३ ४ ५ ६ ७ ८ ९bengfor Bengali digits: ০ ১ ২ ৩ ৪ ৫ ৬ ৭ ৮ ৯thaifor Thai digits: ๐ ๑ ๒ ๓ ๔ ๕ ๖ ๗ ๘ ๙hanidecfor Chinese decimal numbersfullwidefor 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
calendarproperty returns the explicitly set calendar orundefined - The
numberingSystemproperty returns the explicitly set numbering system orundefined - 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.