-
Notifications
You must be signed in to change notification settings - Fork 8
Use more specific calendar-dependent operations in Until, Add, and ToISO #69
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 2 commits
8138fc3
3484587
a358230
a407f48
f8db768
2748433
663b09d
eac8653
c79d968
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -828,7 +828,7 @@ contributors: Google, Ecma International | |
</h1> | ||
<dl class="header"> | ||
<dt>description</dt> | ||
<dd>It produces the year relative to the epoch year (the arithmetic year) for a given set of era, eraYear for a calendar that has eras.</dd> | ||
<dd>It produces the year relative to the epoch year (the arithmetic year) for a given set of _era_, _eraYear_ in _calendar_, a calendar that includes an era named _era_.</dd> | ||
</dl> | ||
<emu-alg> | ||
1. Let _era_ be CanonicalizeEraInCalendar(_calendar_, _era_). | ||
|
@@ -981,6 +981,169 @@ contributors: Google, Ecma International | |
</emu-table> | ||
</emu-clause> | ||
|
||
<emu-clause id="sec-temporal-calendardatearithmeticaltoiso" type="implementation-defined abstract operation"> | ||
<h1> | ||
CalendarDateArithmeticalToISO ( | ||
_calendar_: a calendar type that is not *"iso8601"*, | ||
_arithmeticYear_: an integer, | ||
_ordinalMonth_: a positive integer, | ||
_day_: an integer, | ||
): either a normal completion containing an ISO Date Record or a throw completion | ||
</h1> | ||
<dl class="header"> | ||
<dt>description</dt> | ||
<dd> | ||
It returns an ISO Date Record that, when converted to a Calendar Date Record with _calendar_ (for example, with CalendarISOToDate), contains the given _arithmeticYear_, _ordinalMonth_, and _day_ values in its [[Year]], [[Month]], and [[Day]] fields. If this is not possible, a RangeError is thrown. | ||
</dd> | ||
</dl> | ||
<p>It performs the following steps when called:</p> | ||
<emu-alg> | ||
1. If _arithmeticYear_, _ordinalMonth_, and _day_ do not form a valid date in _calendar_, throw a RangeError exception. | ||
1. Return a calendar-dependent ISO Date Record as described above. | ||
</emu-alg> | ||
sffc marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
</emu-clause> | ||
|
||
<emu-clause id="sec-temporal-calendardaysinmonth" type="implementation-defined abstract operation"> | ||
|
||
<h1> | ||
CalendarDaysInMonth ( | ||
_calendar_: a calendar type that is not *"iso8601"*, | ||
_arithmeticYear_: an integer, | ||
_ordinalMonth_: a positive integer, | ||
): an integer | ||
</h1> | ||
<dl class="header"> | ||
<dt>description</dt> | ||
<dd> | ||
It interprets _arithmeticYear_ and _ordinalMonth_ as arithmetical values in the given _calendar_ and returns the number of days in the corresponding month. | ||
</dd> | ||
</dl> | ||
<p>It performs the following steps when called:</p> | ||
<emu-alg> | ||
1. Return a calendar-dependent integer as described above. | ||
|
||
</emu-alg> | ||
</emu-clause> | ||
|
||
<emu-clause id="sec-temporal-calendarmonthsinyear" type="implementation-defined abstract operation"> | ||
<h1> | ||
CalendarMonthsInYear ( | ||
_calendar_: a calendar type that is not *"iso8601"*, | ||
sffc marked this conversation as resolved.
Show resolved
Hide resolved
|
||
_arithmeticYear_: an integer, | ||
): an integer | ||
</h1> | ||
<dl class="header"> | ||
<dt>description</dt> | ||
<dd> | ||
It interprets _arithmeticYear_ as arithmetical value in the given _calendar_ and returns the number of months in the corresponding year. | ||
</dd> | ||
</dl> | ||
<p>It performs the following steps when called:</p> | ||
<emu-alg> | ||
1. Return a calendar-dependent integer as described above. | ||
</emu-alg> | ||
sffc marked this conversation as resolved.
Show resolved
Hide resolved
|
||
</emu-clause> | ||
|
||
<emu-clause id="sec-temporal-balancenonisodate" type="implementation-defined abstract operation"> | ||
<h1> | ||
BalanceNonISODate ( | ||
sffc marked this conversation as resolved.
Show resolved
Hide resolved
|
||
_calendar_: a calendar type that is not *"iso8601"*, | ||
_arithmeticYear_: an integer, | ||
_ordinalMonth_: an integer, | ||
_day_: an integer, | ||
): a Record with fields [[Year]] (an integer), [[Month]] (an integer), and [[Day]] (an integer) | ||
</h1> | ||
<dl class="header"> | ||
<dt>description</dt> | ||
<dd> | ||
It interprets the given _arithmeticYear_, potentially out-of-range _ordinalMonth_, and potentially out-of-range _day_ as arithmetical values in the given _calendar_ and returns in-range values by overflowing out-of-range _ordinalMonth_ or _day_ values into the next-highest unit. | ||
This date may be outside the range given by ISODateTimeWithinLimits. | ||
</dd> | ||
</dl> | ||
<p>It performs the following steps when called:</p> | ||
<emu-alg> | ||
1. Let _resolvedYear_ be _arithmeticYear_. | ||
1. Let _resolvedMonth_ be _ordinalMonth_. | ||
1. Let _monthsInYear_ be CalendarMonthsInYear(_calendar_, _resolvedYear_). | ||
1. Repeat, while _resolvedMonth_ ≤ 0, | ||
1. Set _resolvedYear_ to _resolvedYear_ - 1. | ||
1. Set _monthsInYear_ to CalendarMonthsInYear(_calendar_, _resolvedYear_). | ||
1. Set _resolvedMonth_ to _resolvedMonth_ + _monthsInYear_. | ||
1. Repeat, while _resolvedMonth_ > _monthsInYear_, | ||
1. Set _resolvedMonth_ to _resolvedMonth_ - _monthsInYear_. | ||
1. Set _resolvedYear_ to _resolvedYear_ + 1. | ||
1. Set _monthsInYear_ to CalendarMonthsInYear(_calendar_, _resolvedYear_). | ||
1. Let _resolvedDay_ be _day_. | ||
1. Let _daysInMonth_ be CalendarDaysInMonth(_calendar_, _resolvedYear_, _resolvedMonth_). | ||
1. Repeat, while _resolvedDay_ ≤ 0, | ||
1. Set _resolvedMonth_ to _resolvedMonth_ - 1. | ||
1. If _resolvedMonth_ is 0, then | ||
1. Set _resolvedYear_ to _resolvedYear_ - 1. | ||
1. Set _monthsInYear_ to CalendarMonthsInYear(_calendar_, _resolvedYear_). | ||
1. Set _resolvedMonth_ to _monthsInYear_. | ||
1. Set _daysInMonth_ to CalendarDaysInMonth(_calendar_, _resolvedYear_, _resolvedMonth_). | ||
1. Set _resolvedDay_ to _day_ + _daysInMonth_. | ||
1. Repeat, while _resolvedDay_ > _daysInMonth_, | ||
1. Set _resolvedDay_ to _resolvedDay_ - _daysInMonth_. | ||
1. Set _resolvedMonth_ to _resolvedMonth_ + 1. | ||
1. If _resolvedMonth_ > _monthsInYear_, then | ||
1. Set _resolvedYear_ to _resolvedYear_ + 1. | ||
1. Set _monthsInYear_ to CalendarMonthsInYear(_calendar_, _resolvedYear_). | ||
1. Set _resolvedMonth_ to 1. | ||
1. Set _daysInMonth_ to CalendarDaysInMonth(_calendar_, _resolvedYear_, _resolvedMonth_). | ||
1. Return the Record { [[Year]]: _resolvedYear_, [[Month]]: _resolvedMonth_, [[Day]]: _resolvedDay_ }. | ||
</emu-alg> | ||
</emu-clause> | ||
|
||
<emu-clause id="sec-temporal-nonisodatesurpasses" type="implementation-defined abstract operation"> | ||
<h1> | ||
NonISODateSurpasses ( | ||
_calendar_: a calendar type that is not *"iso8601"*, | ||
_sign_: -1 or 1, | ||
_fromIsoDate_: an ISO Date Record, | ||
_toIsoDate_: an ISO Date Record, | ||
_years_: an integer, | ||
_months_: an integer, | ||
_weeks_: an integer, | ||
_days_: an integer, | ||
): a Boolean | ||
</h1> | ||
<dl class="header"> | ||
<dt>description</dt> | ||
<dd> | ||
The return value indicates whether the date _date1_, the result of adding the duration denoted by _years_, _months_, _weeks_, and _days_ to _fromIsoDate_ in the calendar system denoted by _calendar_, surpasses _toIsoDate_ in the direction denoted by _sign_. | ||
If _weeks_ and _days_ are both zero, then _date1_ need not exist (for example, it could be February 30). | ||
</dd> | ||
</dl> | ||
<p>It performs the following steps when called:</p> | ||
<emu-alg> | ||
1. Let _parts_ be CalendarISOToDate(_calendar_, _fromIsoDate_). | ||
1. Let _y0_ be _parts_.[[Year]] + _years_. | ||
1. Let _m0_ be MonthCodeToOrdinal(_calendar_, _y0_, ! ConstrainMonthCode(_calendar_, _y0_, _parts_.[[MonthCode]], ~constrain~)). | ||
1. Let _endOfMonth_ be BalanceNonISODate(_calendar_, _y0_, _m0_ + _months_ + 1, 0). | ||
1. Let _baseDay_ be _parts_.[[Day]]. | ||
1. If _weeks_ is not 0 or _days_ is not 0, then | ||
1. If _baseDay_ < _endOfMonth_.[[Day]], then | ||
1. Let _regulatedDay_ be _baseDay_. | ||
1. Else, | ||
1. Let _regulatedDay_ be _endOfMonth_.[[Day]]. | ||
1. Let _balancedDate_ be BalanceNonISODate(_calendar_, _endOfMonth_.[[Year]], _endOfMonth_.[[Month]], _regulatedDay_ + 7 * _weeks_ + _days_). | ||
1. Let _y1_ be _balancedDate_.[[Year]]. | ||
1. Let _m1_ be _balancedDate_.[[Month]]. | ||
1. Let _d1_ be _balancedDate_.[[Day]]. | ||
1. Else, | ||
1. Let _y1_ be _endOfMonth_.[[Year]]. | ||
1. Let _m1_ be _endOfMonth_.[[Month]]. | ||
1. Let _d1_ be _baseDay_. | ||
sffc marked this conversation as resolved.
Show resolved
Hide resolved
|
||
1. Let _calDate2_ be CalendarISOToDate(_calendar_, _toIsoDate_). | ||
1. If _y1_ ≠ _calDate2_.[[Year]], then | ||
1. If _sign_ × (_y1_ - _calDate2_.[[Year]]) > 0, return *true*. | ||
1. Else if _m1_ ≠ _calDate2_.[[Month]], then | ||
1. If _sign_ × (_m1_ - _calDate2_.[[Month]]) > 0, return *true*. | ||
1. Else if _d1_ ≠ _calDate2_.[[Day]], then | ||
1. If _sign_ × (_d1_ - _calDate2_.[[Day]]) > 0, return *true*. | ||
1. Return *false*. | ||
</emu-alg> | ||
</emu-clause> | ||
|
||
<emu-clause id="sup-temporal-nonisodateadd" type="implementation-defined abstract operation"> | ||
<h1> | ||
NonISODateAdd ( | ||
|
@@ -997,23 +1160,22 @@ contributors: Google, Ecma International | |
It may throw a *RangeError* exception if _overflow_ is ~reject~ and the resulting month or day would need to be clamped in order to form a valid date in _calendar_. | ||
</dd> | ||
</dl> | ||
<p>The behaviour is implementation-defined, but all calendars follow the general steps given here, which is a generalization of the precise algorithm specified in CalendarDateAdd for *"iso8601"*.</p> | ||
<p>All calendars follow the steps given here, which is a generalization of the precise algorithm specified in CalendarDateAdd for *"iso8601"*.</p> | ||
<p>This definition supersedes the definition provided in <emu-xref href="#sec-temporal-nonisodateadd"></emu-xref>.</p> | ||
<p>It performs the following steps when called:</p> | ||
<emu-alg> | ||
1. Let _calendarDate_ be CalendarISOToDate(_calendar_, _isoDate_). | ||
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. Let _parts_ be CalendarISOToDate(_calendar_, _isoDate_). | ||
sffc marked this conversation as resolved.
Show resolved
Hide resolved
|
||
1. Let _y0_ be _parts_.[[Year]] + _duration_.[[Years]]. | ||
1. Let _m0_ be MonthCodeToOrdinal(_calendar_, _y0_, ! ConstrainMonthCode(_calendar_, _y0_, _parts_.[[MonthCode]], ~constrain~)). | ||
1. Let _endOfMonth_ be BalanceNonISODate(_calendar_, _y0_, _m0_ + _duration_.[[Months]] + 1, 0). | ||
1. Let _baseDay_ be _parts_.[[Day]]. | ||
1. If _endOfMonth_.[[Day]] < _baseDay_, then | ||
sffc marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
1. If _overflow_ is ~reject~, throw a *RangeError* exception. | ||
1. 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. | ||
1. (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. | ||
1. Add _duration_.[[Weeks]] and _duration_.[[Days]] to _calendarDate_, balancing _calendarDate_ if it goes over a month or year boundary. | ||
1. Let _result_ be ? CalendarDateToISO(_calendar_, _calendarDate_, _overflow_). | ||
1. Let _regulatedDay_ be _endOfMonth_.[[Day]]. | ||
1. Else, | ||
1. Let _regulatedDay_ be _baseDay_. | ||
1. Let _balancedDate_ be BalanceNonISODate(_calendar_, _endOfMonth_.[[Year]], _endOfMonth_.[[Month]], _regulatedDay_ + 7 * _duration_.[[Weeks]] + _duration_.[[Days]]). | ||
1. Let _result_ be ? CalendarDateArithmeticalToISO(_calendar_, _balancedDate_.[[Year]], _balancedDate_.[[Month]], _balancedDate_.[[Day]]). | ||
1. If ISODateWithinLimits(_result_) is *false*, throw a *RangeError* exception. | ||
1. Return _result_. | ||
</emu-alg> | ||
|
@@ -1035,19 +1197,36 @@ contributors: Google, Ecma International | |
No fields larger than _largestUnit_ will be non-zero in the resulting Date Duration Record. | ||
</dd> | ||
</dl> | ||
<p>The algorithm is implementation-defined, but all calendars follow the general steps given here, which is a generalization of the precise algorithm specified in CalendarDateUntil for *"iso8601"*.</p> | ||
<p>All calendars follow the steps given here, which is a generalization of the precise algorithm specified in CalendarDateUntil for *"iso8601"*.</p> | ||
<p>This definition supersedes the definition provided in <emu-xref href="#sec-temporal-nonisodateuntil"></emu-xref>.</p> | ||
<p>It performs the following steps when called:</p> | ||
<emu-alg> | ||
1. Let _sign_ be -CompareISODate(_one_, _two_). | ||
sffc marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
1. If _sign_ = 0, return ZeroDateDuration(). | ||
1. Let _years_ be 0. | ||
1. 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. | ||
1. Constrain _one_ to a real year and month, not taking day into account. This step only matters for lunisolar calendars. | ||
1. If _largestUnit_ is ~year~ or ~month~, then | ||
1. Add (without constraining) as many months as possible to _one_ without surpassing _two_. | ||
1. Constrain _one_ to a real year, month, and day. | ||
1. If _largestUnit_ is ~week~, add as many weeks as possible to _one_ without surpassing _two_. | ||
1. Add as many days as possible to _one_ until it is equal to _two_. | ||
1. Return a Date Duration Record of the number of years, months, weeks, and days added. | ||
1. Let _candidateYears_ be _sign_. | ||
1. Repeat, while NonISODateSurpasses(_calendar_, _sign_, _one_, _two_, _candidateYears_, 0, 0, 0) is *false*, | ||
1. Set _years_ to _candidateYears_. | ||
1. Set _candidateYears_ to _candidateYears_ + _sign_. | ||
1. Let _months_ be 0. | ||
1. If _largestUnit_ is ~year~ or _largestUnit_ is ~month~, then | ||
1. Let _candidateMonths_ be _sign_. | ||
1. Repeat, while NonISODateSurpasses(_calendar_, _sign_, _one_, _two_, _years_, _candidateMonths_, 0, 0) is *false*, | ||
1. Set _months_ to _candidateMonths_. | ||
1. Set _candidateMonths_ to _candidateMonths_ + _sign_. | ||
1. Let _weeks_ be 0. | ||
1. If _largestUnit_ is ~week~, then | ||
1. Let _candidateWeeks_ be _sign_. | ||
1. Repeat, while NonISODateSurpasses(_calendar_, _sign_, _one_, _two_, _years_, _months_, _candidateWeeks_, 0) is *false*, | ||
1. Set _weeks_ to _candidateWeeks_. | ||
1. Set _candidateWeeks_ to _candidateWeeks_ + sign. | ||
1. Let _days_ be 0. | ||
1. Let _candidateDays_ be _sign_. | ||
1. Repeat, while NonISODateSurpasses(_calendar_, _sign_, _one_, _two_, _years_, _months_, _weeks_, _candidateDays_) is *false*, | ||
1. Set _days_ to _candidateDays_. | ||
1. Set _candidateDays_ to _candidateDays_ + _sign_. | ||
1. Return ! CreateDateDurationRecord(_years_, _months_, _weeks_, _days_). | ||
</emu-alg> | ||
</emu-clause> | ||
|
||
|
@@ -1087,8 +1266,13 @@ contributors: Google, Ecma International | |
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_. | ||
1. Let _daysInMonth_ be CalendarDaysInMonth(_calendar_, _arithmeticYear_, _ordinalMonth_). | ||
1. If _daysInMonth_ ≤ _day_, then | ||
1. If _overflow_ is ~reject~, throw a *RangeError* exception. | ||
1. Let _regulatedDay_ be _daysInMonth_. | ||
1. Else, | ||
1. Let _regulatedDay_ be _day_. | ||
1. Return ? CalendarDateArithmeticalToISO(_calendar_, _arithmeticYear_, _ordinalMonth_, _regulatedDay_). | ||
</emu-alg> | ||
</emu-clause> | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nothing to do with the substance of the PR, but I'm surprised this doesn't get linked automatically with
--load-biblio @tc39/ecma262-biblio
!