diff --git a/biblio.json b/biblio.json index ec97db0..b213f38 100644 --- a/biblio.json +++ b/biblio.json @@ -121,6 +121,16 @@ "type": "op", "aoid": "ZeroDateDuration", "id": "sec-temporal-zerodateduration" + }, + { + "type": "op", + "aoid": "ParseMonthCode", + "id": "sec-temporal-parsemonthcode" + }, + { + "type": "op", + "aoid": "CreateMonthCode", + "id": "sec-temporal-createmonthcode" } ] } diff --git a/spec.emu b/spec.emu index ead01a2..6cd16c6 100644 --- a/spec.emu +++ b/spec.emu @@ -533,36 +533,135 @@ contributors: Google, Ecma International Calendar Additional Month Codes + Leap to Common Month Transformation *"chinese"* *"M01L"*, *"M02L"*, *"M03L"*, *"M04L"*, *"M05L"*, *"M06L"*, *"M07L"*, *"M08L"*, *"M09L"*, *"M10L"*, *"M11L"*, *"M12L"* + ~skip-backward~ *"coptic"* *"M13"* + *"dangi"* *"M01L"*, *"M02L"*, *"M03L"*, *"M04L"*, *"M05L"*, *"M06L"*, *"M07L"*, *"M08L"*, *"M09L"*, *"M10L"*, *"M11L"*, *"M12L"* + ~skip-backward~ *"ethioaa"* *"M13"* + *"ethiopic"* *"M13"* + *"hebrew"* *"M05L"* + ~skip-forward~ + +

+ YearContainsMonthCode ( + _calendar_: a calendar type that is not *"iso8601"*, + _arithmeticYear_: an integer, + _monthCode_: a month code, + ): a Boolean +

+
+
description
+
+ It returns whether the given _monthCode_ exists in _arithmeticYear_ of _calendar_. +
+
+

It performs the following steps when called:

+ + 1. Assert: IsValidMonthCodeForCalendar(_calendar_, _monthCode_) is *true*. + 1. If ! ParseMonthCode(_monthCode_).[[IsLeap]] is *false*, return *true*. + 1. Return whether the leap month indicated by _monthCode_ exists in the year _arithmeticYear_ in _calendar_, using calendar-dependent behaviour. + +
+ + +

+ ConstrainMonthCode ( + _calendar_: a calendar type that is not *"iso8601"*, + _arithmeticYear_: an integer, + _monthCode_: a month code, + _overflow_: ~constrain~ or ~reject~, + ): either a normal completion containing a month code or a throw completion +

+
+
description
+
+ It returns the month code in _arithmeticYear_ of _calendar_ that best matches the given _monthCode_. If _monthCode_ does not exist in _arithmeticYear_, it is constrained to the best common month if _overflow_ is ~constrain~, or an error is thrown if _overflow_ is ~reject~. +
+
+

It performs the following steps when called:

+ + 1. Assert: IsValidMonthCodeForCalendar(_calendar_, _monthCode_) is *true*. + 1. If YearContainsMonthCode(_calendar_, _arithmeticYear_, _monthCode_) is *true*, return _monthCode_. + 1. If _overflow_ is ~reject~, throw a *RangeError* exception. + 1. Assert: _calendar_ is listed in the Calendar column of . + 1. Let _r_ be the row in which the _calendar_ is in the Calendar column. + 1. Let _shiftType_ be the value given in the *"Leap to Common Month Transformation"* column of _r_. + 1. If _shiftType_ is ~skip-backward~, then + 1. Return CreateMonthCode(! ParseMonthCode(_monthCode_).[[MonthNumber]], *false*). + 1. Else, + 1. Assert: _monthCode_ is *"M05L"*. + 1. Return *"M06"*. + +
+ + +

+ MonthCodeToOrdinal ( + _calendar_: a calendar type that is not *"iso8601"*, + _arithmeticYear_: an integer, + _monthCode_: a month code, + ): an integer +

+
+
description
+
+ It returns the ordinal month number for _monthCode_ in _arithmeticYear_ of _calendar_. The given _monthCode_ must exist in the given year. +
+
+

It performs the following steps when called:

+ + 1. Assert: YearContainsMonthCode(_calendar_, _arithmeticYear_, _monthCode_) is *true*. + 1. Let _monthsBefore_ be 0. + 1. Let _number_ be 1. + 1. Let _isLeap_ be *false*. + 1. Let _r_ be the row in which the _calendar_ is in the Calendar column. + 1. If the *"Leap to Common Month Transformation"* column of _r_ is empty, then + 1. Return ! ParseMonthCode(_monthCode_).[[MonthNumber]]. + 1. Assert: The *"Additional Month Codes"* column of _r_ does not contain *"M00L"* or *"M13"*. + 1. Assert: The following loop will terminate. + 1. Repeat, while _number_ ≤ 12, + 1. Let _currentMonthCode_ be CreateMonthCode(_number_, _isLeap_). + 1. If YearContainsMonthCode(_calendar_, _arithmeticYear_, _currentMonthCode_), then + 1. Set _monthsBefore_ to _monthsBefore_ + 1. + 1. If _currentMonthCode_ is _monthCode_, then + 1. Return _monthsBefore_. + 1. If _isLeap_ is *false*, then + 1. Set _isLeap_ to *true*. + 1. Else, + 1. Set _isLeap_ to *false*. + 1. Set _number_ to _number_ + 1. + +
+

