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

description
- The return value indicates whether the date denoted by _y1_, _m1_, _d1_ surpasses that denoted by _isoDate2_ in the direction denoted by _sign_. - The former date does not have to exist. + The return value indicates whether the date _isoDate1_, the result of adding the duration denoted by _years_, _months_, _weeks_, and _days_ to _baseDate_, surpasses _isoDate2_ in the direction denoted by _sign_. + If _weeks_ and _days_ are both zero, then _isoDate1_ need not exist (for example, it could be February 30). Note that this operation is specific to date difference calculations and is not the same as CompareISODate.
+ 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