Stage 2 Draft / July 18, 2025

Intl era and monthCode Proposal

1 Identification of Locales, Currencies, Time Zones, Measurement Units, Numbering Systems, Collations, and Calendars

1.1 Calendar Types

Editor's Note

This section, Calendar Types, is present in ECMA-402 but is slated to move to ECMA-262 as part of the Temporal proposal. This proposal re-adds the section to ECMA-402, but with additional requirements for Intl-supporting implementations, beyond those specified in ECMA-262.

This specification identifies calendars using a calendar type as defined by Unicode Technical Standard #35 Part 4 Dates, Section 2 Calendar Elements. Their canonical form is a string containing only Unicode Basic Latin lowercase letters (U+0061 LATIN SMALL LETTER A through U+007A LATIN SMALL LETTER Z) with zero or more medial hyphens (U+002D HYPHEN-MINUS).

ECMA-262 describes calendar types, of which "iso8601" is required to be supported. This specification additionally requires ECMAScript implementations to support calendar types corresponding with those of the Unicode Common Locale Data Repository (CLDR).

1.1.1 AvailableCalendars ( )

The implementation-defined abstract operation AvailableCalendars takes no arguments and returns a List of calendar types. The returned List is sorted according to lexicographic code unit order, and contains unique calendar types in canonical form (6.9) identifying the calendars for which the implementation provides the functionality of Intl.DateTimeFormat objects, including their aliases (e.g., either both or neither of "islamicc" and "islamic-civil"). The List must include "iso8601"the Calendar Type value of every row of Table 1, except the header row.

This definition supersedes the definition provided in 6.9.1.

Table 1: Calendar types described in CLDR
Calendar Type Description and implementation notes
"buddhist" Thai Buddhist calendar, proleptic. Month numbers, month codes, and days are the same as in the ISO 8601 calendar, but the epoch year is different. There is one era.
"chinese" Traditional Chinese calendar, proleptic. Similar lunisolar algorithm to "dangi". The arithmetic year is identical to "gregory" and there are no eras.
"coptic" Coptic calendar, proleptic. Similar solar algorithm to "ethioaa" and "ethiopic", with one era and a different epoch year.
"dangi" Traditional Korean calendar, proleptic. Similar lunisolar algorithm to "chinese". The arithmetic year is identical to "gregory" and there are no eras.
"ethioaa" Ethiopic calendar, Amete Alem, proleptic. Similar solar algorithm to "coptic" and "ethiopic", with one era and a different epoch year.
"ethiopic" Ethiopic calendar, Amete Mihret, proleptic. Similar solar algorithm to "coptic" and "ethioaa", with two eras and a different epoch year.
"ethiopic-amete-alem" Alias for "ethioaa".
"gregory" Gregorian calendar, proleptic. Solar calendar almost identical to the ISO 8601 calendar, except that it does not define week numbering and it contains two eras, one before the epoch year.
"hebrew" Hebrew calendar, proleptic. Lunisolar calendar with one leap month inserted after month 5. There is one era.
"indian" Indian national (or Śaka) calendar, proleptic. Solar calendar with one era.
"islamic-civil" Hijri calendar, proleptic, tabular/rule-based with leap years 2, 5, 7, 10, 13, 16, 18, 21, 24, 26, 29 in the 30-year cycle, and civil epoch (Friday July 16, 622 Julian / 0622-07-19 ISO)
"islamic-tbla" Hijri calendar, proleptic, tabular/rule-based with leap years 2, 5, 7, 10, 13, 16, 18, 21, 24, 26, 29 in the 30-year cycle, and astronomical epoch (Thursday July 15, 622 Julian / 0622-07-18 ISO)
"islamic-umalqura" Hijri calendar, proleptic, Umm al-Qura. Lunisolar calendar using KACST-calculated months from the start of 1300 AH to the end of 1600 AH and falls back to "islamic-civil" outside that range.
"islamicc" Deprecated alias for "islamic-civil".
"iso8601" ISO 8601 calendar. Fully specified in ECMA-262.
"japanese" Japanese Imperial calendar, era system hybridised with "gregory". Month numbers, month codes, and days are the same as in the ISO 8601 calendar, extended proleptically before their introduction in ISO year 1873. Imperial era names only extend as far back as the Meiji period (starting in ISO year 1868) during which calendar reforms took place. The arithmetic year, and the years and eras before ISO year 1868, are identical to "gregory".
"persian" Persian (or Solar Hijri) calendar, proleptic. There is one era.
"roc" Republic of China (or Minguo) calendar, proleptic. Month numbers, month codes, and days are the same as in the ISO 8601 calendar, but the epoch year is different. There are two eras, one before the epoch year and one after.

