Calendars in Temporal

Table of Contents

Much of the world uses the Gregorian calendar, which was invented in 1582 C.E. The ISO 8601 standard extends the Gregorian date reckoning backwards ("proleptically") to cover the period of history before its invention, to allow designating dates before 1582. The ISO 8601 calendar is the system most often used in computing, on the modern Internet.

A significant number of places in the world use another calendar system as the main calendar, or use the Gregorian calendar alongside another calendar system as a commonly-used civil or religious calendar. Even places that use almost exclusively the Gregorian calendar today, often use a different calendar to denote dates before the invention or adoption of the Gregorian calendar.

When to use calendars in Temporal

It is best practice to specify a calendar system when performing calendar-sensitive operations, which are those involving arithmetic or other calculation in months or years.

For example, to add a month to a date in the Hebrew calendar:

date.withCalendar('hebrew').add({ months: 1 });

Temporal types' toLocaleString() methods use the user's preferred calendar, without needing to call withCalendar(). To perform arithmetic consistently with the toLocaleString() calendar system:

const calendar = new Intl.DateTimeFormat().resolvedOptions().calendar;
date.withCalendar(calendar).add({ months: 1 });

Invariants Across Calendars

The following "invariants" (statements that are always true) hold for all built-in calendars:

Writing Cross-Calendar Code

Here are best practices for writing code that will work regardless of the calendar used:

Handling unusual dates: leap days, leap months, and skipped or repeated periods

Calendars can vary from year to year. Solar calendars like 'gregory' use leap days. Lunar calendars like 'islamic' adjust month lengths to lunar cycles. Lunisolar calendars like 'hebrew' or 'chinese' have "leap months": extra months added every few years.

Calendars may also have one-time changes. The built-in 'gregory' calendar in ECMAScript doesn't skip days because it's a proleptic Gregorian calendar, but other calendars may skip days, months, or even years. For example, a non-proleptic custom calendar for France would have 4 October 1582 (the last day of the Julian calendar) directly followed by 15 October 1582 (the first day of the Gregorian calendar), skipping 10 calendar days.

Calendar variation across years means that programs may encounter historical dates that are valid in one year but invalid in another. A common example is calling toPlainDate on a Temporal.PlainMonthDay object to convert a birthday or anniversary that originally fell on a leap day, leap month, or other skipped period. Temporal types' with or from methods can run into the same issue.

When Temporal encounters inputs representing a month and/or day that doesn't exist in the desired calendar year, by default (overridable in with or from via the overflow option) the inputs will be adjusted using the following algorithm:

Finally, just like calendars can sometimes skip days or months, it is possible for real-world calendars to repeat dates, for example when a country transitions from one calendar system to another. No current built-in calendar repeats dates, but may in the future.