Skip to content

Commit 4c2f718

Browse files
committed
Rewrite NonISODateUntil to depend on more specific calendar-dependent operations
1 parent e349341 commit 4c2f718

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
@@ -919,6 +919,266 @@ contributors: Google, Ecma International
919919
</emu-alg>
920920
</emu-clause>
921921

922+
<emu-clause id="sup-temporal-integerfrommonthcode" type="implementation-defined abstract operation">
923+
<h1>
924+
IntegerFromMonthCode (
925+
_monthCode_: a String,
926+
): an integer
927+
</h1>
928+
<dl class="header">
929+
<dt>description</dt>
930+
<dd>
931+
It returns the integer number contained in _monthCode_.
932+
</dd>
933+
</dl>
934+
<p>It performs the following steps when called:</p>
935+
<emu-alg>
936+
1. Assert: The length of _monthCode_ is 3 or 4.
937+
1. Let _monthCodeDigits_ be the substring of _monthCode_ from 1 to 3.
938+
1. Return ℝ(StringToNumber(_monthCodeDigits_)).
939+
</emu-alg>
940+
</emu-clause>
941+
942+
<emu-clause id="sup-temporal-monthcodefrominteger" type="implementation-defined abstract operation">
943+
<h1>
944+
MonthCodeFromInteger (
945+
_integer_: an integer,
946+
): a String
947+
</h1>
948+
<dl class="header">
949+
<dt>description</dt>
950+
<dd>
951+
It returns a month code for a non-leap month containing the given integer number.
952+
</dd>
953+
</dl>
954+
<p>It performs the following steps when called:</p>
955+
<emu-alg>
956+
1. Let _numberPart_ be ToZeroPaddedDecimalString(_integer_, 2).
957+
1. Return the string-concatenation of the code unit 0x004D (LATIN CAPITAL LETTER M) and _numberPart_.
958+
</emu-alg>
959+
</emu-clause>
960+
961+
<emu-clause id="sup-temporal-isvalidmonthcodeforcalendarinyear" type="implementation-defined abstract operation">
962+
<h1>
963+
IsValidMonthCodeForCalendarInYear (
964+
_calendar_: a calendar type that is not *"iso8601"*,
965+
_year_: an integer,
966+
_monthCode_: a String,
967+
): an Boolean
968+
</h1>
969+
<dl class="header">
970+
<dt>description</dt>
971+
<dd>
972+
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.
973+
</dd>
974+
</dl>
975+
<p>It performs the following steps when called:</p>
976+
<emu-alg>
977+
Returns an implementation-and-calendar-defined Boolean as described above.
978+
</emu-alg>
979+
</emu-clause>
980+
981+
<emu-clause id="sup-temporal-calendardatecodestoiso" type="implementation-defined abstract operation">
982+
<h1>
983+
CalendarDateCodesToISO (
984+
_calendar_: a calendar type that is not *"iso8601"*,
985+
_year_: an integer,
986+
_monthCode_: a String,
987+
_day_: an integer,
988+
): either a normal completion containing an ISO Date Record or a throw completion
989+
</h1>
990+
<dl class="header">
991+
<dt>description</dt>
992+
<dd>
993+
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.
994+
</dd>
995+
</dl>
996+
<p>It performs the following steps when called:</p>
997+
<emu-alg>
998+
Returns an implementation-and-calendar-defined completion as described above.
999+
</emu-alg>
1000+
</emu-clause>
1001+
1002+
<emu-clause id="sup-temporal-calendardaysinmonth" type="implementation-defined abstract operation">
1003+
<h1>
1004+
CalendarDaysInMonth (
1005+
_calendar_: a calendar type that is not *"iso8601"*,
1006+
_year_: an integer,
1007+
_month_: an integer,
1008+
): an integer
1009+
</h1>
1010+
<dl class="header">
1011+
<dt>description</dt>
1012+
<dd>
1013+
It interprets _year_ and _month_ as arithmetical values in the given _calendar_ and returns the number of days in the corresponding month.
1014+
</dd>
1015+
</dl>
1016+
<p>It performs the following steps when called:</p>
1017+
<emu-alg>
1018+
Returns an implementation-and-calendar-defined integer as described above.
1019+
</emu-alg>
1020+
</emu-clause>
1021+
1022+
<emu-clause id="sup-temporal-calendarmonthsinyear" type="implementation-defined abstract operation">
1023+
<h1>
1024+
CalendarMonthsInYear (
1025+
_calendar_: a calendar type that is not *"iso8601"*,
1026+
_year_: an integer,
1027+
): an integer
1028+
</h1>
1029+
<dl class="header">
1030+
<dt>description</dt>
1031+
<dd>
1032+
It interprets _year_ as arithmetical value in the given _calendar_ and returns the number of months in the corresponding year.
1033+
</dd>
1034+
</dl>
1035+
<p>It performs the following steps when called:</p>
1036+
<emu-alg>
1037+
Returns an implementation-and-calendar-defined integer as described above.
1038+
</emu-alg>
1039+
</emu-clause>
1040+
1041+
<emu-clause id="sup-temporal-regulatenonisoyearmonth" type="implementation-defined abstract operation">
1042+
<h1>
1043+
RegulateNonISOYearMonth (
1044+
_calendar_: a calendar type that is not *"iso8601"*,
1045+
_isoDate_: an ISO Date Record,
1046+
_years_: an integer,
1047+
): a Record with fields [[Year]] (an integer) and [[Month]] (an integer)
1048+
</h1>
1049+
<dl class="header">
1050+
<dt>description</dt>
1051+
<dd>
1052+
Interprets _isoDate_ as a date in _calendar_, adds _years_, and returns the best-match arithmetic _year_ and _month_ according to the calendar.
1053+
</dd>
1054+
</dl>
1055+
<p>It performs the following steps when called:</p>
1056+
<emu-alg>
1057+
1. Let _y1_ be CalendarDateArithmeticYear(_calendar_, _isoDate_).
1058+
1. Let _d1_ be CalendarISOToDate(_calendar_, _isoDate_).
1059+
1. Let _monthCode_ be _d1_.[[MonthCode]].
1060+
1. Let _y2_ be _y1_ + _years_.
1061+
1. If _calendar_ is *"chinese"*, *"dangi"*, or *"hebrew"*, then
1062+
1. If _calendar_ is *"chinese"* or *"dangi"*, then
1063+
1. If IsValidMonthCodeForCalendarInYear(_calendar_, _y2_, _monthCode_) is *false*, then
1064+
1. Set _monthCode_ to MonthCodeFromInteger(IntegerFromMonthCode(_monthCode_)).
1065+
1. Else,
1066+
1. Assert: _calendar_ is *"hebrew"*.
1067+
1. Let _d2_ be CalendarISOToDate(_calendar_, ! CalendarDateCodesToISO(_calendar_, _y2_, *"M01"*, 1)).
1068+
1. If _d1_.[[InLeapYear]] is *true* and _d2_.[[InLeapYear]] is *false*, then
1069+
1. If _monthCode_ is *"M05L"*, then
1070+
1. Set _monthCode_ to *"M06"*.
1071+
1. Else if _d1_.[[InLeapYear]] is *false* and _d2_.[[InLeapYear]] is *true*, then
1072+
1. If _monthCode_ is *"M06"*, then
1073+
1. Set _monthCode_ to *"M05L"*.
1074+
1. Assert: IsValidMonthCodeForCalendarInYear(_calendar_, _y2_, _monthCode_) is *true*.
1075+
1. Let _month_ be CalendarISOToDate(_calendar_, ! CalendarDateCodesToISO(_calendar_, _y2_, _monthCode_, 1)).[[Month]].
1076+
1. Else,
1077+
1. Let _month_ be IntegerFromMonthCode(_monthCode_).
1078+
1. Return the Record { [[Year]]: _y2_, [[Month]]: _month_ }.
1079+
</emu-alg>
1080+
</emu-clause>
1081+
1082+
<emu-clause id="sup-temporal-balancenonisodate" type="implementation-defined abstract operation">
1083+
<h1>
1084+
BalanceNonISODate (
1085+
_calendar_: a calendar type that is not *"iso8601"*,
1086+
_year_: an integer,
1087+
_month_: an integer,
1088+
_day_: an integer,
1089+
): a Record with fields [[Year]] (an integer), [[Month]] (an integer), and [[Day]] (an integer)
1090+
</h1>
1091+
<dl class="header">
1092+
<dt>description</dt>
1093+
<dd>
1094+
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.
1095+
This date may be outside the range given by ISODateTimeWithinLimits.
1096+
</dd>
1097+
</dl>
1098+
<p>It performs the following steps when called:</p>
1099+
<emu-alg>
1100+
1. Let _resolvedYear_ be _year_.
1101+
1. Let _resolvedMonth_ be _month_.
1102+
1. Let _monthsInYear_ be CalendarMonthsInYear(_calendar_, _resolvedYear_).
1103+
1. Repeat, while _resolvedMonth_ &le; 0,
1104+
1. Set _resolvedYear_ to _resolvedYear_ - 1.
1105+
1. Set _monthsInYear_ to CalendarMonthsInYear(_calendar_, _resolvedYear_).
1106+
1. Set _resolvedMonth_ to _resolvedMonth_ + _monthsInYear_.
1107+
1. Repeat, while _resolvedMonth_ &gt; _monthsInYear_,
1108+
1. Set _resolvedMonth_ to _resolvedMonth_ - _monthsInYear_.
1109+
1. Set _resolvedYear_ to _resolvedYear_ + 1.
1110+
1. Set _monthsInYear_ to CalendarMonthsInYear(_calendar_, _resolvedYear_).
1111+
1. Let _resolvedDay_ be _day_.
1112+
1. Let _daysInMonth_ be CalendarDaysInMonth(_calendar_, _resolvedYear_, _resolvedMonth_).
1113+
1. Repeat, while _resolvedDay_ &le; 0,
1114+
1. Set _resolvedMonth_ to _resolvedMonth_ - 1.
1115+
1. If _resolvedMonth_ is 0, then
1116+
1. Set _resolvedYear_ to _resolvedYear_ - 1.
1117+
1. Set _monthsInYear_ to CalendarMonthsInYear(_calendar_, _resolvedYear_).
1118+
1. Set _resolvedMonth_ to _monthsInYear_.
1119+
1. Set _daysInMonth_ to CalendarDaysInMonth(_calendar_, _resolvedYear_, _resolvedMonth_).
1120+
1. Set _resolvedDay_ to _day_ + _daysInMonth_.
1121+
1. Repeat, while _resolvedDay_ &gt; _daysInMonth_,
1122+
1. Set _resolvedDay_ to _resolvedDay_ - _daysInMonth_.
1123+
1. Set _resolvedMonth_ to _resolvedMonth_ + 1.
1124+
1. If _resolvedMonth_ &gt; _monthsInYear_, then
1125+
1. Set _resolvedYear_ to _resolvedYear_ + 1.
1126+
1. Set _monthsInYear_ to CalendarMonthsInYear(_calendar_, _resolvedYear_).
1127+
1. Set _resolvedMonth_ to 1.
1128+
1. Set _daysInMonth_ to CalendarDaysInMonth(_calendar_, _resolvedYear_, _resolvedMonth_).
1129+
1. Return the Record { [[Year]]: _resolvedYear_, [[Month]]: _resolvedMonth_, [[Day]]: _resolvedDay_ }.
1130+
</emu-alg>
1131+
</emu-clause>
1132+
1133+
<emu-clause id="sup-temporal-nonisodatesurpasses" type="implementation-defined abstract operation">
1134+
<h1>
1135+
NonISODateSurpasses (
1136+
_calendar_: a calendar type that is not *"iso8601"*,
1137+
_sign_: -1 or 1,
1138+
_baseDate_: an ISO Date Record,
1139+
_isoDate2_: an ISO Date Record,
1140+
_years_: an integer,
1141+
_months_: an integer,
1142+
_weeks_: an integer,
1143+
_days_: an integer,
1144+
): a Boolean
1145+
</h1>
1146+
<dl class="header">
1147+
<dt>description</dt>
1148+
<dd>
1149+
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_.
1150+
If _weeks_ and _days_ are both zero, then _date1_ need not exist (for example, it could be February 30).
1151+
</dd>
1152+
</dl>
1153+
<p>It performs the following steps when called:</p>
1154+
<emu-alg>
1155+
1. Let _yearMonth_ be RegulateNonISOYearMonth(_calendar_, _baseDate_, _years_).
1156+
1. Let _endOfMonth_ be BalanceNonISODate(_calendar_, _yearMonth_.[[Year]], _yearMonth_.[[Month]] + _months_ + 1, 0).
1157+
1. Let _baseDay_ be CalendarISOToDate(_calendar_, _baseDate_).[[Day]].
1158+
1. If _weeks_ is not 0 or _days_ is not 0, then
1159+
1. If _baseDay_ &lt; _endOfMonth_.[[Day]], then
1160+
1. Let _regulatedDay_ be _baseDay_.
1161+
1. Else,
1162+
1. Let _regulatedDay_ be _endOfMonth_.[[Day]].
1163+
1. Let _balancedDate_ be BalanceNonISODate(_calendar_, _endOfMonth_.[[Year]], _endOfMonth_.[[Month]], _regulatedDay_ + 7 * _weeks_ + _days_).
1164+
1. Let _y1_ be _balancedDate_.[[Year]].
1165+
1. Let _m1_ be _balancedDate_.[[Month]].
1166+
1. Let _d1_ be _balancedDate_.[[Day]].
1167+
1. Else,
1168+
1. Let _y1_ be _endOfMonth_.[[Year]].
1169+
1. Let _m1_ be _endOfMonth_.[[Month]].
1170+
1. Let _d1_ be _baseDay_.
1171+
1. Let _calDate2_ be CalendarISOToDate(_calendar_, _isoDate2_).
1172+
1. If _y1_ ≠ _calDate2_.[[Year]], then
1173+
1. If _sign_ × (_y1_ - _calDate2_.[[Year]]) > 0, return *true*.
1174+
1. Else if _m1_ ≠ _calDate2_.[[Month]], then
1175+
1. If _sign_ × (_m1_ - _calDate2_.[[Month]]) > 0, return *true*.
1176+
1. Else if _d1_ ≠ _calDate2_.[[Day]], then
1177+
1. If _sign_ × (_d1_ - _calDate2_.[[Day]]) > 0, return *true*.
1178+
1. Return *false*.
1179+
</emu-alg>
1180+
</emu-clause>
1181+
9221182
<emu-clause id="sup-temporal-nonisodateuntil" type="implementation-defined abstract operation">
9231183
<h1>
9241184
NonISODateUntil (
@@ -935,19 +1195,35 @@ contributors: Google, Ecma International
9351195
No fields larger than _largestUnit_ will be non-zero in the resulting Date Duration Record.
9361196
</dd>
9371197
</dl>
938-
<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>
9391198
<p>This definition supersedes the definition provided in <emu-xref href="#sec-temporal-nonisodateuntil"></emu-xref>.</p>
9401199
<p>It performs the following steps when called:</p>
9411200
<emu-alg>
1201+
1. Let _sign_ be -CompareISODate(_one_, _two_).
1202+
1. If _sign_ = 0, return ZeroDateDuration().
1203+
1. Let _years_ be 0.
9421204
1. If _largestUnit_ is ~year~, then
943-
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.
944-
1. Constrain _one_ to a real year and month, not taking day into account. This step only matters for lunisolar calendars.
945-
1. If _largestUnit_ is ~year~ or ~month~, then
946-
1. Add (without constraining) as many months as possible to _one_ without surpassing _two_.
947-
1. Constrain _one_ to a real year, month, and day.
948-
1. If _largestUnit_ is ~week~, add as many weeks as possible to _one_ without surpassing _two_.
949-
1. Add as many days as possible to _one_ until it is equal to _two_.
950-
1. Return a Date Duration Record of the number of years, months, weeks, and days added.
1205+
1. Let _candidateYears_ be _sign_.
1206+
1. Repeat, while NonISODateSurpasses(_calendar_, _sign_, _one_, _two_, _candidateYears_, 0, 0, 0) is *false*,
1207+
1. Set _years_ to _candidateYears_.
1208+
1. Set _candidateYears_ to _candidateYears_ + _sign_.
1209+
1. Let _months_ be 0.
1210+
1. If _largestUnit_ is ~year~ or _largestUnit_ is ~month~, then
1211+
1. Let _candidateMonths_ be _sign_.
1212+
1. Repeat, while NonISODateSurpasses(_calendar_, _sign_, _one_, _two_, _years_, _candidateMonths_, 0, 0) is *false*,
1213+
1. Set _months_ to _candidateMonths_.
1214+
1. Set _candidateMonths_ to _candidateMonths_ + _sign_.
1215+
1. Let _weeks_ be 0.
1216+
1. If _largestUnit_ is ~week~, then
1217+
1. Let _candidateWeeks_ be _sign_.
1218+
1. Repeat, while NonISODateSurpasses(_calendar_, _sign_, _one_, _two_, _years_, _months_, _candidateWeeks_, 0) is *false*,
1219+
1. Set _weeks_ to _candidateWeeks_.
1220+
1. Set _candidateWeeks_ to _candidateWeeks_ + sign.
1221+
1. Let _days_ be 0.
1222+
1. Let _candidateDays_ be _sign_.
1223+
1. Repeat, while NonISODateSurpasses(_calendar_, _sign_, _one_, _two_, _years_, _months_, _weeks_, _candidateDays_) is *false*,
1224+
1. Set _days_ to _candidateDays_.
1225+
1. Set _candidateDays_ to _candidateDays_ + _sign_.
1226+
1. Return ! CreateDateDurationRecord(_years_, _months_, _weeks_, _days_).
9511227
</emu-alg>
9521228
</emu-clause>
9531229

0 commit comments

Comments
 (0)