2 Locale and Parameter Negotiation

2.1 Internal slots of Service Constructors

[...]

Note
For example, an implementation of DateTimeFormat might include the language tag "fa-IR" in its [[AvailableLocales]] internal slot, and must (according to 11.2.3) include the keys "ca", "hc", and "nu" in its [[RelevantExtensionKeys]] internal slot. The default calendar for that locale is usually "persian", but an implementation might also support "gregory", "islamic", and "islamic-civil". The Record in the DateTimeFormat [[LocaleData]] internal slot would therefore include a [[fa-IR]] field whose value is a Record like { [[ca]]: « "persian", "gregory", "islamic", "islamic-civil" », [[hc]]: « … », [[nu]]: « … » }, along with other locale-named fields having the same value shape but different elements in their Lists.

3 DateTimeFormat Objects

3.1 The Intl.DateTimeFormat Constructor

3.1.1 CreateDateTimeFormat ( newTarget, locales, options, required, defaults )

The abstract operation CreateDateTimeFormat takes arguments newTarget (a constructor), locales (an ECMAScript language value), options (an ECMAScript language value), required (date, time, or any), and defaults (date, time, or all) and returns either a normal completion containing a DateTimeFormat object or a throw completion. It performs the following steps when called:

  1. Let dateTimeFormat be ? OrdinaryCreateFromConstructor(newTarget, "%Intl.DateTimeFormat.prototype%", « [[InitializedDateTimeFormat]], [[Locale]], [[Calendar]], [[NumberingSystem]], [[TimeZone]], [[HourCycle]], [[DateStyle]], [[TimeStyle]], [[DateTimeFormat]], [[BoundFormat]] »).
  2. Let hour12 be undefined.
  3. Let modifyResolutionOptions be a new Abstract Closure with parameters (options) that captures hour12 and performs the following steps when called:
    1. Set hour12 to options.[[hour12]].
    2. Remove field [[hour12]] from options.
    3. If hour12 is not undefined, set options.[[hc]] to null.
  4. Let optionsResolution be ? ResolveOptions(%Intl.DateTimeFormat%, %Intl.DateTimeFormat%.[[LocaleData]], locales, options, « coerce-options », modifyResolutionOptions).
  5. Set options to optionsResolution.[[Options]].
  6. Let r be optionsResolution.[[ResolvedLocale]].
  7. Set dateTimeFormat.[[Locale]] to r.[[Locale]].
  8. Let resolvedCalendar be r.[[ca]].
  9. If resolvedCalendar is "islamic" or "islamic-rgsa", then
    1. Let fallbackCalendar be an implementation- and locale-defined calendar type that is one of the values returned from AvailableCalendars.
    2. Set fallbackCalendar to CanonicalizeUValue("ca", fallbackCalendar).
    3. Set resolvedCalendar to fallbackCalendar.
  10. Set dateTimeFormat.[[Calendar]] to resolvedCalendar.
  11. NOTE: Rest of algorithm unchanged.

3.2 Properties of the Intl.DateTimeFormat Constructor

3.2.1 Internal slots

[...]

The value of the [[LocaleData]] internal slot is implementation-defined within the constraints described in 2.1 and the following additional constraints, for all locale values locale:

  • [[LocaleData]].[[<locale>]].[[ca]] must be a List consisting of values from the Calendar Type column of Table 1. The list may also include "islamic" and "islamic-rgsa".
  • [[LocaleData]].[[<locale>]].[[nu]] must be a List that does not include the values "native", "traditio", or "finance".
  • [[LocaleData]].[[<locale>]].[[hc]] must be « null, "h11", "h12", "h23", "h24" ».
  • [...]

