diff --git a/polyfill/lib/calendar.mjs b/polyfill/lib/calendar.mjs
index 22aff9d97..b9886c535 100644
--- a/polyfill/lib/calendar.mjs
+++ b/polyfill/lib/calendar.mjs
@@ -131,7 +131,19 @@ function calendarDateWeekOfYear(id, isoDate) {
return { week: woy, year: yow };
}
-function ISODateSurpasses(sign, y1, m1, d1, isoDate2) {
+function ISODateSurpasses(sign, baseDate, isoDate2, years, months, weeks, days) {
+ const yearMonth = ES.BalanceISOYearMonth(baseDate.year + years, baseDate.month + months);
+ let y1 = yearMonth.year;
+ let m1 = yearMonth.month;
+ let d1 = baseDate.day;
+ if (weeks !== 0 || days !== 0) {
+ const regulatedDate = ES.RegulateISODate(y1, m1, d1, 'constrain');
+ ({
+ year: y1,
+ month: m1,
+ day: d1
+ } = ES.BalanceISODate(regulatedDate.year, regulatedDate.month, regulatedDate.day + 7 * weeks + days));
+ }
if (y1 !== isoDate2.year) {
if (sign * (y1 - isoDate2.year) > 0) return true;
} else if (m1 !== isoDate2.month) {
@@ -192,25 +204,22 @@ impl['iso8601'] = {
let years = 0;
let months = 0;
- let intermediate;
if (largestUnit === 'year' || largestUnit === 'month') {
// We can skip right to the neighbourhood of the correct number of years,
// it'll be at least one less than two.year - one.year (unless it's zero)
let candidateYears = two.year - one.year;
if (candidateYears !== 0) candidateYears -= sign;
// loops at most twice
- while (!ISODateSurpasses(sign, one.year + candidateYears, one.month, one.day, two)) {
+ while (!ISODateSurpasses(sign, one, two, candidateYears, 0, 0, 0)) {
years = candidateYears;
candidateYears += sign;
}
let candidateMonths = sign;
- intermediate = ES.BalanceISOYearMonth(one.year + years, one.month + candidateMonths);
// loops at most 12 times
- while (!ISODateSurpasses(sign, intermediate.year, intermediate.month, one.day, two)) {
+ while (!ISODateSurpasses(sign, one, two, years, candidateMonths, 0, 0)) {
months = candidateMonths;
candidateMonths += sign;
- intermediate = ES.BalanceISOYearMonth(intermediate.year, intermediate.month + sign);
}
if (largestUnit === 'month') {
@@ -219,7 +228,7 @@ impl['iso8601'] = {
}
}
- intermediate = ES.BalanceISOYearMonth(one.year + years, one.month + months);
+ const intermediate = ES.BalanceISOYearMonth(one.year + years, one.month + months);
const constrained = ES.ConstrainISODate(intermediate.year, intermediate.month, one.day);
let weeks = 0;
diff --git a/spec/calendar.html b/spec/calendar.html
index e36bea1dc..f5e61a30c 100644
--- a/spec/calendar.html
+++ b/spec/calendar.html
@@ -563,34 +563,26 @@
1. Let _years_ be 0.
1. If _largestUnit_ is ~year~, then
1. Let _candidateYears_ be _sign_.
- 1. Repeat, while ISODateSurpasses(_sign_, _one_.[[Year]] + _candidateYears_, _one_.[[Month]], _one_.[[Day]], _two_) is *false*,
+ 1. Repeat, while ISODateSurpasses(_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. Let _intermediate_ be BalanceISOYearMonth(_one_.[[Year]] + _years_, _one_.[[Month]] + _candidateMonths_).
- 1. Repeat, while ISODateSurpasses(_sign_, _intermediate_.[[Year]], _intermediate_.[[Month]], _one_.[[Day]], _two_) is *false*,
+ 1. Repeat, while ISODateSurpasses(_sign_, _one_, _two_, _years_, _candidateMonths_, 0, 0) is *false*,
1. Set _months_ to _candidateMonths_.
1. Set _candidateMonths_ to _candidateMonths_ + _sign_.
- 1. Set _intermediate_ to BalanceISOYearMonth(_intermediate_.[[Year]], _intermediate_.[[Month]] + _sign_).
- 1. Set _intermediate_ to BalanceISOYearMonth(_one_.[[Year]] + _years_, _one_.[[Month]] + _months_).
- 1. Let _constrained_ be ! RegulateISODate(_intermediate_.[[Year]], _intermediate_.[[Month]], _one_.[[Day]], ~constrain~).
1. Let _weeks_ be 0.
1. If _largestUnit_ is ~week~, then
1. Let _candidateWeeks_ be _sign_.
- 1. Set _intermediate_ to BalanceISODate(_constrained_.[[Year]], _constrained_.[[Month]], _constrained_.[[Day]] + 7 × _candidateWeeks_).
- 1. Repeat, while ISODateSurpasses(_sign_, _intermediate_.[[Year]], _intermediate_.[[Month]], _intermediate_.[[Day]], _two_) is *false*,
+ 1. Repeat, while ISODateSurpasses(_sign_, _one_, _two_, _years_, _months_, _candidateWeeks_, 0) is *false*,
1. Set _weeks_ to _candidateWeeks_.
1. Set _candidateWeeks_ to _candidateWeeks_ + sign.
- 1. Set _intermediate_ to BalanceISODate(_intermediate_.[[Year]], _intermediate_.[[Month]], _intermediate_.[[Day]] + 7 × _sign_).
1. Let _days_ be 0.
1. Let _candidateDays_ be _sign_.
- 1. Set _intermediate_ to BalanceISODate(_constrained_.[[Year]], _constrained_.[[Month]], _constrained_.[[Day]] + 7 × _weeks_ + _candidateDays_).
- 1. Repeat, while ISODateSurpasses(_sign_, _intermediate_.[[Year]], _intermediate_.[[Month]], _intermediate_.[[Day]], _two_) is *false*,
+ 1. Repeat, while ISODateSurpasses(_sign_, _one_, _two_, _years_, _months_, _weeks_, _candidateDays_) is *false*,
1. Set _days_ to _candidateDays_.
1. Set _candidateDays_ to _candidateDays_ + _sign_.
- 1. Set _intermediate_ to BalanceISODate(_intermediate_.[[Year]], _intermediate_.[[Month]], _intermediate_.[[Day]] + _sign_).
1. Return ! CreateDateDurationRecord(_years_, _months_, _weeks_, _days_).
1. Return NonISODateUntil(_calendar_, _one_, _two_, _largestUnit_).
diff --git a/spec/plaindate.html b/spec/plaindate.html
index 84122d475..123d2376f 100644
--- a/spec/plaindate.html
+++ b/spec/plaindate.html
@@ -694,21 +694,34 @@
ISODateSurpasses (
_sign_: -1 or 1,
- _y1_: an integer,
- _m1_: an integer,
- _d1_: an integer,
+ _baseDate_: an ISO Date Record,
_isoDate2_: an ISO Date Record,
+ _years_: an integer,
+ _months_: an integer,
+ _weeks_: an integer,
+ _days_: an integer,
): a Boolean
+ 1. Let _yearMonth_ be BalanceISOYearMonth(_baseDate_.[[Year]] + _years_, _baseDate_.[[Month]] + _months_).
+ 1. If _weeks_ is not 0 or _days_ is not 0, then
+ 1. Let _regulatedDate_ be ! RegulateISODate(_yearMonth_.[[Year]], _yearMonth_.[[Month]], _baseDate_.[[Day]], ~constrain~).
+ 1. Let _balancedDate_ be BalanceISODate(_regulatedDate_.[[Year]], _regulatedDate_.[[Month]], _regulatedDate_.[[Day]] + 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 _yearMonth_.[[Year]].
+ 1. Let _m1_ be _yearMonth_.[[Month]].
+ 1. Let _d1_ be _baseDate_.[[Day]].
1. If _y1_ ≠ _isoDate2_.[[Year]], then
1. If _sign_ × (_y1_ - _isoDate2_.[[Year]]) > 0, return *true*.
1. Else if _m1_ ≠ _isoDate2_.[[Month]], then