IsValidEraYearForCalendar ( @@ -903,10 +1002,11 @@ contributors: Google, Ecma International

It performs the following steps when called:

1. Let _calendarDate_ be CalendarISOToDate(_calendar_, _isoDate_). - 1. Add _duration_.[[Years]] to _calendarDate_. - 1. (This step only matters for lunisolar calendars.) If _calendarDate_.[[MonthCode]] is a leap month that doesn't exist in the year, then: - 1. 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"*. - 1. Update _calendarDate_.[[Month]] accordingly. + 1. Add _duration_.[[Years]] to _calendarDate_ without changing any less-significant fields. + 1. If YearContainsMonthCode(_calendar_, _calendarDate_.[[Year]], _calendarDate_.[[MonthCode]]) is *false*, then + 1. NOTE: This only happens in lunisolar calendars. + 1. Set _calendarDate_.[[MonthCode]] to ! ConstrainMonthCode(_calendar_, _calendarDate_.[[Year]], _calendarDate_.[[MonthCode]], ~constrain~). + 1. Set _calendarDate_.[[Month]] to MonthCodeToOrdinal(_calendar_, _calendarDate_.[[Year]], _calendarDate_.[[MonthCode]]). 1. Add _duration_.[[Months]] to _calendarDate_, balancing _calendarDate_ if it goes over a year boundary. 1. If the date described by _calendarDate_ does not exist, then 1. If _overflow_ is ~reject~, throw a *RangeError* exception. @@ -972,16 +1072,23 @@ contributors: Google, Ecma International

This definition supersedes the definition provided in .

It performs the following steps when called:

- 1. If _fields_.[[Era]] and _fields_.[[EraYear]] are not ~unset~ and IsValidEraYearForCalendar(_calendar_, _fields_.[[Era]], _fields_.[[EraYear]]) is *false*, throw a *RangeError* exception. - 1. If _fields_.[[MonthCode]] is not ~unset~ and IsValidMonthCodeForCalendar(_calendar_, _fields_.[[MonthCode]]) is *false*, throw a *RangeError* exception. - 1. If _fields_ describes an existing date in _calendar_, return an implementation-defined ISO Date Record that corresponds to the date described by _fields_. - 1. If _overflow_ is ~reject~, throw a *RangeError* exception. - 1. (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"*. - 1. Update _fields_.[[Month]] accordingly. - 1. 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. - 1. (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. - 1. Return an implementation-defined ISO Date Record that corresponds to the date described by _fields_. + 1. If _fields_.[[Era]] and _fields_.[[EraYear]] are not ~unset~, then + 1. If IsValidEraYearForCalendar(_calendar_, _fields_.[[Era]], _fields_.[[EraYear]]) is *false*, throw a *RangeError* exception. + 1. Let _arithmeticYear_ be CalendarDateArithmeticYearForEraYear(_calendar_, _fields_.[[Era]], _fields_.[[EraYear]]). + 1. Else, + 1. Assert: _fields_.[[Year]] is not ~unset~. + 1. Let _arithmeticYear_ be _fields_.[[Year]]. + 1. If _fields_.[[MonthCode]] is not ~unset~, then + 1. If IsValidMonthCodeForCalendar(_calendar_, _fields_.[[MonthCode]]) is *false*, throw a *RangeError* exception. + 1. Let _constrainedMonthCode_ be ? ConstrainMonthCode(_calendar_, _arithmeticYear_, _fields_.[[MonthCode]], _overflow_). + 1. Let _ordinalMonth_ be MonthCodeToOrdinal(_calendar_, _arithmeticYear_, _constrainedMonthCode_). + 1. Else, + 1. Assert: _fields_.[[Month]] is not ~unset~. + 1. Let _ordinalMonth_ be _fields_.[[Month]]. + 1. Let _day_ be _fields_.[[Day]]. + 1. Assert: _day_ is not ~unset~. + 1. If the date described by _calendar_, _arithmeticYear_, _ordinalMonth_, and _day_ does not exist, set _day_ to the closest day in the same month. If there are two equally-close dates in the same month, pick the later one. + 1. Return an implementation-defined ISO Date Record that corresponds to the date described by _calendar_, _arithmeticYear_, _ordinalMonth_, and _day_.