4 Locale Sensitive Functions of the ECMAScript Language Specification

4.1 Abstract Operations for Calendar Calculations

4.1.1 CalendarSupportsEra ( calendar )

The abstract operation CalendarSupportsEra takes argument calendar (a calendar type) and returns a Boolean. The following algorithm refers to the era data from UTS 35's Supplemental Calendar Data. It performs the following steps when called:

  1. If calendar is listed in the Calendar column of Table 2, return true.
  2. Return false.
Table 2: era aliases and range of eraYear
Calendar Era Aliases Minimum eraYear Maximum eraYear
"buddhist" "be" -∞ +∞
"coptic" "am" -∞ +∞
"ethiopic" "am" "incar" 1 +∞
"ethiopic" "aa" "mundi" -∞ 5500
"ethioaa" "aa" "mundi" -∞ +∞
"gregory" "ce" "ad" 1 +∞
"gregory" "bce" "bc" 1 +∞
"hebrew" "am" -∞ +∞
"indian" "shaka" -∞ +∞
"islamic-civil" "ah" 1 +∞
"islamic-civil" "bh" 1 +∞
"islamic-tbla" "ah" 1 +∞
"islamic-tbla" "bh" 1 +∞
"islamic-umalqura" "ah" 1 +∞
"islamic-umalqura" "bh" 1 +∞
"japanese" "reiwa" 1 +∞
"japanese" "heisei" 1 31
"japanese" "showa" 1 64
"japanese" "taisho" 1 15
"japanese" "meiji" 1 45
"japanese" "ce" "ad" 1 1868
"japanese" "bce" "bc" 1 +∞
"persian" "ap" -∞ +∞
"roc" "roc" "minguo" 1 +∞
"roc" "broc" "before-roc", "minguo-qian" 1 +∞

4.1.2 CanonicalizeEraInCalendar ( calendar, era )

The abstract operation CanonicalizeEraInCalendar takes arguments calendar (a calendar type that is not "iso8601") and era (a String) and returns a String or undefined. The following algorithm refers to the era data from UTS 35's Supplemental Calendar Data. It performs the following steps when called:

  1. For each row of Table 2, do
    1. Let cal be the Calendar value of the current row.
    2. If cal is equal to calendar, then
      1. Let canonicalName be the Era value of the current row.
      2. If canonicalName is equal to era, return canonicalName.
      3. Let aliases be a List whose elements are the strings given in the Aliases column of the row.
      4. If aliases contains era, return canonicalName.
  2. Return undefined.

4.1.3 IsValidMonthCodeForCalendar ( calendar, monthCode )

The abstract operation IsValidMonthCodeForCalendar takes arguments calendar (a calendar type that is not "iso8601") and monthCode (a String) and returns a Boolean. It performs the following steps when called:

  1. Let commonMonthCodes be « "M01", "M02", "M03", "M04", "M05", "M06", "M07", "M08", "M09", "M10", "M11", "M12" ».
  2. If commonMonthCodes contains monthCode, return true.
  3. If calendar is not listed in the Calendar column of Table 3, return false.
  4. Let r be the row in Table 3 which the calendar is in the Calendar column.
  5. Let specialMonthCodes be a List whose elements are the strings given in the "Additional Month Codes" column of r.
  6. If specialMonthCodes contains monthCode, return true.
  7. Return false.
Table 3: Additional Month Codes in Calendars
Calendar Additional Month Codes
"chinese" "M01L", "M02L", "M03L", "M04L", "M05L", "M06L", "M07L", "M08L", "M09L", "M10L", "M11L", "M12L"
"coptic" "M13"
"dangi" "M01L", "M02L", "M03L", "M04L", "M05L", "M06L", "M07L", "M08L", "M09L", "M10L", "M11L", "M12L"
"ethiopic" "M13"
"ethioaa" "M13"
"hebrew" "M05L"

4.1.4 IsValidEraYearForCalendar ( calendar, era, eraYear )

