Skip to content

Commit

Permalink
Normative: Call user code on relativeTo only when necessary in RoundD…
Browse files Browse the repository at this point in the history
…uration

relativeTo as a PlainDate is only needed when smallestUnit is year, month,
or week. relativeTo as a ZonedDateTime is used additionally when
smallestUnit is day. However, ToTemporalDate only needs to be called in
the former case. Since ToTemporalDate potentially calls user code,
rearrange some steps to make sure to call it only when necessary.

Closes: #2247
  • Loading branch information
ptomato committed Jul 6, 2022
1 parent 5b38ab4 commit 34e700b
Show file tree
Hide file tree
Showing 2 changed files with 8 additions and 14 deletions.
14 changes: 4 additions & 10 deletions polyfill/lib/ecmascript.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4532,13 +4532,12 @@ export const ES = ObjectAssign({}, ES2020, {
relativeTo = undefined
) => {
const TemporalDuration = GetIntrinsic('%Temporal.Duration%');
let calendar, zdtRelative;
if (relativeTo) {
let calendar;
const zdtRelative = ES.IsTemporalZonedDateTime(relativeTo) ? relativeTo : undefined;
if (unit === 'year' || unit === 'month' || unit === 'week') {
if (!relativeTo) throw new RangeError(`A starting point is required for ${unit}s rounding`);
if (ES.IsTemporalZonedDateTime(relativeTo)) {
zdtRelative = relativeTo;
relativeTo = ES.ToTemporalDate(relativeTo);
} else if (!ES.IsTemporalDate(relativeTo)) {
throw new TypeError('starting point must be PlainDate or ZonedDateTime');
}
calendar = GetSlot(relativeTo, CALENDAR);
}
Expand All @@ -4561,8 +4560,6 @@ export const ES = ObjectAssign({}, ES2020, {
let total;
switch (unit) {
case 'year': {
if (!calendar) throw new RangeError('A starting point is required for years rounding');

// convert months and weeks to days by calculating difference(
// relativeTo + years, relativeTo + { years, months, weeks })
const yearsDuration = new TemporalDuration(years);
Expand Down Expand Up @@ -4602,8 +4599,6 @@ export const ES = ObjectAssign({}, ES2020, {
break;
}
case 'month': {
if (!calendar) throw new RangeError('A starting point is required for months rounding');

// convert weeks to days by calculating difference(relativeTo +
// { years, months }, relativeTo + { years, months, weeks })
const yearsMonths = new TemporalDuration(years, months);
Expand Down Expand Up @@ -4636,7 +4631,6 @@ export const ES = ObjectAssign({}, ES2020, {
break;
}
case 'week': {
if (!calendar) throw new RangeError('A starting point is required for weeks rounding');
// Weeks may be different lengths of days depending on the calendar,
// convert days to weeks in a loop as described above under 'years'.
const sign = MathSign(days);
Expand Down
8 changes: 4 additions & 4 deletions spec/duration.html
Original file line number Diff line number Diff line change
Expand Up @@ -1560,12 +1560,12 @@ <h1>
</dl>
<emu-alg>
1. If _relativeTo_ is not present, set _relativeTo_ to *undefined*.
1. If _unit_ is *"year"*, *"month"*, or *"week"*, and _relativeTo_ is *undefined*, then
1. Throw a *RangeError* exception.
1. Let _zonedRelativeTo_ be *undefined*.
1. If _relativeTo_ is not *undefined*, then
1. If _relativeTo_ has an [[InitializedTemporalZonedDateTime]] internal slot, then
1. Set _zonedRelativeTo_ to _relativeTo_.
1. If _unit_ is one of *"year"*, *"month"*, or *"week"*, then
1. If _relativeTo_ is *undefined*, throw a *RangeError* exception.
1. If _relativeTo_ has an [[InitializedTemporalZonedDateTime]] internal slot, then
1. Set _zonedRelativeTo_ to _relativeTo_.
1. Set _relativeTo_ to ? ToTemporalDate(_relativeTo_).
1. Else,
1. Assert: _relativeTo_ has an [[InitializedTemporalDate]] internal slot.
Expand Down

0 comments on commit 34e700b

Please sign in to comment.