Skip to content

Commit ca08cb5

Browse files
committed
Rewrite NonISODateUntil to depend on more specific calendar-dependent operations
1 parent e548740 commit ca08cb5

File tree

1 file changed

+285
-9
lines changed

1 file changed

+285
-9
lines changed

spec.emu

Lines changed: 285 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -837,6 +837,266 @@ contributors: Google, Ecma International
837837
</emu-alg>
838838
</emu-clause>
839839

840+
<emu-clause id="sup-temporal-integerfrommonthcode" type="implementation-defined abstract operation">
841+
<h1>
842+
IntegerFromMonthCode (
843+
_monthCode_: a String,
844+
): an integer
845+
</h1>
846+
<dl class="header">
847+
<dt>description</dt>
848+
<dd>
849+
It returns the integer number contained in _monthCode_.
850+
</dd>
851+
</dl>
852+
<p>It performs the following steps when called:</p>
853+
<emu-alg>
854+
1. Assert: The length of _monthCode_ is 3 or 4.
855+
1. Let _monthCodeDigits_ be the substring of _monthCode_ from 1 to 3.
856+
1. Return ℝ(StringToNumber(_monthCodeDigits_)).
857+
</emu-alg>
858+
</emu-clause>
859+
860+
<emu-clause id="sup-temporal-monthcodefrominteger" type="implementation-defined abstract operation">
861+
<h1>
862+
MonthCodeFromInteger (
863+
_integer_: an integer,
864+
): a String
865+
</h1>
866+
<dl class="header">
867+
<dt>description</dt>
868+
<dd>
869+
It returns a month code for a non-leap month containing the given integer number.
870+
</dd>
871+
</dl>
872+
<p>It performs the following steps when called:</p>
873+
<emu-alg>
874+
1. Let _numberPart_ be ToZeroPaddedDecimalString(_integer_, 2).
875+
1. Return the string-concatenation of the code unit 0x004D (LATIN CAPITAL LETTER M) and _numberPart_.
876+
</emu-alg>
877+
</emu-clause>
878+
879+
<emu-clause id="sup-temporal-isvalidmonthcodeforcalendarinyear" type="implementation-defined abstract operation">
880+
<h1>
881+
IsValidMonthCodeForCalendarInYear (
882+
_calendar_: a calendar type that is not *"iso8601"*,
883+
_year_: an integer,
884+
_monthCode_: a String,
885+
): an Boolean
886+
</h1>
887+
<dl class="header">
888+
<dt>description</dt>
889+
<dd>
890+
It interprets _year_ as arithmetical value in the given _calendar_ and returns *true* if there is a month with the given _monthCode_ in that year or *false* otherwise.
891+
</dd>
892+
</dl>
893+
<p>It performs the following steps when called:</p>
894+
<emu-alg>
895+
Returns an implementation-and-calendar-defined Boolean as described above.
896+
</emu-alg>
897+
</emu-clause>
898+
899+
<emu-clause id="sup-temporal-calendardatecodestoiso" type="implementation-defined abstract operation">
900+
<h1>
901+
CalendarDateCodesToISO (
902+
_calendar_: a calendar type that is not *"iso8601"*,
903+
_year_: an integer,
904+
_monthCode_: a String,
905+
_day_: an integer,
906+
): either a normal completion containing an ISO Date Record or a throw completion
907+
</h1>
908+
<dl class="header">
909+
<dt>description</dt>
910+
<dd>
911+
It returns an ISO Date Record that, when converted to a Calendar Date Record with _calendar_ (for example, with CalendarISOToDate), contains the given _year_, _monthCode_, and _day_ values in its [[Year]], [[MonthCode]], and [[Day]] fields. If this is not possible, a RangeError is thrown.
912+
</dd>
913+
</dl>
914+
<p>It performs the following steps when called:</p>
915+
<emu-alg>
916+
Returns an implementation-and-calendar-defined completion as described above.
917+
</emu-alg>
918+
</emu-clause>
919+
920+
<emu-clause id="sup-temporal-calendardaysinmonth" type="implementation-defined abstract operation">
921+
<h1>
922+
CalendarDaysInMonth (
923+
_calendar_: a calendar type that is not *"iso8601"*,
924+
_year_: an integer,
925+
_month_: an integer,
926+
): an integer
927+
</h1>
928+
<dl class="header">
929+
<dt>description</dt>
930+
<dd>
931+
It interprets _year_ and _month_ as arithmetical values in the given _calendar_ and returns the number of days in the corresponding month.
932+
</dd>
933+
</dl>
934+
<p>It performs the following steps when called:</p>
935+
<emu-alg>
936+
Returns an implementation-and-calendar-defined integer as described above.
937+
</emu-alg>
938+
</emu-clause>
939+
940+
<emu-clause id="sup-temporal-calendarmonthsinyear" type="implementation-defined abstract operation">
941+
<h1>
942+
CalendarMonthsInYear (
943+
_calendar_: a calendar type that is not *"iso8601"*,
944+
_year_: an integer,
945+
): an integer
946+
</h1>
947+
<dl class="header">
948+
<dt>description</dt>
949+
<dd>
950+
It interprets _year_ as arithmetical value in the given _calendar_ and returns the number of months in the corresponding year.
951+
</dd>
952+
</dl>
953+
<p>It performs the following steps when called:</p>
954+
<emu-alg>
955+
Returns an implementation-and-calendar-defined integer as described above.
956+
</emu-alg>
957+
</emu-clause>
958+
959+
<emu-clause id="sup-temporal-regulatenonisoyearmonth" type="implementation-defined abstract operation">
960+
<h1>
961+
RegulateNonISOYearMonth (
962+
_calendar_: a calendar type that is not *"iso8601"*,
963+
_isoDate_: an ISO Date Record,
964+
_years_: an integer,
965+
): a Record with fields [[Year]] (an integer) and [[Month]] (an integer)
966+
</h1>
967+
<dl class="header">
968+
<dt>description</dt>
969+
<dd>
970+
Interprets _isoDate_ as a date in _calendar_, adds _years_, and returns the best-match arithmetic _year_ and _month_ according to the calendar.
971+
</dd>
972+
</dl>
973+
<p>It performs the following steps when called:</p>
974+
<emu-alg>
975+
1. Let _y1_ be CalendarDateArithmeticYear(_calendar_, _isoDate_).
976+
1. Let _d1_ be CalendarISOToDate(_calendar_, _isoDate_).
977+
1. Let _monthCode_ be _d1_.[[MonthCode]].
978+
1. Let _y2_ be _y1_ + _years_.
979+
1. If _calendar_ is *"chinese"*, *"dangi"*, or *"hebrew"*, then
980+
1. If _calendar_ is *"chinese"* or *"dangi"*, then
981+
1. If IsValidMonthCodeForCalendarInYear(_calendar_, _y2_, _monthCode_) is *false*, then
982+
1. Set _monthCode_ to MonthCodeFromInteger(IntegerFromMonthCode(_monthCode_)).
983+
1. Else,
984+
1. Assert: _calendar_ is *"hebrew"*.
985+
1. Let _d2_ be CalendarISOToDate(_calendar_, ! CalendarDateCodesToISO(_calendar_, _y2_, *"M01"*, 1)).
986+
1. If _d1_.[[InLeapYear]] is *true* and _d2_.[[InLeapYear]] is *false*, then
987+
1. If _monthCode_ is *"M05L"*, then
988+
1. Set _monthCode_ to *"M06"*.
989+
1. Else if _d1_.[[InLeapYear]] is *false* and _d2_.[[InLeapYear]] is *true*, then
990+
1. If _monthCode_ is *"M06"*, then
991+
1. Set _monthCode_ to *"M05L"*.
992+
1. Assert: IsValidMonthCodeForCalendarInYear(_calendar_, _y2_, _monthCode_) is *true*.
993+
1. Let _month_ be CalendarISOToDate(_calendar_, ! CalendarDateCodesToISO(_calendar_, _y2_, _monthCode_, 1)).[[Month]].
994+
1. Else,
995+
1. Let _month_ be IntegerFromMonthCode(_monthCode_).
996+
1. Return the Record { [[Year]]: _y2_, [[Month]]: _month_ }.
997+
</emu-alg>
998+
</emu-clause>
999+
1000+
<emu-clause id="sup-temporal-balancenonisodate" type="implementation-defined abstract operation">
1001+
<h1>
1002+
BalanceNonISODate (
1003+
_calendar_: a calendar type that is not *"iso8601"*,
1004+
_year_: an integer,
1005+
_month_: an integer,
1006+
_day_: an integer,
1007+
): a Record with fields [[Year]] (an integer), [[Month]] (an integer), and [[Day]] (an integer)
1008+
</h1>
1009+
<dl class="header">
1010+
<dt>description</dt>
1011+
<dd>
1012+
It interprets the given _year_ and potentially out-of-range _month_ and _day_ as arithmetical values in the given _calendar_ and returns in-range values by overflowing out-of-range _month_ or _day_ values into the next-highest unit.
1013+
This date may be outside the range given by ISODateTimeWithinLimits.
1014+
</dd>
1015+
</dl>
1016+
<p>It performs the following steps when called:</p>
1017+
<emu-alg>
1018+
1. Let _resolvedYear_ be _year_.
1019+
1. Let _resolvedMonth_ be _month_.
1020+
1. Let _monthsInYear_ be CalendarMonthsInYear(_calendar_, _resolvedYear_).
1021+
1. Repeat, while _resolvedMonth_ &le; 0,
1022+
1. Set _resolvedYear_ to _resolvedYear_ - 1.
1023+
1. Set _monthsInYear_ to CalendarMonthsInYear(_calendar_, _resolvedYear_).
1024+
1. Set _resolvedMonth_ to _resolvedMonth_ + _monthsInYear_.
1025+
1. Repeat, while _resolvedMonth_ &gt; _monthsInYear_,
1026+
1. Set _resolvedMonth_ to _resolvedMonth_ - _monthsInYear_.
1027+
1. Set _resolvedYear_ to _resolvedYear_ + 1.
1028+
1. Set _monthsInYear_ to CalendarMonthsInYear(_calendar_, _resolvedYear_).
1029+
1. Let _resolvedDay_ be _day_.
1030+
1. Let _daysInMonth_ be CalendarDaysInMonth(_calendar_, _resolvedYear_, _resolvedMonth_).
1031+
1. Repeat, while _resolvedDay_ &le; 0,
1032+
1. Set _resolvedMonth_ to _resolvedMonth_ - 1.
1033+
1. If _resolvedMonth_ is 0, then
1034+
1. Set _resolvedYear_ to _resolvedYear_ - 1.
1035+
1. Set _monthsInYear_ to CalendarMonthsInYear(_calendar_, _resolvedYear_).
1036+
1. Set _resolvedMonth_ to _monthsInYear_.
1037+
1. Set _daysInMonth_ to CalendarDaysInMonth(_calendar_, _resolvedYear_, _resolvedMonth_).
1038+
1. Set _resolvedDay_ to _day_ + _daysInMonth_.
1039+
1. Repeat, while _resolvedDay_ &gt; _daysInMonth_,
1040+
1. Set _resolvedDay_ to _resolvedDay_ - _daysInMonth_.
1041+
1. Set _resolvedMonth_ to _resolvedMonth_ + 1.
1042+
1. If _resolvedMonth_ &gt; _monthsInYear_, then
1043+
1. Set _resolvedYear_ to _resolvedYear_ + 1.
1044+
1. Set _monthsInYear_ to CalendarMonthsInYear(_calendar_, _resolvedYear_).
1045+
1. Set _resolvedMonth_ to 1.
1046+
1. Set _daysInMonth_ to CalendarDaysInMonth(_calendar_, _resolvedYear_, _resolvedMonth_).
1047+
1. Return the Record { [[Year]]: _resolvedYear_, [[Month]]: _resolvedMonth_, [[Day]]: _resolvedDay_ }.
1048+
</emu-alg>
1049+
</emu-clause>
1050+
1051+
<emu-clause id="sup-temporal-nonisodatesurpasses" type="implementation-defined abstract operation">
1052+
<h1>
1053+
NonISODateSurpasses (
1054+
_calendar_: a calendar type that is not *"iso8601"*,
1055+
_sign_: -1 or 1,
1056+
_baseDate_: an ISO Date Record,
1057+
_isoDate2_: an ISO Date Record,
1058+
_years_: an integer,
1059+
_months_: an integer,
1060+
_weeks_: an integer,
1061+
_days_: an integer,
1062+
): a Boolean
1063+
</h1>
1064+
<dl class="header">
1065+
<dt>description</dt>
1066+
<dd>
1067+
The return value indicates whether the date _date1_, the result of adding the duration denoted by _years_, _months_, _weeks_, and _days_ to _baseDate_ in the calendar system denoted by _calendar_, surpasses _isoDate2_ in the direction denoted by _sign_.
1068+
If _weeks_ and _days_ are both zero, then _date1_ need not exist (for example, it could be February 30).
1069+
</dd>
1070+
</dl>
1071+
<p>It performs the following steps when called:</p>
1072+
<emu-alg>
1073+
1. Let _yearMonth_ be RegulateNonISOYearMonth(_calendar_, _baseDate_, _years_).
1074+
1. Let _endOfMonth_ be BalanceNonISODate(_calendar_, _yearMonth_.[[Year]], _yearMonth_.[[Month]] + _months_ + 1, 0).
1075+
1. Let _baseDay_ be CalendarISOToDate(_calendar_, _baseDate_).[[Day]].
1076+
1. If _weeks_ is not 0 or _days_ is not 0, then
1077+
1. If _baseDay_ &lt; _endOfMonth_.[[Day]], then
1078+
1. Let _regulatedDay_ be _baseDay_.
1079+
1. Else,
1080+
1. Let _regulatedDay_ be _endOfMonth_.[[Day]].
1081+
1. Let _balancedDate_ be BalanceNonISODate(_calendar_, _endOfMonth_.[[Year]], _endOfMonth_.[[Month]], _regulatedDay_ + 7 * _weeks_ + _days_).
1082+
1. Let _y1_ be _balancedDate_.[[Year]].
1083+
1. Let _m1_ be _balancedDate_.[[Month]].
1084+
1. Let _d1_ be _balancedDate_.[[Day]].
1085+
1. Else,
1086+
1. Let _y1_ be _endOfMonth_.[[Year]].
1087+
1. Let _m1_ be _endOfMonth_.[[Month]].
1088+
1. Let _d1_ be _baseDay_.
1089+
1. Let _calDate2_ be CalendarISOToDate(_calendar_, _isoDate2_).
1090+
1. If _y1_ ≠ _calDate2_.[[Year]], then
1091+
1. If _sign_ × (_y1_ - _calDate2_.[[Year]]) > 0, return *true*.
1092+
1. Else if _m1_ ≠ _calDate2_.[[Month]], then
1093+
1. If _sign_ × (_m1_ - _calDate2_.[[Month]]) > 0, return *true*.
1094+
1. Else if _d1_ ≠ _calDate2_.[[Day]], then
1095+
1. If _sign_ × (_d1_ - _calDate2_.[[Day]]) > 0, return *true*.
1096+
1. Return *false*.
1097+
</emu-alg>
1098+
</emu-clause>
1099+
8401100
<emu-clause id="sup-temporal-nonisodateuntil" type="implementation-defined abstract operation">
8411101
<h1>
8421102
NonISODateUntil (
@@ -853,19 +1113,35 @@ contributors: Google, Ecma International
8531113
No fields larger than _largestUnit_ will be non-zero in the resulting Date Duration Record.
8541114
</dd>
8551115
</dl>
856-
<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>
8571116
<p>This definition supersedes the definition provided in <emu-xref href="#sec-temporal-nonisodateuntil"></emu-xref>.</p>
8581117
<p>It performs the following steps when called:</p>
8591118
<emu-alg>
1119+
1. Let _sign_ be -CompareISODate(_one_, _two_).
1120+
1. If _sign_ = 0, return ZeroDateDuration().
1121+
1. Let _years_ be 0.
8601122
1. If _largestUnit_ is ~year~, then
861-
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.
862-
1. Constrain _one_ to a real year and month, not taking day into account. This step only matters for lunisolar calendars.
863-
1. If _largestUnit_ is ~year~ or ~month~, then
864-
1. Add (without constraining) as many months as possible to _one_ without surpassing _two_.
865-
1. Constrain _one_ to a real year, month, and day.
866-
1. If _largestUnit_ is ~week~, add as many weeks as possible to _one_ without surpassing _two_.
867-
1. Add as many days as possible to _one_ until it is equal to _two_.
868-
1. Return a Date Duration Record of the number of years, months, weeks, and days added.
1123+
1. Let _candidateYears_ be _sign_.
1124+
1. Repeat, while NonISODateSurpasses(_calendar_, _sign_, _one_, _two_, _candidateYears_, 0, 0, 0) is *false*,
1125+
1. Set _years_ to _candidateYears_.
1126+
1. Set _candidateYears_ to _candidateYears_ + _sign_.
1127+
1. Let _months_ be 0.
1128+
1. If _largestUnit_ is ~year~ or _largestUnit_ is ~month~, then
1129+
1. Let _candidateMonths_ be _sign_.
1130+
1. Repeat, while NonISODateSurpasses(_calendar_, _sign_, _one_, _two_, _years_, _candidateMonths_, 0, 0) is *false*,
1131+
1. Set _months_ to _candidateMonths_.
1132+
1. Set _candidateMonths_ to _candidateMonths_ + _sign_.
1133+
1. Let _weeks_ be 0.
1134+
1. If _largestUnit_ is ~week~, then
1135+
1. Let _candidateWeeks_ be _sign_.
1136+
1. Repeat, while NonISODateSurpasses(_calendar_, _sign_, _one_, _two_, _years_, _months_, _candidateWeeks_, 0) is *false*,
1137+
1. Set _weeks_ to _candidateWeeks_.
1138+
1. Set _candidateWeeks_ to _candidateWeeks_ + sign.
1139+
1. Let _days_ be 0.
1140+
1. Let _candidateDays_ be _sign_.
1141+
1. Repeat, while NonISODateSurpasses(_calendar_, _sign_, _one_, _two_, _years_, _months_, _weeks_, _candidateDays_) is *false*,
1142+
1. Set _days_ to _candidateDays_.
1143+
1. Set _candidateDays_ to _candidateDays_ + _sign_.
1144+
1. Return ! CreateDateDurationRecord(_years_, _months_, _weeks_, _days_).
8691145
</emu-alg>
8701146
</emu-clause>
8711147

0 commit comments

Comments
 (0)