The abstract operation IsValidEraYearForCalendar takes arguments calendar (a calendar type that is not "iso8601"), era (a String), and eraYear (an integer) and returns a Boolean. The following algorithm refers to the era data from UTS 35's Supplemental Calendar Data. It performs the following steps when called:

  1. Let era be CanonicalizeEraInCalendar(calendar, era).
  2. If era is undefined, return false.
  3. Let r be the row in Table 2 in which calendar is in the Calendar column and era is in the Era column.
  4. Let min be the value given in the "Minimum eraYear" column of r.
  5. Let max be the value given in the "Maximum eraYear" column of r.
  6. If eraYear < min, return false.
  7. If eraYear > max, return false.
  8. Return true.

4.1.5 CalendarDateEra ( calendar, date )

The abstract operation CalendarDateEra takes arguments calendar (a calendar type that is not "iso8601") and date (a Temporal.PlainDateTime, Temporal.PlainDate, or Temporal.PlainYearMonth) and returns a String or undefined. It performs implementation-defined processing to find the era for the date corresponding to date in the context of the calendar represented by calendar and returns a lowercase String value representing that era, or undefined for calendars that do not have eras. It performs the following steps when called:

  1. If CalendarSupportsEra(calendar) is false, return undefined.
  2. Let era be the String to indicate the era corresponding to date in the context of the calendar represented by calendar according to implementation-defined processing.
  3. Return CanonicalizeEraInCalendar(calendar, era).

4.1.6 CalendarDateEraYear ( calendar, date )

The abstract operation CalendarDateEraYear takes arguments calendar (a calendar type that is not "iso8601") and date (a Temporal.PlainDateTime, Temporal.PlainDate, or Temporal.PlainYearMonth) and returns an integer or undefined. It performs implementation-defined processing to find the era for the date corresponding to date in the context of the calendar represented by calendar and returns an integer representing the ordinal position of the year of date in that era, or undefined for calendars that do not have eras. It performs the following steps when called:

  1. If CalendarSupportsEra(calendar) is false, return undefined.
  2. Let eraYear be the integer to indicate the era year corresponding to date in the context of the calendar represented by calendar according to implementation-defined processing.
  3. Assert: eraYear is an integer.
  4. Return eraYear.

4.1.7 CalendarDateArithmeticYear ( calendar, date )

The abstract operation CalendarDateArithmeticYear takes arguments calendar (a calendar type that is not "iso8601") and date (a Temporal.PlainDateTime, Temporal.PlainDate, or Temporal.PlainYearMonth) and returns an integer. It performs implementation-defined processing to find the year for the date corresponding to date in the context of the calendar represented by calendar relative to a well-defined epoch year for that calendar. It performs the following steps when called:

  1. Let year be date.[[ISOYear]].
  2. Let r be the row in Table 4 which the value of the Calendar column is calendar.
  3. Let epochYear be the value given in the "Epoch ISO Year" column of r.
  4. Let arithmeticYear be the number of whole years in the calendar represented by calendar elapsed until the ISO year year since the calendar year that started during ISO year epochYear, according to implementation-defined processing.
  5. Return arithmeticYear.
Table 4: epoch years
Calendar Epoch ISO Year
"buddhist" -543
"chinese" 0
"coptic" 283
"dangi" 0
"ethiopic" 7
"ethioaa" -5492
"gregory" 0
"hebrew" -3761
"indian" 78
"islamic-civil" 621
"islamic-tbla" 621
"islamic-umalqura" 621
"japanese" 0
"persian" 621
"roc" 1911

4.1.8 Calendar Date Records

A Calendar Date Record is a Record value used to represent a valid calendar date in a non-ISO 8601 calendar. Calendar Date Records are produced by the abstract operation CalendarISOToDate.

Calendar Date Records have the fields listed in Table 5.

This definition supersedes the one in Temporal, 12.2.1.

Table 5: Calendar Date Record Fields
Field Name Value Meaning
[[Era]] a String or undefined A lowercase String value representing the date's era, or undefined for calendars that do not have eras.
The value of this field for a calendar type calendar should be the result of calling CalendarDateEra(calendar, date), where date is a Temporal.PlainDateTime, Temporal.PlainDate, or Temporal.PlainYearMonth value corresponding to the date.
[[EraYear]] an integer or undefined The ordinal position of the date's year within its era, or undefined for calendars that do not have eras.
The value of this field for a calendar type calendar should be the result of calling CalendarDateEraYear(calendar, date), where date is a Temporal.PlainDateTime, Temporal.PlainDate, or Temporal.PlainYearMonth value corresponding to the date. Note 1
Era years are 1-indexed for many calendars, but not all (e.g., the eras of the Burmese calendar each start with a year 0). Years can also advance opposite the flow of time (as for BCE years in the Gregorian calendar).
[[Year]] an integer The date's year relative to the first day of a calendar-specific "epoch year".
The value of this field for a calendar type calendar should be the result of calling CalendarDateArithmeticYear(calendar, date), where date is a Temporal.PlainDateTime, Temporal.PlainDate, or Temporal.PlainYearMonth value corresponding to the date. Note 2
The year is relative to the first day of the calendar's epoch year, so if the epoch era starts in the middle of the year, the year will be the same value before and after the start date of the era.
[[Month]] a positive integer The 1-based ordinal position of the date's month within its year. Note 3
When the number of months in a year of the calendar is variable, a different value can be returned for dates that are part of the same month in different years. For example, in the Hebrew calendar, 1 Nisan 5781 is associated with value 7 while 1 Nisan 5782 is associated with value 8 because 5782 is a leap year and Nisan follows the insertion of Adar I.
[[MonthCode]] a String The month code of the date's month. The month code for a month that is not a leap month and whose 1-based ordinal position in a common year of the calendar (i.e., a year that is not a leap year) is n should be the string-concatenation of "M" and ToZeroPaddedDecimalString(n, 2), and the month code for a month that is a leap month inserted after a month whose 1-based ordinal position in a common year of the calendar is p should be the string-concatenation of "M", ToZeroPaddedDecimalString(p, 2), and "L". Note 4
For example, in the Hebrew calendar, the month code of Adar (and Adar II, in leap years) is "M06" and the month code of Adar I (the leap month inserted before Adar II) is "M05L". In a calendar with a leap month at the start of some years, the month code of that month would be "M00L".
[[Day]] a positive integer The 1-based ordinal position of the date's day within its month.
[[DayOfWeek]] a positive integer The day of the week corresponding to the date. The value should be 1-based, where 1 is the day corresponding to Monday in the given calendar.
[[DayOfYear]] a positive integer The 1-based ordinal position of the date's day within its year.
[[WeekOfYear]] a Year-Week Record

The date's calendar week of year, and the corresponding week calendar year.

The Year-Week Record's [[Week]] field should be 1-based.

The Year-Week Record's [[Year]] field is relative to the first day of a calendar-specific "epoch year", as in the Calendar Date Record's [[Year]] field, not relative to an era as in [[EraYear]].

Usually the Year-Week Record's [[Year]] field will contain the same value as the Calendar Date Record's [[Year]] field, but may contain the previous or next year if the week number in the Year-Week Record's [[Week]] field overlaps two different years. See also ISOWeekOfYear.

The Year-Week Record contains undefined in [[Week]] and [[Year]] field for calendars that do not have a well-defined week numbering system.

Note 5
Currently, of the calendars supported in this specification, only "iso8601" has a well-defined, locale-independent week numbering system. For all other calendars, the Year-Week Record fields are undefined.
[[DaysInWeek]] a positive integer The number of days in the date's week.
[[DaysInMonth]] a positive integer The number of days in the date's month.
[[DaysInYear]] a positive integer The number of days in the date's year.
[[MonthsInYear]] a positive integer The number of months in the date's year.
[[InLeapYear]] a Boolean true if the date falls within a leap year, and false otherwise. Note 6
A "leap year" is a year that contains more days than other years (for solar or lunar calendars) or more months than other years (for lunisolar calendars like Hebrew or Chinese). Some calendars, especially lunisolar ones, have further variation in year length that is not represented in the output of this operation (e.g., the Hebrew calendar includes common years with 353, 354, or 355 days and leap years with 383, 384, or 385 days).

4.1.9 CalendarDateAdd ( calendar, isoDate, duration, overflow )

The implementation-defined abstract operation CalendarDateAdd takes arguments calendar (a calendar type), isoDate (an ISO Date Record), duration (a Date Duration Record), and overflow (constrain or reject) and returns either a normal completion containing an ISO Date Record or a throw completion. It adds dateDuration to isoDate using the years, months, and weeks reckoning of calendar. If addition of years or months results in a nonexistent date, depending on overflow it will be coerced to an existing date or the operation will throw.

This definition supersedes the definition provided in Temporal, 12.2.6.

It performs the following steps when called:

  1. If calendar is "iso8601", then
    1. Let intermediate be BalanceISOYearMonth(isoDate.[[Year]] + duration.[[Years]], isoDate.[[Month]] + duration.[[Months]]).
    2. Set intermediate to ? RegulateISODate(intermediate.[[Year]], intermediate.[[Month]], isoDate.[[Day]], overflow).
    3. Let d be intermediate.[[Day]] + duration.[[Days]] + 7 × duration.[[Weeks]].
    4. Let result be BalanceISODate(intermediate.[[Year]], intermediate.[[Month]], d).
  2. Else,
    1. NOTE: The algorithm when calendar is not "iso8601" is implementation-defined, but all calendars follow the general steps given here, which is a generalization of the precise algorithm specified above for "iso8601".
    2. Let calendarDate be CalendarISOToDate(calendar, isoDate).
    3. Add duration.[[Years]] to calendarDate.
    4. (This step only matters for lunisolar calendars.) If calendarDate.[[MonthCode]] is a leap month that doesn't exist in the year, then:
      1. If overflow is reject, throw a RangeError exception.
      2. Set calendarDate to another date according to the cultural conventions of that calendar's users. Of the currently supported calendars: if calendar is "chinese" or "dangi", change calendarDate.[[MonthCode]] to the same month code but without the "L". If calendar is "hebrew", change calendarDate.[[MonthCode]] from "M05L" to "M06".
      3. Update calendarDate.[[Month]] accordingly.
    5. Add duration.[[Months]] to calendarDate, balancing calendarDate if it goes over a year boundary.
    6. If the date described by calendarDate does not exist, then
      1. If overflow is reject, throw a RangeError exception.
      2. If calendarDate.[[MonthCode]] is a valid month code for calendarDate.[[Year]], but the date described by calendarDate does not exist, set calendarDate.[[Day]] to the closest day in the same month. If there are two equally-close dates in the same month, pick the later one.
      3. (This step does not apply to any currently supported calendars.) If the date described by calendarDate still does not exist, set calendarDate to the closest date in the same year. If there are two equally-close dates in that year, pick the later one.
    7. Add duration.[[Weeks]] and duration.[[Days]] to calendarDate, balancing calendarDate if it goes over a month or year boundary.
    8. Let result be ? CalendarDateToISO(calendar, calendarDate, overflow).
  3. If ISODateWithinLimits(result) is false, throw a RangeError exception.
  4. Return result.

4.1.10 CalendarDateUntil ( calendar, one, two, largestUnit )

The implementation-defined abstract operation CalendarDateUntil takes arguments calendar (a calendar type), one (an ISO Date Record), two (an ISO Date Record), and largestUnit (a date unit) and returns a Date Duration Record. It determines the difference between the dates one and two using the years, months, and weeks reckoning of calendar. No fields larger than largestUnit will be non-zero in the resulting Date Duration Record.

This definition supersedes the definition provided in Temporal, 12.2.7.

It performs the following steps when called:

  1. If calendar is "iso8601", then
    1. Let sign be -CompareISODate(one, two).
    2. If sign = 0, return ZeroDateDuration().
    3. Let years be 0.
    4. If largestUnit is year, then
      1. Let candidateYears be sign.
      2. Repeat, while ISODateSurpasses(sign, one.[[Year]] + candidateYears, one.[[Month]], one.[[Day]], two) is false,
        1. Set years to candidateYears.
        2. Set candidateYears to candidateYears + sign.
    5. Let months be 0.
    6. If largestUnit is year or largestUnit is month, then
      1. Let candidateMonths be sign.
      2. Let intermediate be BalanceISOYearMonth(one.[[Year]] + years, one.[[Month]] + candidateMonths).
      3. Repeat, while ISODateSurpasses(sign, intermediate.[[Year]], intermediate.[[Month]], one.[[Day]], two) is false,
        1. Set months to candidateMonths.
        2. Set candidateMonths to candidateMonths + sign.
        3. Set intermediate to BalanceISOYearMonth(intermediate.[[Year]], intermediate.[[Month]] + sign).
    7. Set intermediate to BalanceISOYearMonth(one.[[Year]] + years, one.[[Month]] + months).
    8. Let constrained be ! RegulateISODate(intermediate.[[Year]], intermediate.[[Month]], one.[[Day]], constrain).
    9. Let weeks be 0.
    10. If largestUnit is week, then
      1. Let candidateWeeks be sign.
      2. Set intermediate to BalanceISODate(constrained.[[Year]], constrained.[[Month]], constrained.[[Day]] + 7 × candidateWeeks).
      3. Repeat, while ISODateSurpasses(sign, intermediate.[[Year]], intermediate.[[Month]], intermediate.[[Day]], two) is false,
        1. Set weeks to candidateWeeks.
        2. Set candidateWeeks to candidateWeeks + sign.
        3. Set intermediate to BalanceISODate(intermediate.[[Year]], intermediate.[[Month]], intermediate.[[Day]] + 7 × sign).
    11. Let days be 0.
    12. Let candidateDays be sign.
    13. Set intermediate to BalanceISODate(constrained.[[Year]], constrained.[[Month]], constrained.[[Day]] + 7 × weeks + candidateDays).
    14. Repeat, while ISODateSurpasses(sign, intermediate.[[Year]], intermediate.[[Month]], intermediate.[[Day]], two) is false,
      1. Set days to candidateDays.
      2. Set candidateDays to candidateDays + sign.
      3. Set intermediate to BalanceISODate(intermediate.[[Year]], intermediate.[[Month]], intermediate.[[Day]] + sign).
    15. Return ! CreateDateDurationRecord(years, months, weeks, days).
  2. NOTE: The algorithm when calendar is not "iso8601" is implementation-defined, but all calendars follow the general steps given here, which is a generalization of the precise algorithm specified above for "iso8601".
  3. If largestUnit is year, then
    1. Add (without constraining) as many years as possible to one, in the direction from one to two, without surpassing two. "Surpassing" here (and in all steps below) means to compare years numerically, then month codes lexicographically, then days numerically; if any of them exceed two in the direction from one to two, then two is surpassed.
    2. Constrain one to a real year and month, not taking day into account. This step only matters for lunisolar calendars.
  4. If largestUnit is year or month, then
    1. Add (without constraining) as many months as possible to one without surpassing two.
    2. Constrain one to a real year, month, and day.
  5. If largestUnit is week, add as many weeks as possible to one without surpassing two.
  6. Add as many days as possible to one until it is equal to two.
  7. Return a Date Duration Record of the number of years, months, weeks, and days added.

4.1.11 CalendarDateToISO ( calendar, fields, overflow )

The implementation-defined abstract operation CalendarDateToISO takes arguments calendar (a calendar type), fields (a Calendar Fields Record), and overflow (constrain or reject) and returns either a normal completion containing an ISO Date Record or a throw completion. It performs implementation-defined processing to convert fields, which represents either a date or a year and month in the built-in calendar identified by calendar, to a corresponding representative date in the ISO 8601 calendar, subject to overflow correction specified by overflow. For reject, values that do not form a valid date cause an exception to be thrown, as described below. For constrain, values that do not form a valid date are clamped to their respective valid range.

This definition supersedes the definition provided in Temporal, 12.2.19.

It performs the following steps when called:

  1. If calendar is "iso8601", then
    1. Assert: fields.[[Year]], fields.[[Month]], and fields.[[Day]] are not unset.
    2. Return ? RegulateISODate(fields.[[Year]], fields.[[Month]], fields.[[Day]], overflow).
  2. NOTE: The algorithm when calendar is not "iso8601" is implementation-defined, but all calendars follow the general steps given here, which is a generalization of the precise algorithm specified above for "iso8601".
  3. If fields.[[Era]] and fields.[[EraYear]] are not unset and IsValidEraYearForCalendar(calendar, fields.[[Era]], fields.[[EraYear]]) is false, throw a RangeError exception.
  4. If fields.[[MonthCode]] is not unset and IsValidMonthCodeForCalendar(calendar, fields.[[MonthCode]]) is false, throw a RangeError exception.
  5. If fields describes an existing date in calendar, return an implementation-defined ISO Date Record that corresponds to the date described by fields.
  6. If overflow is reject, throw a RangeError exception.
  7. (This step only matters for lunisolar calendars.) If fields.[[MonthCode]] is a leap month that doesn't exist in the year, then:
    1. Set fields to another date according to the cultural conventions of that calendar's users. Of the currently supported calendars: if calendar is "chinese" or "dangi", change fields.[[MonthCode]] to the same month code but without the "L". If calendar is "hebrew", change fields.[[MonthCode]] from "M05L" to "M06".
    2. Update fields.[[Month]] accordingly.
  8. If fields.[[MonthCode]] is a valid month code for fields.[[Year]], but the date described by fields does not exist, set fields.[[Day]] to the closest day in the same month. If there are two equally-close dates in the same month, pick the later one.
  9. (This step does not apply to any currently supported calendars.) If the date described by fields still does not exist, set fields to the closest date in the same year. If there are two equally-close dates in that year, pick the later one.
  10. Return an implementation-defined ISO Date Record that corresponds to the date described by fields.

4.1.12 CalendarExtraFields ( calendar, fields )

The implementation-defined abstract operation CalendarExtraFields takes arguments calendar (a calendar type) and fields (a List of values from the Enumeration Key column of Table 19) and returns a List of values from the Enumeration Key column of Table 19. It characterizes calendar-specific fields that are relevant for the provided fields in the built-in calendar identified by calendar.

This definition supersedes the definition provided in Temporal, 12.2.22.

It performs the following steps when called:

  1. If fields contains an element equal to year and CalendarSupportsEra(calendar) is true, then
    1. Append era and era-year to fields.
  2. Return fields.

4.1.13 CalendarFieldKeysToIgnore ( calendar, keys )

The implementation-defined abstract operation CalendarFieldKeysToIgnore takes arguments calendar (a calendar type) and keys (a List of values from the Enumeration Key column of Table 19) and returns a List of values from the Enumeration Key column of Table 19. It determines which calendar date fields changing any of the fields named in keys can potentially conflict with or invalidate, for the given calendar. A field always invalidates at least itself.

This definition supersedes the definition provided in Temporal, 12.2.23.

It performs the following steps when called:

  1. Let ignoredKeys be an empty List.
  2. For each element key of keys, do
    1. If key is month, append month-code to ignoredKeys.
    2. Else if key is month-code, append month to ignoredKeys.
    3. If key is one of era, era-year, or year and CalendarSupportsEra(calendar) is true, then
      1. Append era, era-year, and year to ignoredKeys.
    4. Else,
      1. Append key to ignoredKeys.
  3. NOTE: While ignoredKeys can have duplicate elements, this is not intended to be meaningful. This specification only checks whether particular keys are or are not members of the list.
  4. Return ignoredKeys.

Copyright & Software License

Software License

All Software contained in this document ("Software") is protected by copyright and is being made available under the "BSD License", included below. This Software may be subject to third party rights (rights from parties other than Ecma International), including patent rights, and no licenses under such third party rights are granted under this license even if the third party concerned is a member of Ecma International. SEE THE ECMA CODE OF CONDUCT IN PATENT MATTERS AVAILABLE AT https://ecma-international.org/memento/codeofconduct.htm FOR INFORMATION REGARDING THE LICENSING OF PATENT CLAIMS THAT ARE REQUIRED TO IMPLEMENT ECMA INTERNATIONAL STANDARDS.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. Neither the name of the authors nor Ecma International may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE ECMA INTERNATIONAL "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ECMA INTERNATIONAL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.