From c60c39d8dd439c0b86252202f0438d152b7adc5b Mon Sep 17 00:00:00 2001 From: Philip Chimento Date: Tue, 7 Mar 2023 14:31:47 -0800 Subject: [PATCH] Normative: Separate zoned and plain operations in RoundDuration This converts a ZonedDateTime relativeTo into a PlainDateTime relativeTo only when necessary, only after potentially throwing other errors, and only once. Previously, it could be converted up to a few separate times in each operation, such as UnbalanceDurationRelative, RoundDuration, and BalanceDurationRelative. Since the conversion is user-visible, we don't want to perform it when not necessary or perform it more times than necessary. Closes: #2247 Closes: #2529 --- polyfill/lib/duration.mjs | 69 ++++++--- polyfill/lib/ecmascript.mjs | 274 +++++++++++++++++++++++------------ polyfill/test/ecmascript.mjs | 90 ++++++++++++ spec/abstractops.html | 23 +-- spec/duration.html | 229 +++++++++++++++-------------- spec/zoneddatetime.html | 12 +- 6 files changed, 467 insertions(+), 230 deletions(-) diff --git a/polyfill/lib/duration.mjs b/polyfill/lib/duration.mjs index fdf87550e7..a30de1124f 100644 --- a/polyfill/lib/duration.mjs +++ b/polyfill/lib/duration.mjs @@ -244,7 +244,7 @@ export class Duration { } let largestUnit = ES.GetTemporalUnit(roundTo, 'largestUnit', 'datetime', undefined, ['auto']); - let relativeTo = ES.ToRelativeTemporalObject(roundTo); + let { plainRelativeTo, zonedRelativeTo } = ES.ToRelativeTemporalObject(roundTo); const roundingIncrement = ES.ToTemporalRoundingIncrement(roundTo); const roundingMode = ES.ToTemporalRoundingMode(roundTo, 'halfExpand'); let smallestUnit = ES.GetTemporalUnit(roundTo, 'smallestUnit', 'datetime', undefined); @@ -284,7 +284,7 @@ export class Duration { const calendarUnitsPresent = years !== 0 || months !== 0 || weeks !== 0; const timeUnitsOverflowWillOccur = minutes >= 60 || seconds >= 60 || milliseconds >= 1000 || microseconds >= 1000 || nanoseconds >= 1000; - const hoursToDaysConversionMayOccur = (days !== 0 && ES.IsTemporalZonedDateTime(relativeTo)) || hours >= 24; + const hoursToDaysConversionMayOccur = (days !== 0 && zonedRelativeTo) || hours >= 24; if ( roundingGranularityIsNoop && !balancingRequested && @@ -295,13 +295,27 @@ export class Duration { return new Duration(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds); } + const plainRelativeToWillBeUsed = + smallestUnit === 'year' || + smallestUnit === 'month' || + smallestUnit === 'week' || + years !== 0 || + months !== 0 || + weeks !== 0 || + days !== 0; + if (zonedRelativeTo && plainRelativeToWillBeUsed) { + // Convert a ZonedDateTime relativeTo to PlainDate only if needed in one + // of the operations below, because the conversion is user visible + plainRelativeTo = ES.ToTemporalDate(zonedRelativeTo); + } + ({ years, months, weeks, days } = ES.UnbalanceDateDurationRelative( years, months, weeks, days, largestUnit, - relativeTo + plainRelativeTo )); ({ years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = ES.RoundDuration( @@ -318,9 +332,10 @@ export class Duration { roundingIncrement, smallestUnit, roundingMode, - relativeTo + plainRelativeTo, + zonedRelativeTo )); - if (ES.IsTemporalZonedDateTime(relativeTo)) { + if (zonedRelativeTo) { ({ years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = ES.AdjustRoundedDurationDays( years, @@ -336,7 +351,7 @@ export class Duration { roundingIncrement, smallestUnit, roundingMode, - relativeTo + zonedRelativeTo )); ({ days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = ES.BalanceTimeDurationRelative( days, @@ -347,7 +362,7 @@ export class Duration { microseconds, nanoseconds, largestUnit, - relativeTo + zonedRelativeTo )); } else { ({ days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = ES.BalanceTimeDuration( @@ -367,7 +382,7 @@ export class Duration { weeks, days, largestUnit, - relativeTo + plainRelativeTo )); return new Duration(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds); @@ -393,15 +408,30 @@ export class Duration { } else { totalOf = ES.GetOptionsObject(totalOf); } - const relativeTo = ES.ToRelativeTemporalObject(totalOf); + let { plainRelativeTo, zonedRelativeTo } = ES.ToRelativeTemporalObject(totalOf); const unit = ES.GetTemporalUnit(totalOf, 'unit', 'datetime', ES.REQUIRED); + const plainRelativeToWillBeUsed = + unit === 'year' || unit === 'month' || unit === 'week' || years !== 0 || months !== 0 || weeks !== 0; + if (zonedRelativeTo !== undefined && plainRelativeToWillBeUsed) { + // Convert a ZonedDateTime relativeTo to PlainDate only if needed in one + // of the operations below, because the conversion is user visible + plainRelativeTo = ES.ToTemporalDate(zonedRelativeTo); + } + // Convert larger units down to days - ({ years, months, weeks, days } = ES.UnbalanceDateDurationRelative(years, months, weeks, days, unit, relativeTo)); + ({ years, months, weeks, days } = ES.UnbalanceDateDurationRelative( + years, + months, + weeks, + days, + unit, + plainRelativeTo + )); // If the unit we're totalling is smaller than `days`, convert days down to that unit. let balanceResult; - if (ES.IsTemporalZonedDateTime(relativeTo)) { - const intermediate = ES.MoveRelativeZonedDateTime(relativeTo, years, months, weeks, 0); + if (zonedRelativeTo) { + const intermediate = ES.MoveRelativeZonedDateTime(zonedRelativeTo, years, months, weeks, 0); balanceResult = ES.BalancePossiblyInfiniteTimeDurationRelative( days, hours, @@ -446,7 +476,8 @@ export class Duration { 1, unit, 'trunc', - relativeTo + plainRelativeTo, + zonedRelativeTo ); return total; } @@ -548,7 +579,7 @@ export class Duration { one = ES.ToTemporalDuration(one); two = ES.ToTemporalDuration(two); options = ES.GetOptionsObject(options); - let relativeTo = ES.ToRelativeTemporalObject(options); + let { plainRelativeTo, zonedRelativeTo } = ES.ToRelativeTemporalObject(options); const y1 = GetSlot(one, YEARS); const mon1 = GetSlot(one, MONTHS); const w1 = GetSlot(one, WEEKS); @@ -569,12 +600,12 @@ export class Duration { const ms2 = GetSlot(two, MILLISECONDS); const µs2 = GetSlot(two, MICROSECONDS); let ns2 = GetSlot(two, NANOSECONDS); - const shift1 = ES.CalculateOffsetShift(relativeTo, y1, mon1, w1, d1); - const shift2 = ES.CalculateOffsetShift(relativeTo, y2, mon2, w2, d2); + const shift1 = ES.CalculateOffsetShift(zonedRelativeTo, y1, mon1, w1, d1); + const shift2 = ES.CalculateOffsetShift(zonedRelativeTo, y2, mon2, w2, d2); if (y1 !== 0 || y2 !== 0 || mon1 !== 0 || mon2 !== 0 || w1 !== 0 || w2 !== 0) { - if (ES.IsTemporalZonedDateTime(relativeTo)) relativeTo = ES.ToTemporalDate(relativeTo); - ({ days: d1 } = ES.UnbalanceDateDurationRelative(y1, mon1, w1, d1, 'day', relativeTo)); - ({ days: d2 } = ES.UnbalanceDateDurationRelative(y2, mon2, w2, d2, 'day', relativeTo)); + if (zonedRelativeTo) plainRelativeTo = ES.ToTemporalDate(zonedRelativeTo); + ({ days: d1 } = ES.UnbalanceDateDurationRelative(y1, mon1, w1, d1, 'day', plainRelativeTo)); + ({ days: d2 } = ES.UnbalanceDateDurationRelative(y2, mon2, w2, d2, 'day', plainRelativeTo)); } ns1 = ES.TotalDurationNanoseconds(d1, h1, min1, s1, ms1, µs1, ns1, shift1); ns2 = ES.TotalDurationNanoseconds(d2, h2, min2, s2, ms2, µs2, ns2, shift2); diff --git a/polyfill/lib/ecmascript.mjs b/polyfill/lib/ecmascript.mjs index 17a9398ada..82f13de895 100644 --- a/polyfill/lib/ecmascript.mjs +++ b/polyfill/lib/ecmascript.mjs @@ -973,15 +973,21 @@ export function GetTemporalUnit(options, key, unitGroup, requiredOrDefault, extr } export function ToRelativeTemporalObject(options) { + // returns: { + // plainRelativeTo: Temporal.PlainDate | undefined + // zonedRelativeTo: Temporal.ZonedDateTime | undefined + // } + // plainRelativeTo and zonedRelativeTo are mutually exclusive. const relativeTo = options.relativeTo; - if (relativeTo === undefined) return relativeTo; + if (relativeTo === undefined) return {}; let offsetBehaviour = 'option'; let matchMinutes = false; let year, month, day, hour, minute, second, millisecond, microsecond, nanosecond, calendar, timeZone, offset; if (Type(relativeTo) === 'Object') { - if (IsTemporalZonedDateTime(relativeTo) || IsTemporalDate(relativeTo)) return relativeTo; - if (IsTemporalDateTime(relativeTo)) return TemporalDateTimeToDate(relativeTo); + if (IsTemporalZonedDateTime(relativeTo)) return { zonedRelativeTo: relativeTo }; + if (IsTemporalDate(relativeTo)) return { plainRelativeTo: relativeTo }; + if (IsTemporalDateTime(relativeTo)) return { plainRelativeTo: TemporalDateTimeToDate(relativeTo) }; calendar = GetTemporalCalendarSlotValueWithISODefault(relativeTo); const fieldNames = CalendarFields(calendar, ['day', 'month', 'monthCode', 'year']); Call(ArrayPrototypePush, fieldNames, [ @@ -1040,7 +1046,7 @@ export function ToRelativeTemporalObject(options) { if (!IsBuiltinCalendar(calendar)) throw new RangeError(`invalid calendar identifier ${calendar}`); calendar = ASCIILowercase(calendar); } - if (timeZone === undefined) return CreateTemporalDate(year, month, day, calendar); + if (timeZone === undefined) return { plainRelativeTo: CreateTemporalDate(year, month, day, calendar) }; const offsetNs = offsetBehaviour === 'option' ? ParseDateTimeUTCOffset(offset) : 0; const epochNanoseconds = InterpretISODateTimeOffset( year, @@ -1059,7 +1065,7 @@ export function ToRelativeTemporalObject(options) { 'reject', matchMinutes ); - return CreateTemporalZonedDateTime(epochNanoseconds, timeZone, calendar); + return { zonedRelativeTo: CreateTemporalZonedDateTime(epochNanoseconds, timeZone, calendar) }; } export function DefaultTemporalLargestUnit( @@ -3527,16 +3533,12 @@ export function BalancePossiblyInfiniteTimeDurationRelative( return { days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds }; } -export function UnbalanceDateDurationRelative(years, months, weeks, days, largestUnit, relativeTo) { +export function UnbalanceDateDurationRelative(years, months, weeks, days, largestUnit, plainRelativeTo) { const TemporalDuration = GetIntrinsic('%Temporal.Duration%'); const sign = DurationSign(years, months, weeks, days, 0, 0, 0, 0, 0, 0); if (sign === 0) return { years, months, weeks, days }; - let calendar; - if (relativeTo) { - relativeTo = ToTemporalDate(relativeTo); - calendar = GetSlot(relativeTo, CALENDAR); - } + const calendar = plainRelativeTo ? GetSlot(plainRelativeTo, CALENDAR) : undefined; const oneYear = new TemporalDuration(sign); const oneMonth = new TemporalDuration(0, sign); @@ -3554,6 +3556,7 @@ export function UnbalanceDateDurationRelative(years, months, weeks, days, larges break; case 'month': { + if (years.isZero()) break; if (!calendar) throw new RangeError('a starting point is required for months balancing'); // balance years down to months let dateAdd, dateUntil; @@ -3562,12 +3565,12 @@ export function UnbalanceDateDurationRelative(years, months, weeks, days, larges dateUntil = GetMethod(calendar, 'dateUntil'); } while (!years.isZero()) { - const newRelativeTo = CalendarDateAdd(calendar, relativeTo, oneYear, undefined, dateAdd); + const newRelativeTo = CalendarDateAdd(calendar, plainRelativeTo, oneYear, undefined, dateAdd); const untilOptions = ObjectCreate(null); untilOptions.largestUnit = 'month'; - const untilResult = CalendarDateUntil(calendar, relativeTo, newRelativeTo, untilOptions, dateUntil); + const untilResult = CalendarDateUntil(calendar, plainRelativeTo, newRelativeTo, untilOptions, dateUntil); const oneYearMonths = GetSlot(untilResult, MONTHS); - relativeTo = newRelativeTo; + plainRelativeTo = newRelativeTo; months = months.add(oneYearMonths); years = years.subtract(sign); } @@ -3575,12 +3578,18 @@ export function UnbalanceDateDurationRelative(years, months, weeks, days, larges break; case 'week': { + if (years.isZero() && months.isZero()) break; if (!calendar) throw new RangeError('a starting point is required for weeks balancing'); const dateAdd = typeof calendar !== 'string' ? GetMethod(calendar, 'dateAdd') : undefined; // balance years down to days while (!years.isZero()) { let oneYearDays; - ({ relativeTo, days: oneYearDays } = MoveRelativeDate(calendar, relativeTo, oneYear, dateAdd)); + ({ relativeTo: plainRelativeTo, days: oneYearDays } = MoveRelativeDate( + calendar, + plainRelativeTo, + oneYear, + dateAdd + )); days = days.add(oneYearDays); years = years.subtract(sign); } @@ -3588,7 +3597,12 @@ export function UnbalanceDateDurationRelative(years, months, weeks, days, larges // balance months down to days while (!months.isZero()) { let oneMonthDays; - ({ relativeTo, days: oneMonthDays } = MoveRelativeDate(calendar, relativeTo, oneMonth, dateAdd)); + ({ relativeTo: plainRelativeTo, days: oneMonthDays } = MoveRelativeDate( + calendar, + plainRelativeTo, + oneMonth, + dateAdd + )); days = days.add(oneMonthDays); months = months.subtract(sign); } @@ -3602,7 +3616,12 @@ export function UnbalanceDateDurationRelative(years, months, weeks, days, larges // balance years down to days while (!years.isZero()) { let oneYearDays; - ({ relativeTo, days: oneYearDays } = MoveRelativeDate(calendar, relativeTo, oneYear, dateAdd)); + ({ relativeTo: plainRelativeTo, days: oneYearDays } = MoveRelativeDate( + calendar, + plainRelativeTo, + oneYear, + dateAdd + )); days = days.add(oneYearDays); years = years.subtract(sign); } @@ -3610,7 +3629,12 @@ export function UnbalanceDateDurationRelative(years, months, weeks, days, larges // balance months down to days while (!months.isZero()) { let oneMonthDays; - ({ relativeTo, days: oneMonthDays } = MoveRelativeDate(calendar, relativeTo, oneMonth, dateAdd)); + ({ relativeTo: plainRelativeTo, days: oneMonthDays } = MoveRelativeDate( + calendar, + plainRelativeTo, + oneMonth, + dateAdd + )); days = days.add(oneMonthDays); months = months.subtract(sign); } @@ -3618,7 +3642,12 @@ export function UnbalanceDateDurationRelative(years, months, weeks, days, larges // balance weeks down to days while (!weeks.isZero()) { let oneWeekDays; - ({ relativeTo, days: oneWeekDays } = MoveRelativeDate(calendar, relativeTo, oneWeek, dateAdd)); + ({ relativeTo: plainRelativeTo, days: oneWeekDays } = MoveRelativeDate( + calendar, + plainRelativeTo, + oneWeek, + dateAdd + )); days = days.add(oneWeekDays); weeks = weeks.subtract(sign); } @@ -3634,17 +3663,16 @@ export function UnbalanceDateDurationRelative(years, months, weeks, days, larges }; } -export function BalanceDateDurationRelative(years, months, weeks, days, largestUnit, relativeTo) { +export function BalanceDateDurationRelative(years, months, weeks, days, largestUnit, plainRelativeTo) { const TemporalDuration = GetIntrinsic('%Temporal.Duration%'); const sign = DurationSign(years, months, weeks, days, 0, 0, 0, 0, 0, 0); - if (sign === 0) return { years, months, weeks, days }; - - let calendar; - if (relativeTo) { - relativeTo = ToTemporalDate(relativeTo); - calendar = GetSlot(relativeTo, CALENDAR); + if (sign === 0 || (largestUnit !== 'year' && largestUnit !== 'month' && largestUnit !== 'week')) { + return { years, months, weeks, days }; } + if (!plainRelativeTo) throw new RangeError(`a starting point is required for ${largestUnit}s balancing`); + const calendar = GetSlot(plainRelativeTo, CALENDAR); + const oneYear = new TemporalDuration(sign); const oneMonth = new TemporalDuration(0, sign); const oneWeek = new TemporalDuration(0, 0, sign); @@ -3657,72 +3685,109 @@ export function BalanceDateDurationRelative(years, months, weeks, days, largestU switch (largestUnit) { case 'year': { - if (!calendar) throw new RangeError('a starting point is required for years balancing'); const dateAdd = typeof calendar !== 'string' ? GetMethod(calendar, 'dateAdd') : undefined; // balance days up to years let newRelativeTo, oneYearDays; - ({ relativeTo: newRelativeTo, days: oneYearDays } = MoveRelativeDate(calendar, relativeTo, oneYear, dateAdd)); + ({ relativeTo: newRelativeTo, days: oneYearDays } = MoveRelativeDate( + calendar, + plainRelativeTo, + oneYear, + dateAdd + )); while (days.abs().geq(MathAbs(oneYearDays))) { days = days.subtract(oneYearDays); years = years.add(sign); - relativeTo = newRelativeTo; - ({ relativeTo: newRelativeTo, days: oneYearDays } = MoveRelativeDate(calendar, relativeTo, oneYear, dateAdd)); + plainRelativeTo = newRelativeTo; + ({ relativeTo: newRelativeTo, days: oneYearDays } = MoveRelativeDate( + calendar, + plainRelativeTo, + oneYear, + dateAdd + )); } // balance days up to months let oneMonthDays; - ({ relativeTo: newRelativeTo, days: oneMonthDays } = MoveRelativeDate(calendar, relativeTo, oneMonth, dateAdd)); + ({ relativeTo: newRelativeTo, days: oneMonthDays } = MoveRelativeDate( + calendar, + plainRelativeTo, + oneMonth, + dateAdd + )); while (days.abs().geq(MathAbs(oneMonthDays))) { days = days.subtract(oneMonthDays); months = months.add(sign); - relativeTo = newRelativeTo; - ({ relativeTo: newRelativeTo, days: oneMonthDays } = MoveRelativeDate(calendar, relativeTo, oneMonth, dateAdd)); + plainRelativeTo = newRelativeTo; + ({ relativeTo: newRelativeTo, days: oneMonthDays } = MoveRelativeDate( + calendar, + plainRelativeTo, + oneMonth, + dateAdd + )); } // balance months up to years - newRelativeTo = CalendarDateAdd(calendar, relativeTo, oneYear, undefined, dateAdd); + newRelativeTo = CalendarDateAdd(calendar, plainRelativeTo, oneYear, undefined, dateAdd); const dateUntil = typeof calendar !== 'string' ? GetMethod(calendar, 'dateUntil') : undefined; const untilOptions = ObjectCreate(null); untilOptions.largestUnit = 'month'; - let untilResult = CalendarDateUntil(calendar, relativeTo, newRelativeTo, untilOptions, dateUntil); + let untilResult = CalendarDateUntil(calendar, plainRelativeTo, newRelativeTo, untilOptions, dateUntil); let oneYearMonths = GetSlot(untilResult, MONTHS); while (months.abs().geq(MathAbs(oneYearMonths))) { months = months.subtract(oneYearMonths); years = years.add(sign); - relativeTo = newRelativeTo; - newRelativeTo = CalendarDateAdd(calendar, relativeTo, oneYear, undefined, dateAdd); + plainRelativeTo = newRelativeTo; + newRelativeTo = CalendarDateAdd(calendar, plainRelativeTo, oneYear, undefined, dateAdd); const untilOptions = ObjectCreate(null); untilOptions.largestUnit = 'month'; - untilResult = CalendarDateUntil(calendar, relativeTo, newRelativeTo, untilOptions, dateUntil); + untilResult = CalendarDateUntil(calendar, plainRelativeTo, newRelativeTo, untilOptions, dateUntil); oneYearMonths = GetSlot(untilResult, MONTHS); } break; } case 'month': { - if (!calendar) throw new RangeError('a starting point is required for months balancing'); const dateAdd = typeof calendar !== 'string' ? GetMethod(calendar, 'dateAdd') : undefined; // balance days up to months let newRelativeTo, oneMonthDays; - ({ relativeTo: newRelativeTo, days: oneMonthDays } = MoveRelativeDate(calendar, relativeTo, oneMonth, dateAdd)); + ({ relativeTo: newRelativeTo, days: oneMonthDays } = MoveRelativeDate( + calendar, + plainRelativeTo, + oneMonth, + dateAdd + )); while (days.abs().geq(MathAbs(oneMonthDays))) { days = days.subtract(oneMonthDays); months = months.add(sign); - relativeTo = newRelativeTo; - ({ relativeTo: newRelativeTo, days: oneMonthDays } = MoveRelativeDate(calendar, relativeTo, oneMonth, dateAdd)); + plainRelativeTo = newRelativeTo; + ({ relativeTo: newRelativeTo, days: oneMonthDays } = MoveRelativeDate( + calendar, + plainRelativeTo, + oneMonth, + dateAdd + )); } break; } case 'week': { - if (!calendar) throw new RangeError('a starting point is required for weeks balancing'); const dateAdd = typeof calendar !== 'string' ? GetMethod(calendar, 'dateAdd') : undefined; // balance days up to weeks let newRelativeTo, oneWeekDays; - ({ relativeTo: newRelativeTo, days: oneWeekDays } = MoveRelativeDate(calendar, relativeTo, oneWeek, dateAdd)); + ({ relativeTo: newRelativeTo, days: oneWeekDays } = MoveRelativeDate( + calendar, + plainRelativeTo, + oneWeek, + dateAdd + )); while (days.abs().geq(MathAbs(oneWeekDays))) { days = days.subtract(oneWeekDays); weeks = weeks.add(sign); - relativeTo = newRelativeTo; - ({ relativeTo: newRelativeTo, days: oneWeekDays } = MoveRelativeDate(calendar, relativeTo, oneWeek, dateAdd)); + plainRelativeTo = newRelativeTo; + ({ relativeTo: newRelativeTo, days: oneWeekDays } = MoveRelativeDate( + calendar, + plainRelativeTo, + oneWeek, + dateAdd + )); } break; } @@ -4511,6 +4576,9 @@ export function DifferenceTemporalZonedDateTime(operation, zonedDateTime, other, DifferenceZonedDateTime(ns1, ns2, timeZone, calendar, settings.largestUnit, resolvedOptions)); if (settings.smallestUnit !== 'nanosecond' || settings.roundingIncrement !== 1) { + const plainRelativeToWillBeUsed = + settings.smallestUnit === 'year' || settings.smallestUnit === 'month' || settings.smallestUnit === 'week'; + const plainRelativeTo = plainRelativeToWillBeUsed ? ToTemporalDate(zonedDateTime) : undefined; ({ years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = RoundDuration( years, months, @@ -4525,6 +4593,7 @@ export function DifferenceTemporalZonedDateTime(operation, zonedDateTime, other, settings.roundingIncrement, settings.smallestUnit, settings.roundingMode, + plainRelativeTo, zonedDateTime )); ({ years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = @@ -4626,14 +4695,15 @@ export function AddDuration( ms2, µs2, ns2, - relativeTo + plainRelativeTo, + zonedRelativeTo ) { const largestUnit1 = DefaultTemporalLargestUnit(y1, mon1, w1, d1, h1, min1, s1, ms1, µs1, ns1); const largestUnit2 = DefaultTemporalLargestUnit(y2, mon2, w2, d2, h2, min2, s2, ms2, µs2, ns2); const largestUnit = LargerOfTwoTemporalUnits(largestUnit1, largestUnit2); let years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds; - if (!relativeTo) { + if (!zonedRelativeTo && !plainRelativeTo) { if (largestUnit === 'year' || largestUnit === 'month' || largestUnit === 'week') { throw new RangeError('relativeTo is required for years, months, or weeks arithmetic'); } @@ -4648,20 +4718,20 @@ export function AddDuration( bigInt(ns1).add(ns2), largestUnit )); - } else if (IsTemporalDate(relativeTo)) { + } else if (plainRelativeTo) { const TemporalDuration = GetIntrinsic('%Temporal.Duration%'); - const calendar = GetSlot(relativeTo, CALENDAR); + const calendar = GetSlot(plainRelativeTo, CALENDAR); const dateDuration1 = new TemporalDuration(y1, mon1, w1, d1, 0, 0, 0, 0, 0, 0); const dateDuration2 = new TemporalDuration(y2, mon2, w2, d2, 0, 0, 0, 0, 0, 0); const dateAdd = typeof calendar !== 'string' ? GetMethod(calendar, 'dateAdd') : undefined; - const intermediate = CalendarDateAdd(calendar, relativeTo, dateDuration1, undefined, dateAdd); + const intermediate = CalendarDateAdd(calendar, plainRelativeTo, dateDuration1, undefined, dateAdd); const end = CalendarDateAdd(calendar, intermediate, dateDuration2, undefined, dateAdd); const dateLargestUnit = LargerOfTwoTemporalUnits('day', largestUnit); const differenceOptions = ObjectCreate(null); differenceOptions.largestUnit = dateLargestUnit; - const untilResult = CalendarDateUntil(calendar, relativeTo, end, differenceOptions); + const untilResult = CalendarDateUntil(calendar, plainRelativeTo, end, differenceOptions); years = GetSlot(untilResult, YEARS); months = GetSlot(untilResult, MONTHS); weeks = GetSlot(untilResult, WEEKS); @@ -4678,12 +4748,12 @@ export function AddDuration( largestUnit )); } else { - // relativeTo is a ZonedDateTime + // zonedRelativeTo is defined const TemporalInstant = GetIntrinsic('%Temporal.Instant%'); - const timeZone = GetSlot(relativeTo, TIME_ZONE); - const calendar = GetSlot(relativeTo, CALENDAR); + const timeZone = GetSlot(zonedRelativeTo, TIME_ZONE); + const calendar = GetSlot(zonedRelativeTo, CALENDAR); const intermediateNs = AddZonedDateTime( - GetSlot(relativeTo, INSTANT), + GetSlot(zonedRelativeTo, INSTANT), timeZone, calendar, y1, @@ -4719,7 +4789,7 @@ export function AddDuration( weeks = 0; days = 0; ({ hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = DifferenceInstant( - GetSlot(relativeTo, EPOCHNANOSECONDS), + GetSlot(zonedRelativeTo, EPOCHNANOSECONDS), endNs, 1, 'nanosecond', @@ -4729,7 +4799,7 @@ export function AddDuration( } else { ({ years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = DifferenceZonedDateTime( - GetSlot(relativeTo, EPOCHNANOSECONDS), + GetSlot(zonedRelativeTo, EPOCHNANOSECONDS), endNs, timeZone, calendar, @@ -4876,7 +4946,7 @@ export function AddDurationToOrSubtractDurationFromDuration(operation, duration, let { years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = ToTemporalDurationRecord(other); options = GetOptionsObject(options); - const relativeTo = ToRelativeTemporalObject(options); + const { plainRelativeTo, zonedRelativeTo } = ToRelativeTemporalObject(options); ({ years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = AddDuration( GetSlot(duration, YEARS), GetSlot(duration, MONTHS), @@ -4898,7 +4968,8 @@ export function AddDurationToOrSubtractDurationFromDuration(operation, duration, sign * milliseconds, sign * microseconds, sign * nanoseconds, - relativeTo + plainRelativeTo, + zonedRelativeTo )); const Duration = GetIntrinsic('%Temporal.Duration%'); return new Duration(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds); @@ -5248,10 +5319,9 @@ export function AdjustRoundedDurationDays( increment, unit, roundingMode, - relativeTo + zonedRelativeTo ) { if ( - !IsTemporalZonedDateTime(relativeTo) || unit === 'year' || unit === 'month' || unit === 'week' || @@ -5281,10 +5351,10 @@ export function AdjustRoundedDurationDays( ); const direction = MathSign(timeRemainderNs.toJSNumber()); - const timeZone = GetSlot(relativeTo, TIME_ZONE); - const calendar = GetSlot(relativeTo, CALENDAR); + const timeZone = GetSlot(zonedRelativeTo, TIME_ZONE); + const calendar = GetSlot(zonedRelativeTo, CALENDAR); const dayStart = AddZonedDateTime( - GetSlot(relativeTo, INSTANT), + GetSlot(zonedRelativeTo, INSTANT), timeZone, calendar, years, @@ -5339,7 +5409,8 @@ export function AdjustRoundedDurationDays( 0, 0, 0, - relativeTo + /* plainRelativeTo = */ undefined, + zonedRelativeTo )); ({ hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = RoundDuration( years, @@ -5384,11 +5455,12 @@ export function RoundDuration( increment, unit, roundingMode, - relativeTo = undefined + plainRelativeTo = undefined, + zonedRelativeTo = undefined ) { const TemporalDuration = GetIntrinsic('%Temporal.Duration%'); - if ((unit === 'year' || unit === 'month' || unit === 'week') && !relativeTo) { + if ((unit === 'year' || unit === 'month' || unit === 'week') && !plainRelativeTo) { throw new RangeError(`A starting point is required for ${unit}s rounding`); } @@ -5398,8 +5470,8 @@ export function RoundDuration( if (unit === 'year' || unit === 'month' || unit === 'week' || unit === 'day') { nanoseconds = TotalDurationNanoseconds(0, hours, minutes, seconds, milliseconds, microseconds, nanoseconds, 0); let deltaDays; - if (IsTemporalZonedDateTime(relativeTo)) { - const intermediate = MoveRelativeZonedDateTime(relativeTo, years, months, weeks, days); + if (zonedRelativeTo) { + const intermediate = MoveRelativeZonedDateTime(zonedRelativeTo, years, months, weeks, days); ({ days: deltaDays, nanoseconds, dayLengthNs } = NanosecondsToDays(nanoseconds, intermediate)); } else { ({ quotient: deltaDays, remainder: nanoseconds } = nanoseconds.divmod(DAY_NANOS)); @@ -5413,32 +5485,36 @@ export function RoundDuration( let total; switch (unit) { case 'year': { - relativeTo = ToTemporalDate(relativeTo); - const calendar = GetSlot(relativeTo, CALENDAR); + const calendar = GetSlot(plainRelativeTo, CALENDAR); // convert months and weeks to days by calculating difference( // relativeTo + years, relativeTo + { years, months, weeks }) const yearsDuration = new TemporalDuration(years); const dateAdd = typeof calendar !== 'string' ? GetMethod(calendar, 'dateAdd') : undefined; - const yearsLater = CalendarDateAdd(calendar, relativeTo, yearsDuration, undefined, dateAdd); + const yearsLater = CalendarDateAdd(calendar, plainRelativeTo, yearsDuration, undefined, dateAdd); const yearsMonthsWeeks = new TemporalDuration(years, months, weeks); - const yearsMonthsWeeksLater = CalendarDateAdd(calendar, relativeTo, yearsMonthsWeeks, undefined, dateAdd); + const yearsMonthsWeeksLater = CalendarDateAdd(calendar, plainRelativeTo, yearsMonthsWeeks, undefined, dateAdd); const monthsWeeksInDays = DaysUntil(yearsLater, yearsMonthsWeeksLater); - relativeTo = yearsLater; + plainRelativeTo = yearsLater; days += monthsWeeksInDays; const wholeDays = new TemporalDuration(0, 0, 0, days); - const wholeDaysLater = CalendarDateAdd(calendar, relativeTo, wholeDays, undefined, dateAdd); + const wholeDaysLater = CalendarDateAdd(calendar, plainRelativeTo, wholeDays, undefined, dateAdd); const untilOptions = ObjectCreate(null); untilOptions.largestUnit = 'year'; - const yearsPassed = GetSlot(CalendarDateUntil(calendar, relativeTo, wholeDaysLater, untilOptions), YEARS); + const yearsPassed = GetSlot(CalendarDateUntil(calendar, plainRelativeTo, wholeDaysLater, untilOptions), YEARS); years += yearsPassed; const yearsPassedDuration = new TemporalDuration(yearsPassed); let daysPassed; - ({ relativeTo, days: daysPassed } = MoveRelativeDate(calendar, relativeTo, yearsPassedDuration, dateAdd)); + ({ relativeTo: plainRelativeTo, days: daysPassed } = MoveRelativeDate( + calendar, + plainRelativeTo, + yearsPassedDuration, + dateAdd + )); days -= daysPassed; const oneYear = new TemporalDuration(days < 0 ? -1 : 1); - let { days: oneYearDays } = MoveRelativeDate(calendar, relativeTo, oneYear, dateAdd); + let { days: oneYearDays } = MoveRelativeDate(calendar, plainRelativeTo, oneYear, dateAdd); // Note that `nanoseconds` below (here and in similar code for months, // weeks, and days further below) isn't actually nanoseconds for the @@ -5457,18 +5533,17 @@ export function RoundDuration( break; } case 'month': { - relativeTo = ToTemporalDate(relativeTo); - const calendar = GetSlot(relativeTo, CALENDAR); + const calendar = GetSlot(plainRelativeTo, CALENDAR); // convert weeks to days by calculating difference(relativeTo + // { years, months }, relativeTo + { years, months, weeks }) const yearsMonths = new TemporalDuration(years, months); const dateAdd = typeof calendar !== 'string' ? GetMethod(calendar, 'dateAdd') : undefined; - const yearsMonthsLater = CalendarDateAdd(calendar, relativeTo, yearsMonths, undefined, dateAdd); + const yearsMonthsLater = CalendarDateAdd(calendar, plainRelativeTo, yearsMonths, undefined, dateAdd); const yearsMonthsWeeks = new TemporalDuration(years, months, weeks); - const yearsMonthsWeeksLater = CalendarDateAdd(calendar, relativeTo, yearsMonthsWeeks, undefined, dateAdd); + const yearsMonthsWeeksLater = CalendarDateAdd(calendar, plainRelativeTo, yearsMonthsWeeks, undefined, dateAdd); const weeksInDays = DaysUntil(yearsMonthsLater, yearsMonthsWeeksLater); - relativeTo = yearsMonthsLater; + plainRelativeTo = yearsMonthsLater; days += weeksInDays; // Months may be different lengths of days depending on the calendar, @@ -5476,11 +5551,21 @@ export function RoundDuration( const sign = MathSign(days); const oneMonth = new TemporalDuration(0, days < 0 ? -1 : 1); let oneMonthDays; - ({ relativeTo, days: oneMonthDays } = MoveRelativeDate(calendar, relativeTo, oneMonth, dateAdd)); + ({ relativeTo: plainRelativeTo, days: oneMonthDays } = MoveRelativeDate( + calendar, + plainRelativeTo, + oneMonth, + dateAdd + )); while (MathAbs(days) >= MathAbs(oneMonthDays)) { months += sign; days -= oneMonthDays; - ({ relativeTo, days: oneMonthDays } = MoveRelativeDate(calendar, relativeTo, oneMonth, dateAdd)); + ({ relativeTo: plainRelativeTo, days: oneMonthDays } = MoveRelativeDate( + calendar, + plainRelativeTo, + oneMonth, + dateAdd + )); } oneMonthDays = MathAbs(oneMonthDays); const divisor = bigInt(oneMonthDays).multiply(dayLengthNs); @@ -5493,8 +5578,7 @@ export function RoundDuration( break; } case 'week': { - relativeTo = ToTemporalDate(relativeTo); - const calendar = GetSlot(relativeTo, CALENDAR); + const calendar = GetSlot(plainRelativeTo, CALENDAR); // Weeks may be different lengths of days depending on the calendar, // convert days to weeks in a loop as described above under 'years'. @@ -5502,11 +5586,21 @@ export function RoundDuration( const oneWeek = new TemporalDuration(0, 0, days < 0 ? -1 : 1); const dateAdd = typeof calendar !== 'string' ? GetMethod(calendar, 'dateAdd') : undefined; let oneWeekDays; - ({ relativeTo, days: oneWeekDays } = MoveRelativeDate(calendar, relativeTo, oneWeek, dateAdd)); + ({ relativeTo: plainRelativeTo, days: oneWeekDays } = MoveRelativeDate( + calendar, + plainRelativeTo, + oneWeek, + dateAdd + )); while (MathAbs(days) >= MathAbs(oneWeekDays)) { weeks += sign; days -= oneWeekDays; - ({ relativeTo, days: oneWeekDays } = MoveRelativeDate(calendar, relativeTo, oneWeek, dateAdd)); + ({ relativeTo: plainRelativeTo, days: oneWeekDays } = MoveRelativeDate( + calendar, + plainRelativeTo, + oneWeek, + dateAdd + )); } oneWeekDays = MathAbs(oneWeekDays); const divisor = bigInt(oneWeekDays).multiply(dayLengthNs); diff --git a/polyfill/test/ecmascript.mjs b/polyfill/test/ecmascript.mjs index 94d3c752b3..8c7072156b 100644 --- a/polyfill/test/ecmascript.mjs +++ b/polyfill/test/ecmascript.mjs @@ -120,6 +120,96 @@ describe('ECMAScript', () => { } }); }); + + describe('ToRelativeTemporalObject', () => { + it('bare date-time string', () => { + const { plainRelativeTo, zonedRelativeTo } = ES.ToRelativeTemporalObject({ relativeTo: '2019-11-01T00:00' }); + equal(`${plainRelativeTo}`, '2019-11-01'); + equal(zonedRelativeTo, undefined); + }); + + it('bare date-time property bag', () => { + const { plainRelativeTo, zonedRelativeTo } = ES.ToRelativeTemporalObject({ + relativeTo: { year: 2019, month: 11, day: 1 } + }); + equal(`${plainRelativeTo}`, '2019-11-01'); + equal(zonedRelativeTo, undefined); + }); + + it('date-time + offset string', () => { + const { plainRelativeTo, zonedRelativeTo } = ES.ToRelativeTemporalObject({ + relativeTo: '2019-11-01T00:00-07:00' + }); + equal(`${plainRelativeTo}`, '2019-11-01'); + equal(zonedRelativeTo, undefined); + }); + + it('date-time + offset property bag', () => { + const { plainRelativeTo, zonedRelativeTo } = ES.ToRelativeTemporalObject({ + relativeTo: { year: 2019, month: 11, day: 1, offset: '-07:00' } + }); + equal(`${plainRelativeTo}`, '2019-11-01'); + equal(zonedRelativeTo, undefined); + }); + + it('date-time + annotation string', () => { + const { plainRelativeTo, zonedRelativeTo } = ES.ToRelativeTemporalObject({ + relativeTo: '2019-11-01T00:00[-07:00]' + }); + equal(plainRelativeTo, undefined); + equal(`${zonedRelativeTo}`, '2019-11-01T00:00:00-07:00[-07:00]'); + }); + + it('date-time + annotation property bag', () => { + const { plainRelativeTo, zonedRelativeTo } = ES.ToRelativeTemporalObject({ + relativeTo: { year: 2019, month: 11, day: 1, timeZone: '-07:00' } + }); + equal(plainRelativeTo, undefined); + equal(`${zonedRelativeTo}`, '2019-11-01T00:00:00-07:00[-07:00]'); + }); + + it('date-time + offset + annotation string', () => { + const { plainRelativeTo, zonedRelativeTo } = ES.ToRelativeTemporalObject({ + relativeTo: '2019-11-01T00:00+00:00[UTC]' + }); + equal(plainRelativeTo, undefined); + equal(`${zonedRelativeTo}`, '2019-11-01T00:00:00+00:00[UTC]'); + }); + + it('date-time + offset + annotation property bag', () => { + const { plainRelativeTo, zonedRelativeTo } = ES.ToRelativeTemporalObject({ + relativeTo: { year: 2019, month: 11, day: 1, offset: '+00:00', timeZone: 'UTC' } + }); + equal(plainRelativeTo, undefined); + equal(`${zonedRelativeTo}`, '2019-11-01T00:00:00+00:00[UTC]'); + }); + + it('date-time + Z + offset', () => { + const { plainRelativeTo, zonedRelativeTo } = ES.ToRelativeTemporalObject({ + relativeTo: '2019-11-01T00:00Z[-07:00]' + }); + equal(plainRelativeTo, undefined); + equal(`${zonedRelativeTo}`, '2019-10-31T17:00:00-07:00[-07:00]'); + }); + + it('date-time + Z', () => { + throws(() => ES.ToRelativeTemporalObject({ relativeTo: '2019-11-01T00:00Z' }), RangeError); + }); + + it('string offset does not agree', () => { + throws(() => ES.ToRelativeTemporalObject({ relativeTo: '2019-11-01T00:00+04:15[UTC]' }), RangeError); + }); + + it('property bag offset does not agree', () => { + throws( + () => + ES.ToRelativeTemporalObject({ + relativeTo: { year: 2019, month: 11, day: 1, offset: '+04:15', timeZone: 'UTC' } + }), + RangeError + ); + }); + }); }); import { normalize } from 'path'; diff --git a/spec/abstractops.html b/spec/abstractops.html index 7f1a9d5a3d..8718d3637a 100644 --- a/spec/abstractops.html +++ b/spec/abstractops.html @@ -570,27 +570,30 @@

ToRelativeTemporalObject ( _options_: an Object - ): either a normal completion containing either a Temporal.ZonedDateTime object or a Temporal.PlainDate object, or a throw completion

+ ): either a normal completion containing a Record with fields [[PlainRelativeTo]] and [[ZonedRelativeTo]], or a throw completion

description
It examines the value of the `relativeTo` property of its _options_ argument. - If the value is *undefined*, it returns *undefined*. + If the value is *undefined*, both the [[PlainRelativeTo]] and [[ZonedRelativeTo]] fields of the returned Record are *undefined*. If the value is not a String or an Object, it throws a *TypeError*. - Otherwise, it attempts to return a Temporal.ZonedDateTime instance or Temporal.PlainDate instance, in order of preference, by converting the value. + Otherwise, it attempts to return a Temporal.ZonedDateTime instance in the [[ZonedRelativeTo]] field, or a Temporal.PlainDate instance in the [[PlainRelativeTo]] field, in order of preference, by converting the value. If neither of those are possible, it throws a *RangeError*.
1. Let _value_ be ? Get(_options_, *"relativeTo"*). - 1. If _value_ is *undefined*, return *undefined*. + 1. If _value_ is *undefined*, return the Record { [[ZonedRelativeTo]]: *undefined*, [[PlainRelativeTo]]: *undefined* }. 1. Let _offsetBehaviour_ be ~option~. 1. Let _matchBehaviour_ be ~match exactly~. 1. If Type(_value_) is Object, then - 1. If _value_ has either an [[InitializedTemporalDate]] or [[InitializedTemporalZonedDateTime]] internal slot, then - 1. Return _value_. + 1. If _value_ has an [[InitializedTemporalZonedDateTime]] internal slot, then + 1. Return the Record { [[PlainRelativeTo]]: *undefined*, [[ZonedRelativeTo]]: _value_ }. + 1. If _value_ has an [[InitializedTemporalDate]] internal slot, then + 1. Return the Record { [[PlainRelativeTo]]: _value_, [[ZonedRelativeTo]]: *undefined* }. 1. If _value_ has an [[InitializedTemporalDateTime]] internal slot, then - 1. Return ! CreateTemporalDate(_value_.[[ISOYear]], _value_.[[ISOMonth]], _value_.[[ISODay]], _value_.[[Calendar]]). + 1. Let _plainDate_ be ! CreateTemporalDate(_value_.[[ISOYear]], _value_.[[ISOMonth]], _value_.[[ISODay]], _value_.[[Calendar]]). + 1. Return the Record { [[PlainRelativeTo]]: _plainDate_, [[ZonedRelativeTo]]: *undefined* }. 1. Let _calendar_ be ? GetTemporalCalendarSlotValueWithISODefault(_value_). 1. Let _fieldNames_ be ? CalendarFields(_calendar_, « *"day"*, *"month"*, *"monthCode"*, *"year"* »). 1. Append *"hour"*, *"microsecond"*, *"millisecond"*, *"minute"*, *"nanosecond"*, *"offset"*, *"second"*, and *"timeZone"* to _fieldNames_. @@ -623,13 +626,15 @@

ToRelativeTemporalObject ( 1. If IsBuiltinCalendar(_calendar_) is *false*, throw a *RangeError* exception. 1. Set _calendar_ to the ASCII-lowercase of _calendar_. 1. If _timeZone_ is *undefined*, then - 1. Return ? CreateTemporalDate(_result_.[[Year]], _result_.[[Month]], _result_.[[Day]], _calendar_). + 1. Let _plainDate_ be ? CreateTemporalDate(_result_.[[Year]], _result_.[[Month]], _result_.[[Day]], _calendar_). + 1. Return the Record { [[PlainRelativeTo]]: _plainDate, [[ZonedRelativeTo]]: *undefined* }. 1. If _offsetBehaviour_ is ~option~, then 1. Let _offsetNs_ be ? ParseDateTimeUTCOffset(_offsetString_). 1. Else, 1. Let _offsetNs_ be 0. 1. Let _epochNanoseconds_ be ? InterpretISODateTimeOffset(_result_.[[Year]], _result_.[[Month]], _result_.[[Day]], _result_.[[Hour]], _result_.[[Minute]], _result_.[[Second]], _result_.[[Millisecond]], _result_.[[Microsecond]], _result_.[[Nanosecond]], _offsetBehaviour_, _offsetNs_, _timeZone_, *"compatible"*, *"reject"*, _matchBehaviour_). - 1. Return ! CreateTemporalZonedDateTime(_epochNanoseconds_, _timeZone_, _calendar_). + 1. Let _zonedRelativeTo_ be ! CreateTemporalZonedDateTime(_epochNanoseconds_, _timeZone_, _calendar_). + 1. Return the Record { [[PlainRelativeTo]]: *undefined*, [[ZonedRelativeTo]]: _zonedRelativeTo_ }. diff --git a/spec/duration.html b/spec/duration.html index e1983e3885..8e1b9bea71 100644 --- a/spec/duration.html +++ b/spec/duration.html @@ -94,13 +94,15 @@

Temporal.Duration.compare ( _one_, _two_ [ , _options_ ] )

1. Set _one_ to ? ToTemporalDuration(_one_). 1. Set _two_ to ? ToTemporalDuration(_two_). 1. Set _options_ to ? GetOptionsObject(_options_). - 1. Let _relativeTo_ be ? ToRelativeTemporalObject(_options_). - 1. Let _shift1_ be ? CalculateOffsetShift(_relativeTo_, _one_.[[Years]], _one_.[[Months]], _one_.[[Weeks]], _one_.[[Days]]). - 1. Let _shift2_ be ? CalculateOffsetShift(_relativeTo_, _two_.[[Years]], _two_.[[Months]], _two_.[[Weeks]], _two_.[[Days]]). + 1. Let _relativeToRecord_ be ? ToRelativeTemporalObject(_options_). + 1. Let _zonedRelativeTo_ be _relativeToRecord_.[[ZonedRelativeTo]]. + 1. Let _plainRelativeTo_ be _relativeToRecord_.[[PlainRelativeTo]]. + 1. Let _shift1_ be ? CalculateOffsetShift(_zonedRelativeTo_, _one_.[[Years]], _one_.[[Months]], _one_.[[Weeks]], _one_.[[Days]]). + 1. Let _shift2_ be ? CalculateOffsetShift(_zonedRelativeTo_, _two_.[[Years]], _two_.[[Months]], _two_.[[Weeks]], _two_.[[Days]]). 1. If _one_.[[Years]] ≠ 0, or _two_.[[Years]] ≠ 0, or _one_.[[Months]] ≠ 0, or _two_.[[Months]] ≠ 0, or _one_.[[Weeks]] ≠ 0, or _two_.[[Weeks]] ≠ 0, then - 1. If _relativeTo_ is an Object with an [[InitializedTemporalZonedDateTime]] internal slot, set _relativeTo_ to ? ToTemporalDate(_relativeTo_). - 1. Let _unbalanceResult1_ be ? UnbalanceDateDurationRelative(_one_.[[Years]], _one_.[[Months]], _one_.[[Weeks]], _one_.[[Days]], *"day"*, _relativeTo_). - 1. Let _unbalanceResult2_ be ? UnbalanceDateDurationRelative(_two_.[[Years]], _two_.[[Months]], _two_.[[Weeks]], _two_.[[Days]], *"day"*, _relativeTo_). + 1. If _zonedRelativeTo_ is not *undefined*, set _plainRelativeTo_ to ? ToTemporalDate(_zonedRelativeTo_). + 1. Let _unbalanceResult1_ be ? UnbalanceDateDurationRelative(_one_.[[Years]], _one_.[[Months]], _one_.[[Weeks]], _one_.[[Days]], *"day"*, _plainRelativeTo_). + 1. Let _unbalanceResult2_ be ? UnbalanceDateDurationRelative(_two_.[[Years]], _two_.[[Months]], _two_.[[Weeks]], _two_.[[Days]], *"day"*, _plainRelativeTo_). 1. Let _days1_ be _unbalanceResult1_.[[Days]]. 1. Let _days2_ be _unbalanceResult2_.[[Days]]. 1. Else, @@ -415,7 +417,9 @@

Temporal.Duration.prototype.round ( _roundTo_ )

1. Let _largestUnitPresent_ be *true*. 1. NOTE: The following steps read options and perform independent validation in alphabetical order (ToRelativeTemporalObject reads *"relativeTo"*, ToTemporalRoundingIncrement reads *"roundingIncrement"* and ToTemporalRoundingMode reads *"roundingMode"*). 1. Let _largestUnit_ be ? GetTemporalUnit(_roundTo_, *"largestUnit"*, ~datetime~, *undefined*, « *"auto"* »). - 1. Let _relativeTo_ be ? ToRelativeTemporalObject(_roundTo_). + 1. Let _relativeToRecord_ be ? ToRelativeTemporalObject(_roundTo_). + 1. Let _zonedRelativeTo_ be _relativeToRecord_.[[ZonedRelativeTo]]. + 1. Let _plainRelativeTo_ be _relativeToRecord_.[[PlainRelativeTo]]. 1. Let _roundingIncrement_ be ? ToTemporalRoundingIncrement(_roundTo_). 1. Let _roundingMode_ be ? ToTemporalRoundingMode(_roundTo_, *"halfExpand"*). 1. Let _smallestUnit_ be ? GetTemporalUnit(_roundTo_, *"smallestUnit"*, ~datetime~, *undefined*). @@ -435,20 +439,23 @@

Temporal.Duration.prototype.round ( _roundTo_ )

1. Let _maximum_ be ! MaximumTemporalDurationRoundingIncrement(_smallestUnit_). 1. If _maximum_ is not *undefined*, perform ? ValidateTemporalRoundingIncrement(_roundingIncrement_, _maximum_, *false*). 1. Let _hoursToDaysConversionMayOccur_ be *false*. - 1. If _duration_.[[Days]] ≠ 0 and _relativeTo_ is an Object with an [[InitializedTemporalZonedDateTime]] internal slot, set _hoursToDaysConversionMayOccur_ to *true*. + 1. If _duration_.[[Days]] ≠ 0 and _zonedRelativeTo_ is not *undefined*, set _hoursToDaysConversionMayOccur_ to *true*. 1. Else if _duration_.[[Hours]] ≥ 24, set _hoursToDaysConversionMayOccur_ to *true*. 1. If _smallestUnit_ is *"nanosecond"*, and _roundingIncrement_ = 1, and _largestUnit_ is _existingLargestUnit_, and _duration_.[[Years]] = 0, and _duration_.[[Months]] = 0, and _duration_.[[Weeks]] = 0, and _hoursToDaysConversionMayOccur_ is *false*, and _duration_.[[Minutes]] < 60, and _duration_.[[Seconds]] < 60, and _duration_.[[Milliseconds]] < 1000, and _duration_.[[Microseconds]] < 1000, and _duration_.[[Nanoseconds]] < 1000, then 1. NOTE: The above conditions mean that the operation will have no effect: the smallest unit and rounding increment will leave the total duration unchanged, and it can be determined without calling a calendar or time zone method that no balancing will take place. 1. Return ! CreateTemporalDuration(_duration_.[[Years]], _duration_.[[Months]], _duration_.[[Weeks]], _duration_.[[Days]], _duration_.[[Hours]], _duration_.[[Minutes]], _duration_.[[Seconds]], _duration_.[[Milliseconds]], _duration_.[[Microseconds]], _duration_.[[Nanoseconds]]). - 1. Let _unbalanceResult_ be ? UnbalanceDateDurationRelative(_duration_.[[Years]], _duration_.[[Months]], _duration_.[[Weeks]], _duration_.[[Days]], _largestUnit_, _relativeTo_). - 1. Let _roundRecord_ be ? RoundDuration(_unbalanceResult_.[[Years]], _unbalanceResult_.[[Months]], _unbalanceResult_.[[Weeks]], _unbalanceResult_.[[Days]], _duration_.[[Hours]], _duration_.[[Minutes]], _duration_.[[Seconds]], _duration_.[[Milliseconds]], _duration_.[[Microseconds]], _duration_.[[Nanoseconds]], _roundingIncrement_, _smallestUnit_, _roundingMode_, _relativeTo_). + 1. If _zonedRelativeTo_ is not *undefined*; and _smallestUnit_ is any of *"year"*, *"month"*, *"week"*; and any of _duration_.[[Years]], _duration_.[[Months]], _duration_.[[Weeks]], _duration_.[[Days]] ≠ 0; then + 1. NOTE: The above conditions mean that the corresponding `Temporal.PlainDate` for _zonedRelativeTo_ will be used in one of the operations below. + 1. Set _plainRelativeTo_ to ? ToTemporalDate(_zonedRelativeTo_). + 1. Let _unbalanceResult_ be ? UnbalanceDateDurationRelative(_duration_.[[Years]], _duration_.[[Months]], _duration_.[[Weeks]], _duration_.[[Days]], _largestUnit_, _plainRelativeTo_). + 1. Let _roundRecord_ be ? RoundDuration(_unbalanceResult_.[[Years]], _unbalanceResult_.[[Months]], _unbalanceResult_.[[Weeks]], _unbalanceResult_.[[Days]], _duration_.[[Hours]], _duration_.[[Minutes]], _duration_.[[Seconds]], _duration_.[[Milliseconds]], _duration_.[[Microseconds]], _duration_.[[Nanoseconds]], _roundingIncrement_, _smallestUnit_, _roundingMode_, _plainRelativeTo_, _zonedRelativeTo_). 1. Let _roundResult_ be _roundRecord_.[[DurationRecord]]. - 1. If _relativeTo_ is not *undefined* and _relativeTo_ has an [[InitializedTemporalZonedDateTime]] internal slot, then - 1. Set _roundResult_ to ? AdjustRoundedDurationDays(_roundResult_.[[Years]], _roundResult_.[[Months]], _roundResult_.[[Weeks]], _roundResult_.[[Days]], _roundResult_.[[Hours]], _roundResult_.[[Minutes]], _roundResult_.[[Seconds]], _roundResult_.[[Milliseconds]], _roundResult_.[[Microseconds]], _roundResult_.[[Nanoseconds]], _roundingIncrement_, _smallestUnit_, _roundingMode_, _relativeTo_). - 1. Let _balanceResult_ be ? BalanceTimeDurationRelative(_roundResult_.[[Days]], _roundResult_.[[Hours]], _roundResult_.[[Minutes]], _roundResult_.[[Seconds]], _roundResult_.[[Milliseconds]], _roundResult_.[[Microseconds]], _roundResult_.[[Nanoseconds]], _largestUnit_, _relativeTo_). + 1. If _zonedRelativeTo_ is not *undefined*, then + 1. Set _roundResult_ to ? AdjustRoundedDurationDays(_roundResult_.[[Years]], _roundResult_.[[Months]], _roundResult_.[[Weeks]], _roundResult_.[[Days]], _roundResult_.[[Hours]], _roundResult_.[[Minutes]], _roundResult_.[[Seconds]], _roundResult_.[[Milliseconds]], _roundResult_.[[Microseconds]], _roundResult_.[[Nanoseconds]], _roundingIncrement_, _smallestUnit_, _roundingMode_, _zonedRelativeTo_). + 1. Let _balanceResult_ be ? BalanceTimeDurationRelative(_roundResult_.[[Days]], _roundResult_.[[Hours]], _roundResult_.[[Minutes]], _roundResult_.[[Seconds]], _roundResult_.[[Milliseconds]], _roundResult_.[[Microseconds]], _roundResult_.[[Nanoseconds]], _largestUnit_, _zonedRelativeTo_). 1. Else, 1. Let _balanceResult_ be ? BalanceTimeDuration(_roundResult_.[[Days]], _roundResult_.[[Hours]], _roundResult_.[[Minutes]], _roundResult_.[[Seconds]], _roundResult_.[[Milliseconds]], _roundResult_.[[Microseconds]], _roundResult_.[[Nanoseconds]], _largestUnit_). - 1. Let _result_ be ? BalanceDateDurationRelative(_roundResult_.[[Years]], _roundResult_.[[Months]], _roundResult_.[[Weeks]], _balanceResult_.[[Days]], _largestUnit_, _relativeTo_). + 1. Let _result_ be ? BalanceDateDurationRelative(_roundResult_.[[Years]], _roundResult_.[[Months]], _roundResult_.[[Weeks]], _balanceResult_.[[Days]], _largestUnit_, _plainRelativeTo_). 1. Return ! CreateTemporalDuration(_result_.[[Years]], _result_.[[Months]], _result_.[[Weeks]], _result_.[[Days]], _balanceResult_.[[Hours]], _balanceResult_.[[Minutes]], _balanceResult_.[[Seconds]], _balanceResult_.[[Milliseconds]], _balanceResult_.[[Microseconds]], _balanceResult_.[[Nanoseconds]]).
@@ -469,18 +476,23 @@

Temporal.Duration.prototype.total ( _totalOf_ )

1. Else, 1. Set _totalOf_ to ? GetOptionsObject(_totalOf_). 1. NOTE: The following steps read options and perform independent validation in alphabetical order (ToRelativeTemporalObject reads *"relativeTo"*). - 1. Let _relativeTo_ be ? ToRelativeTemporalObject(_totalOf_). + 1. Let _relativeToRecord_ be ? ToRelativeTemporalObject(_totalOf_). + 1. Let _zonedRelativeTo_ be _relativeToRecord_.[[ZonedRelativeTo]]. + 1. Let _plainRelativeTo_ be _relativeToRecord_.[[PlainRelativeTo]]. 1. Let _unit_ be ? GetTemporalUnit(_totalOf_, *"unit"*, ~datetime~, ~required~). - 1. Let _unbalanceResult_ be ? UnbalanceDateDurationRelative(_duration_.[[Years]], _duration_.[[Months]], _duration_.[[Weeks]], _duration_.[[Days]], _unit_, _relativeTo_). - 1. If Type(_relativeTo_) is Object and _relativeTo_ has an [[InitializedTemporalZonedDateTime]] internal slot, then - 1. Let _intermediate_ be ? MoveRelativeZonedDateTime(_relativeTo_, _unbalanceResult_.[[Years]], _unbalanceResult_.[[Months]], _unbalanceResult_.[[Weeks]], 0). + 1. If _zonedRelativeTo_ is not *undefined*; and _unit_ is any of *"year"*, *"month"*, *"week"*; and any of _duration_.[[Years]], _duration_.[[Months]], _duration_.[[Weeks]] ≠ 0; then + 1. NOTE: The above conditions mean that the corresponding `Temporal.PlainDate` for _zonedRelativeTo_ will be used in one of the operations below. + 1. Set _plainRelativeTo_ to ? ToTemporalDate(_zonedRelativeTo_). + 1. Let _unbalanceResult_ be ? UnbalanceDateDurationRelative(_duration_.[[Years]], _duration_.[[Months]], _duration_.[[Weeks]], _duration_.[[Days]], _unit_, _plainRelativeTo_). + 1. If _zonedRelativeTo_ is not *undefined*, then + 1. Let _intermediate_ be ? MoveRelativeZonedDateTime(_zonedRelativeTo_, _unbalanceResult_.[[Years]], _unbalanceResult_.[[Months]], _unbalanceResult_.[[Weeks]], 0). 1. Let _balanceResult_ be ? BalancePossiblyInfiniteTimeDurationRelative(_unbalanceResult_.[[Days]], _duration_.[[Hours]], _duration_.[[Minutes]], _duration_.[[Seconds]], _duration_.[[Milliseconds]], _duration_.[[Microseconds]], _duration_.[[Nanoseconds]], _unit_, _intermediate_). 1. Else, 1. Let _balanceResult_ be BalancePossiblyInfiniteTimeDuration(_unbalanceResult_.[[Days]], _duration_.[[Hours]], _duration_.[[Minutes]], _duration_.[[Seconds]], _duration_.[[Milliseconds]], _duration_.[[Microseconds]], _duration_.[[Nanoseconds]], _unit_). 1. If _balanceResult_ is ~positive overflow~, return *+∞*𝔽. 1. If _balanceResult_ is ~negative overflow~, return *-∞*𝔽. 1. Assert: _balanceResult_ is a Time Duration Record. - 1. Let _roundRecord_ be ? RoundDuration(_unbalanceResult_.[[Years]], _unbalanceResult_.[[Months]], _unbalanceResult_.[[Weeks]], _balanceResult_.[[Days]], _balanceResult_.[[Hours]], _balanceResult_.[[Minutes]], _balanceResult_.[[Seconds]], _balanceResult_.[[Milliseconds]], _balanceResult_.[[Microseconds]], _balanceResult_.[[Nanoseconds]], 1, _unit_, *"trunc"*, _relativeTo_). + 1. Let _roundRecord_ be ? RoundDuration(_unbalanceResult_.[[Years]], _unbalanceResult_.[[Months]], _unbalanceResult_.[[Weeks]], _balanceResult_.[[Days]], _balanceResult_.[[Hours]], _balanceResult_.[[Minutes]], _balanceResult_.[[Seconds]], _balanceResult_.[[Milliseconds]], _balanceResult_.[[Microseconds]], _balanceResult_.[[Nanoseconds]], 1, _unit_, *"trunc"*, _plainRelativeTo_, _zonedRelativeTo_). 1. Return 𝔽(_roundRecord_.[[Total]]). @@ -1357,7 +1369,7 @@

_weeks_: an integer, _days_: an integer, _largestUnit_: a String, - _relativeTo_: *undefined*, a Temporal.PlainDate, or a Temporal.ZonedDateTime, + _plainRelativeTo_: *undefined* or a Temporal.PlainDate, )

@@ -1374,12 +1386,12 @@

1. Let _oneYear_ be ! CreateTemporalDuration(_sign_, 0, 0, 0, 0, 0, 0, 0, 0, 0). 1. Let _oneMonth_ be ! CreateTemporalDuration(0, _sign_, 0, 0, 0, 0, 0, 0, 0, 0). 1. Let _oneWeek_ be ! CreateTemporalDuration(0, 0, _sign_, 0, 0, 0, 0, 0, 0, 0). - 1. If _relativeTo_ is not *undefined*, then - 1. Set _relativeTo_ to ? ToTemporalDate(_relativeTo_). - 1. Let _calendar_ be _relativeTo_.[[Calendar]]. + 1. If _plainRelativeTo_ is not *undefined*, then + 1. Let _calendar_ be _plainRelativeTo_.[[Calendar]]. 1. Else, 1. Let _calendar_ be *undefined*. 1. If _largestUnit_ is *"month"*, then + 1. If _years_ = 0, return ? CreateDateDurationRecord(0, _months_, _weeks_, _days_). 1. If _calendar_ is *undefined*, then 1. Throw a *RangeError* exception. 1. If _calendar_ is an Object, then @@ -1389,15 +1401,16 @@

1. Let _dateAdd_ be ~unused~. 1. Let _dateUntil_ be ~unused~. 1. Repeat, while _years_ ≠ 0, - 1. Let _newRelativeTo_ be ? CalendarDateAdd(_calendar_, _relativeTo_, _oneYear_, *undefined*, _dateAdd_). + 1. Let _newRelativeTo_ be ? CalendarDateAdd(_calendar_, _plainRelativeTo_, _oneYear_, *undefined*, _dateAdd_). 1. Let _untilOptions_ be OrdinaryObjectCreate(*null*). 1. Perform ! CreateDataPropertyOrThrow(_untilOptions_, *"largestUnit"*, *"month"*). - 1. Let _untilResult_ be ? CalendarDateUntil(_calendar_, _relativeTo_, _newRelativeTo_, _untilOptions_, _dateUntil_). + 1. Let _untilResult_ be ? CalendarDateUntil(_calendar_, _plainRelativeTo_, _newRelativeTo_, _untilOptions_, _dateUntil_). 1. Let _oneYearMonths_ be _untilResult_.[[Months]]. - 1. Set _relativeTo_ to _newRelativeTo_. + 1. Set _plainRelativeTo_ to _newRelativeTo_. 1. Set _years_ to _years_ - _sign_. 1. Set _months_ to _months_ + _oneYearMonths_. 1. Else if _largestUnit_ is *"week"*, then + 1. If _years_ = 0 and _months_ = 0, return ? CreateDateDurationRecord(0, 0, _weeks_, _days_). 1. If _calendar_ is *undefined*, then 1. Throw a *RangeError* exception. 1. If _calendar_ is an Object, then @@ -1405,13 +1418,13 @@

1. Else, 1. Let _dateAdd_ be ~unused~. 1. Repeat, while _years_ ≠ 0, - 1. Let _moveResult_ be ? MoveRelativeDate(_calendar_, _relativeTo_, _oneYear_, _dateAdd_). - 1. Set _relativeTo_ to _moveResult_.[[RelativeTo]]. + 1. Let _moveResult_ be ? MoveRelativeDate(_calendar_, _plainRelativeTo_, _oneYear_, _dateAdd_). + 1. Set _plainRelativeTo_ to _moveResult_.[[RelativeTo]]. 1. Set _days_ to _days_ + _moveResult_.[[Days]]. 1. Set _years_ to _years_ - _sign_. 1. Repeat, while _months_ ≠ 0, - 1. Let _moveResult_ be ? MoveRelativeDate(_calendar_, _relativeTo_, _oneMonth_, _dateAdd_). - 1. Set _relativeTo_ to _moveResult_.[[RelativeTo]]. + 1. Let _moveResult_ be ? MoveRelativeDate(_calendar_, _plainRelativeTo_, _oneMonth_, _dateAdd_). + 1. Set _plainRelativeTo_ to _moveResult_.[[RelativeTo]]. 1. Set _days_ to _days_ + _moveResult_.[[Days]]. 1. Set _months_ to _months_ - _sign_. 1. Else, @@ -1423,18 +1436,18 @@

1. Else, 1. Let _dateAdd_ be ~unused~. 1. Repeat, while _years_ ≠ 0, - 1. Let _moveResult_ be ? MoveRelativeDate(_calendar_, _relativeTo_, _oneYear_, _dateAdd_). - 1. Set _relativeTo_ to _moveResult_.[[RelativeTo]]. + 1. Let _moveResult_ be ? MoveRelativeDate(_calendar_, _plainRelativeTo_, _oneYear_, _dateAdd_). + 1. Set _plainRelativeTo_ to _moveResult_.[[RelativeTo]]. 1. Set _days_ to _days_ + _moveResult_.[[Days]]. 1. Set _years_ to _years_ - _sign_. 1. Repeat, while _months_ ≠ 0, - 1. Let _moveResult_ be ? MoveRelativeDate(_calendar_, _relativeTo_, _oneMonth_, _dateAdd_). - 1. Set _relativeTo_ to _moveResult_.[[RelativeTo]]. + 1. Let _moveResult_ be ? MoveRelativeDate(_calendar_, _plainRelativeTo_, _oneMonth_, _dateAdd_). + 1. Set _plainRelativeTo_ to _moveResult_.[[RelativeTo]]. 1. Set _days_ to _days_ +_moveResult_.[[Days]]. 1. Set _months_ to _months_ - _sign_. 1. Repeat, while _weeks_ ≠ 0, - 1. Let _moveResult_ be ? MoveRelativeDate(_calendar_, _relativeTo_, _oneWeek_, _dateAdd_). - 1. Set _relativeTo_ to _moveResult_.[[RelativeTo]]. + 1. Let _moveResult_ be ? MoveRelativeDate(_calendar_, _plainRelativeTo_, _oneWeek_, _dateAdd_). + 1. Set _plainRelativeTo_ to _moveResult_.[[RelativeTo]]. 1. Set _days_ to _days_ + _moveResult_.[[Days]]. 1. Set _weeks_ to _weeks_ - _sign_. 1. Return ? CreateDateDurationRecord(_years_, _months_, _weeks_, _days_). @@ -1449,7 +1462,7 @@

_weeks_: an integer, _days_: an integer, _largestUnit_: a String, - _relativeTo_: *undefined*, a Temporal.PlainDate, or a Temporal.ZonedDateTime, + _plainRelativeTo_: *undefined* or a Temporal.PlainDate, )

@@ -1461,71 +1474,70 @@

1. If _years_ = 0, and _months_ = 0, and _weeks_ = 0, and _days_ = 0, set _allZero_ to *true*. 1. If _largestUnit_ is not one of *"year"*, *"month"*, or *"week"*, or _allZero_ is *true*, then 1. Return ! CreateDateDurationRecord(_years_, _months_, _weeks_, _days_). - 1. If _relativeTo_ is *undefined*, then + 1. If _plainRelativeTo_ is *undefined*, then 1. Throw a *RangeError* exception. 1. Let _sign_ be ! DurationSign(_years_, _months_, _weeks_, _days_, 0, 0, 0, 0, 0, 0). 1. Assert: _sign_ ≠ 0. 1. Let _oneYear_ be ! CreateTemporalDuration(_sign_, 0, 0, 0, 0, 0, 0, 0, 0, 0). 1. Let _oneMonth_ be ! CreateTemporalDuration(0, _sign_, 0, 0, 0, 0, 0, 0, 0, 0). 1. Let _oneWeek_ be ! CreateTemporalDuration(0, 0, _sign_, 0, 0, 0, 0, 0, 0, 0). - 1. Set _relativeTo_ to ? ToTemporalDate(_relativeTo_). - 1. Let _calendar_ be _relativeTo_.[[Calendar]]. + 1. Let _calendar_ be _plainRelativeTo_.[[Calendar]]. 1. If _largestUnit_ is *"year"*, then 1. If _calendar_ is an Object, then 1. Let _dateAdd_ be ? GetMethod(_calendar_, *"dateAdd"*). 1. Else, 1. Let _dateAdd_ be ~unused~. - 1. Let _moveResult_ be ? MoveRelativeDate(_calendar_, _relativeTo_, _oneYear_, _dateAdd_). + 1. Let _moveResult_ be ? MoveRelativeDate(_calendar_, _plainRelativeTo_, _oneYear_, _dateAdd_). 1. Let _newRelativeTo_ be _moveResult_.[[RelativeTo]]. 1. Let _oneYearDays_ be _moveResult_.[[Days]]. 1. Repeat, while abs(_days_) ≥ abs(_oneYearDays_), 1. Set _days_ to _days_ - _oneYearDays_. 1. Set _years_ to _years_ + _sign_. - 1. Set _relativeTo_ to _newRelativeTo_. - 1. Set _moveResult_ to ? MoveRelativeDate(_calendar_, _relativeTo_, _oneYear_, _dateAdd_). + 1. Set _plainRelativeTo_ to _newRelativeTo_. + 1. Set _moveResult_ to ? MoveRelativeDate(_calendar_, _plainRelativeTo_, _oneYear_, _dateAdd_). 1. Set _newRelativeTo_ to _moveResult_.[[RelativeTo]]. 1. Set _oneYearDays_ to _moveResult_.[[Days]]. - 1. Set _moveResult_ to ? MoveRelativeDate(_calendar_, _relativeTo_, _oneMonth_, _dateAdd_). + 1. Set _moveResult_ to ? MoveRelativeDate(_calendar_, _plainRelativeTo_, _oneMonth_, _dateAdd_). 1. Set _newRelativeTo_ to _moveResult_.[[RelativeTo]]. 1. Let _oneMonthDays_ be _moveResult_.[[Days]]. 1. Repeat, while abs(_days_) ≥ abs(_oneMonthDays_), 1. Set _days_ to _days_ - _oneMonthDays_. 1. Set _months_ to _months_ + _sign_. - 1. Set _relativeTo_ to _newRelativeTo_. - 1. Set _moveResult_ to ? MoveRelativeDate(_calendar_, _relativeTo_, _oneMonth_, _dateAdd_). + 1. Set _plainRelativeTo_ to _newRelativeTo_. + 1. Set _moveResult_ to ? MoveRelativeDate(_calendar_, _plainRelativeTo_, _oneMonth_, _dateAdd_). 1. Set _newRelativeTo_ to _moveResult_.[[RelativeTo]]. 1. Set _oneMonthDays_ to _moveResult_.[[Days]]. - 1. Set _newRelativeTo_ to ? CalendarDateAdd(_calendar_, _relativeTo_, _oneYear_, *undefined*, _dateAdd_). + 1. Set _newRelativeTo_ to ? CalendarDateAdd(_calendar_, _plainRelativeTo_, _oneYear_, *undefined*, _dateAdd_). 1. If _calendar_ is an Object, then 1. Let _dateUntil_ be ? GetMethod(_calendar_, *"dateUntil"*). 1. Else, 1. Let _dateUntil_ be ~unused~. 1. Let _untilOptions_ be OrdinaryObjectCreate(*null*). 1. Perform ! CreateDataPropertyOrThrow(_untilOptions_, *"largestUnit"*, *"month"*). - 1. Let _untilResult_ be ? CalendarDateUntil(_calendar_, _relativeTo_, _newRelativeTo_, _untilOptions_, _dateUntil_). + 1. Let _untilResult_ be ? CalendarDateUntil(_calendar_, _plainRelativeTo_, _newRelativeTo_, _untilOptions_, _dateUntil_). 1. Let _oneYearMonths_ be _untilResult_.[[Months]]. 1. Repeat, while abs(_months_) ≥ abs(_oneYearMonths_), 1. Set _months_ to _months_ - _oneYearMonths_. 1. Set _years_ to _years_ + _sign_. - 1. Set _relativeTo_ to _newRelativeTo_. - 1. Set _newRelativeTo_ to ? CalendarDateAdd(_calendar_, _relativeTo_, _oneYear_, *undefined*, _dateAdd_). + 1. Set _plainRelativeTo_ to _newRelativeTo_. + 1. Set _newRelativeTo_ to ? CalendarDateAdd(_calendar_, _plainRelativeTo_, _oneYear_, *undefined*, _dateAdd_). 1. Set _untilOptions_ to OrdinaryObjectCreate(*null*). 1. Perform ! CreateDataPropertyOrThrow(_untilOptions_, *"largestUnit"*, *"month"*). - 1. Set _untilResult_ to ? CalendarDateUntil(_calendar_, _relativeTo_, _newRelativeTo_, _untilOptions_, _dateUntil_). + 1. Set _untilResult_ to ? CalendarDateUntil(_calendar_, _plainRelativeTo_, _newRelativeTo_, _untilOptions_, _dateUntil_). 1. Set _oneYearMonths_ to _untilResult_.[[Months]]. 1. Else if _largestUnit_ is *"month"*, then 1. If _calendar_ is an Object, then 1. Let _dateAdd_ be ? GetMethod(_calendar_, *"dateAdd"*). 1. Else, 1. Let _dateAdd_ be ~unused~. - 1. Let _moveResult_ be ? MoveRelativeDate(_calendar_, _relativeTo_, _oneMonth_, _dateAdd_). + 1. Let _moveResult_ be ? MoveRelativeDate(_calendar_, _plainRelativeTo_, _oneMonth_, _dateAdd_). 1. Let _newRelativeTo_ be _moveResult_.[[RelativeTo]]. 1. Let _oneMonthDays_ be _moveResult_.[[Days]]. 1. Repeat, while abs(_days_) ≥ abs(_oneMonthDays_), 1. Set _days_ to _days_ - _oneMonthDays_. 1. Set _months_ to _months_ + _sign_. - 1. Set _relativeTo_ to _newRelativeTo_. - 1. Set _moveResult_ to ? MoveRelativeDate(_calendar_, _relativeTo_, _oneMonth_, _dateAdd_). + 1. Set _plainRelativeTo_ to _newRelativeTo_. + 1. Set _moveResult_ to ? MoveRelativeDate(_calendar_, _plainRelativeTo_, _oneMonth_, _dateAdd_). 1. Set _newRelativeTo_ to _moveResult_.[[RelativeTo]]. 1. Set _oneMonthDays_ to _moveResult_.[[Days]]. 1. Else, @@ -1534,14 +1546,14 @@

1. Let _dateAdd_ be ? GetMethod(_calendar_, *"dateAdd"*). 1. Else, 1. Let _dateAdd_ be ~unused~. - 1. Let _moveResult_ be ? MoveRelativeDate(_calendar_, _relativeTo_, _oneWeek_, _dateAdd_). + 1. Let _moveResult_ be ? MoveRelativeDate(_calendar_, _plainRelativeTo_, _oneWeek_, _dateAdd_). 1. Let _newRelativeTo_ be _moveResult_.[[RelativeTo]]. 1. Let _oneWeekDays_ be _moveResult_.[[Days]]. 1. Repeat, while abs(_days_) ≥ abs(_oneWeekDays_), 1. Set _days_ to _days_ - _oneWeekDays_. 1. Set _weeks_ to _weeks_ + _sign_. - 1. Set _relativeTo_ to _newRelativeTo_. - 1. Set _moveResult_ to ? MoveRelativeDate(_calendar_, _relativeTo_, _oneWeek_, _dateAdd_). + 1. Set _plainRelativeTo_ to _newRelativeTo_. + 1. Set _moveResult_ to ? MoveRelativeDate(_calendar_, _plainRelativeTo_, _oneWeek_, _dateAdd_). 1. Set _newRelativeTo_ to _moveResult_.[[RelativeTo]]. 1. Set _oneWeekDays_ to _moveResult_.[[Days]]. 1. Return ! CreateDateDurationRecord(_years_, _months_, _weeks_, _days_). @@ -1571,47 +1583,49 @@

_ms2_: an integer, _mus2_: an integer, _ns2_: an integer, - _relativeTo_: *undefined*, a Temporal.PlainDate, or a Temporal.ZonedDateTime, + _plainRelativeTo_: a Temporal.PlainDate or *undefined*, + _zonedRelativeTo_: a Temporal.ZonedDateTime or *undefined*, ): either a normal completion containing a Duration Record, or a throw completion

description
-
It adds the components of a second duration represented by _y2_ through _ns2_ to those of a first duration represented by _y1_ through _ns1_, and balances the duration relative to the given date _relativeTo_, to ensure that no mixed signs remain in the result.
+
It adds the components of a second duration represented by _y2_ through _ns2_ to those of a first duration represented by _y1_ through _ns1_, and balances the duration relative to the given date _zonedRelativeTo_ or _plainRelativeTo_, to ensure that no mixed signs remain in the result.
1. Let _largestUnit1_ be ! DefaultTemporalLargestUnit(_y1_, _mon1_, _w1_, _d1_, _h1_, _min1_, _s1_, _ms1_, _mus1_). 1. Let _largestUnit2_ be ! DefaultTemporalLargestUnit(_y2_, _mon2_, _w2_, _d2_, _h2_, _min2_, _s2_, _ms2_, _mus2_). 1. Let _largestUnit_ be ! LargerOfTwoTemporalUnits(_largestUnit1_, _largestUnit2_). - 1. If _relativeTo_ is *undefined*, then + 1. If _zonedRelativeTo_ is *undefined* and _plainRelativeTo_ is *undefined*, then 1. If _largestUnit_ is one of *"year"*, *"month"*, or *"week"*, then 1. Throw a *RangeError* exception. 1. Let _result_ be ? BalanceTimeDuration(_d1_ + _d2_, _h1_ + _h2_, _min1_ + _min2_, _s1_ + _s2_, _ms1_ + _ms2_, _mus1_ + _mus2_, _ns1_ + _ns2_, _largestUnit_). 1. Return ! CreateDurationRecord(0, 0, 0, _result_.[[Days]], _result_.[[Hours]], _result_.[[Minutes]], _result_.[[Seconds]], _result_.[[Milliseconds]], _result_.[[Microseconds]], _result_.[[Nanoseconds]]). - 1. If _relativeTo_ has an [[InitializedTemporalDate]] internal slot, then - 1. Let _calendar_ be _relativeTo_.[[Calendar]]. + 1. If _plainRelativeTo_ is not *undefined*, then + 1. Assert: _zonedRelativeTo_ is *undefined*. + 1. Let _calendar_ be _plainRelativeTo_.[[Calendar]]. 1. Let _dateDuration1_ be ! CreateTemporalDuration(_y1_, _mon1_, _w1_, _d1_, 0, 0, 0, 0, 0, 0). 1. Let _dateDuration2_ be ! CreateTemporalDuration(_y2_, _mon2_, _w2_, _d2_, 0, 0, 0, 0, 0, 0). 1. If _calendar_ is an Object, then 1. Let _dateAdd_ be ? GetMethod(_calendar_, *"dateAdd"*). 1. Else, 1. Let _dateAdd_ be ~unused~. - 1. Let _intermediate_ be ? CalendarDateAdd(_calendar_, _relativeTo_, _dateDuration1_, *undefined*, _dateAdd_). + 1. Let _intermediate_ be ? CalendarDateAdd(_calendar_, _plainRelativeTo_, _dateDuration1_, *undefined*, _dateAdd_). 1. Let _end_ be ? CalendarDateAdd(_calendar_, _intermediate_, _dateDuration2_, *undefined*, _dateAdd_). 1. Let _dateLargestUnit_ be ! LargerOfTwoTemporalUnits(*"day"*, _largestUnit_). 1. Let _differenceOptions_ be OrdinaryObjectCreate(*null*). 1. Perform ! CreateDataPropertyOrThrow(_differenceOptions_, *"largestUnit"*, _dateLargestUnit_). - 1. Let _dateDifference_ be ? CalendarDateUntil(_calendar_, _relativeTo_, _end_, _differenceOptions_). + 1. Let _dateDifference_ be ? CalendarDateUntil(_calendar_, _plainRelativeTo_, _end_, _differenceOptions_). 1. Let _result_ be ? BalanceTimeDuration(_dateDifference_.[[Days]], _h1_ + _h2_, _min1_ + _min2_, _s1_ + _s2_, _ms1_ + _ms2_, _mus1_ + _mus2_, _ns1_ + _ns2_, _largestUnit_). 1. Return ! CreateDurationRecord(_dateDifference_.[[Years]], _dateDifference_.[[Months]], _dateDifference_.[[Weeks]], _result_.[[Days]], _result_.[[Hours]], _result_.[[Minutes]], _result_.[[Seconds]], _result_.[[Milliseconds]], _result_.[[Microseconds]], _result_.[[Nanoseconds]]). - 1. Assert: _relativeTo_ has an [[InitializedTemporalZonedDateTime]] internal slot. - 1. Let _timeZone_ be _relativeTo_.[[TimeZone]]. - 1. Let _calendar_ be _relativeTo_.[[Calendar]]. - 1. Let _intermediateNs_ be ? AddZonedDateTime(_relativeTo_.[[Nanoseconds]], _timeZone_, _calendar_, _y1_, _mon1_, _w1_, _d1_, _h1_, _min1_, _s1_, _ms1_, _mus1_, _ns1_). + 1. Assert: _zonedRelativeTo_ is not *undefined*. + 1. Let _timeZone_ be _zonedRelativeTo_.[[TimeZone]]. + 1. Let _calendar_ be _zonedRelativeTo_.[[Calendar]]. + 1. Let _intermediateNs_ be ? AddZonedDateTime(_zonedRelativeTo_.[[Nanoseconds]], _timeZone_, _calendar_, _y1_, _mon1_, _w1_, _d1_, _h1_, _min1_, _s1_, _ms1_, _mus1_, _ns1_). 1. Let _endNs_ be ? AddZonedDateTime(_intermediateNs_, _timeZone_, _calendar_, _y2_, _mon2_, _w2_, _d2_, _h2_, _min2_, _s2_, _ms2_, _mus2_, _ns2_). 1. If _largestUnit_ is not one of *"year"*, *"month"*, *"week"*, or *"day"*, then - 1. Let _result_ be DifferenceInstant(_relativeTo_.[[Nanoseconds]], _endNs_, 1, *"nanosecond"*, _largestUnit_, *"halfExpand"*). + 1. Let _result_ be DifferenceInstant(_zonedRelativeTo_.[[Nanoseconds]], _endNs_, 1, *"nanosecond"*, _largestUnit_, *"halfExpand"*). 1. Return ! CreateDurationRecord(0, 0, 0, 0, _result_.[[Hours]], _result_.[[Minutes]], _result_.[[Seconds]], _result_.[[Milliseconds]], _result_.[[Microseconds]], _result_.[[Nanoseconds]]). - 1. Return ? DifferenceZonedDateTime(_relativeTo_.[[Nanoseconds]], _endNs_, _timeZone_, _calendar_, _largestUnit_, OrdinaryObjectCreate(*null*)). + 1. Return ? DifferenceZonedDateTime(_zonedRelativeTo_.[[Nanoseconds]], _endNs_, _timeZone_, _calendar_, _largestUnit_, OrdinaryObjectCreate(*null*)). @@ -1696,7 +1710,8 @@

_increment_: an integer, _unit_: a String, _roundingMode_: a String, - optional _relativeTo_: *undefined*, a Temporal.PlainDate, or a Temporal.ZonedDateTime, + optional _plainRelativeTo_: *undefined* or a Temporal.PlainDate, + optional _zonedRelativeTo_: *undefined* or a Temporal.ZonedDateTime, ): either a normal completion containing a Record with fields [[DurationRecord]] (a Duration Record) and [[Total]] (a mathematical value), or a throw completion

@@ -1708,13 +1723,14 @@

- 1. If _relativeTo_ is not present, set _relativeTo_ to *undefined*. - 1. If _unit_ is *"year"*, *"month"*, or *"week"*, and _relativeTo_ is *undefined*, then + 1. If _plainRelativeTo_ is not present, set _plainRelativeTo_ to *undefined*. + 1. If _zonedRelativeTo_ is not present, set _zonedRelativeTo_ to *undefined*. + 1. If _unit_ is *"year"*, *"month"*, or *"week"*, and _plainRelativeTo_ is *undefined*, then 1. Throw a *RangeError* exception. 1. If _unit_ is one of *"year"*, *"month"*, *"week"*, or *"day"*, then 1. Let _nanoseconds_ be ! TotalDurationNanoseconds(0, _hours_, _minutes_, _seconds_, _milliseconds_, _microseconds_, _nanoseconds_, 0). - 1. If _relativeTo_ is an Object with an [[InitializedTemporalZonedDateTime]] internal slot, then - 1. Let _intermediate_ be ? MoveRelativeZonedDateTime(_relativeTo_, _years_, _months_, _weeks_, _days_). + 1. If _zonedRelativeTo_ is not *undefined*, then + 1. Let _intermediate_ be ? MoveRelativeZonedDateTime(_zonedRelativeTo_, _years_, _months_, _weeks_, _days_). 1. Let _result_ be ? NanosecondsToDays(_nanoseconds_, _intermediate_). 1. Let _fractionalDays_ be _days_ + _result_.[[Days]] + _result_.[[Nanoseconds]] / _result_.[[DayLength]]. 1. Else, @@ -1726,85 +1742,82 @@

1. Assert: _fractionalDays_ is not used below. 1. Let _total_ be ~unset~. 1. If _unit_ is *"year"*, then - 1. Set _relativeTo_ to ? ToTemporalDate(_relativeTo_). - 1. Let _calendar_ be _relativeTo_.[[Calendar]]. + 1. Let _calendar_ be _plainRelativeTo_.[[Calendar]]. 1. Let _yearsDuration_ be ! CreateTemporalDuration(_years_, 0, 0, 0, 0, 0, 0, 0, 0, 0). 1. If _calendar_ is an Object, then 1. Let _dateAdd_ be ? GetMethod(_calendar_, *"dateAdd"*). 1. Else, 1. Let _dateAdd_ be ~unused~. - 1. Let _yearsLater_ be ? CalendarDateAdd(_calendar_, _relativeTo_, _yearsDuration_, *undefined*, _dateAdd_). + 1. Let _yearsLater_ be ? CalendarDateAdd(_calendar_, _plainRelativeTo_, _yearsDuration_, *undefined*, _dateAdd_). 1. Let _yearsMonthsWeeks_ be ! CreateTemporalDuration(_years_, _months_, _weeks_, 0, 0, 0, 0, 0, 0, 0). - 1. Let _yearsMonthsWeeksLater_ be ? CalendarDateAdd(_calendar_, _relativeTo_, _yearsMonthsWeeks_, *undefined*, _dateAdd_). + 1. Let _yearsMonthsWeeksLater_ be ? CalendarDateAdd(_calendar_, _plainRelativeTo_, _yearsMonthsWeeks_, *undefined*, _dateAdd_). 1. Let _monthsWeeksInDays_ be DaysUntil(_yearsLater_, _yearsMonthsWeeksLater_). - 1. Set _relativeTo_ to _yearsLater_. + 1. Set _plainRelativeTo_ to _yearsLater_. 1. Set _fractionalDays_ to _fractionalDays_ + _monthsWeeksInDays_. - 1. Let _wholeDaysDuration_ be ? CreateTemporalDuration(0, 0, 0, truncate(_fractionalDays_), 0, 0, 0, 0, 0, 0). - 1. Let _wholeDaysLater_ be ? CalendarDateAdd(_calendar_, _relativeTo_, _wholeDaysDuration_, *undefined*, _dateAdd_). + 1. Let _wholeDaysDuration_ be ? CreateTemporalDuration(0, 0, 0, truncate(_days_), 0, 0, 0, 0, 0, 0). + 1. Let _wholeDaysLater_ be ? CalendarDateAdd(_calendar_, _plainRelativeTo_, _wholeDaysDuration_, *undefined*, _dateAdd_). 1. Let _untilOptions_ be OrdinaryObjectCreate(*null*). 1. Perform ! CreateDataPropertyOrThrow(_untilOptions_, *"largestUnit"*, *"year"*). - 1. Let _timePassed_ be ? CalendarDateUntil(_calendar_, _relativeTo_, _wholeDaysLater_, _untilOptions_). + 1. Let _timePassed_ be ? CalendarDateUntil(_calendar_, _plainRelativeTo_, _wholeDaysLater_, _untilOptions_). 1. Let _yearsPassed_ be _timePassed_.[[Years]]. 1. Set _years_ to _years_ + _yearsPassed_. 1. Let _yearsDuration_ be ! CreateTemporalDuration(_yearsPassed_, 0, 0, 0, 0, 0, 0, 0, 0, 0). - 1. Let _moveResult_ be ? MoveRelativeDate(_calendar_, _relativeTo_, _yearsDuration_, _dateAdd_). - 1. Set _relativeTo_ to _moveResult_.[[RelativeTo]]. + 1. Let _moveResult_ be ? MoveRelativeDate(_calendar_, _plainRelativeTo_, _yearsDuration_, _dateAdd_). + 1. Set _plainRelativeTo_ to _moveResult_.[[RelativeTo]]. 1. Let _daysPassed_ be _moveResult_.[[Days]]. 1. Set _fractionalDays_ to _fractionalDays_ - _daysPassed_. 1. If _fractionalDays_ < 0, let _sign_ be -1; else, let _sign_ be 1. 1. Let _oneYear_ be ! CreateTemporalDuration(_sign_, 0, 0, 0, 0, 0, 0, 0, 0, 0). - 1. Set _moveResult_ to ? MoveRelativeDate(_calendar_, _relativeTo_, _oneYear_, _dateAdd_). + 1. Set _moveResult_ to ? MoveRelativeDate(_calendar_, _plainRelativeTo_, _oneYear_, _dateAdd_). 1. Let _oneYearDays_ be _moveResult_.[[Days]]. 1. Let _fractionalYears_ be _years_ + _fractionalDays_ / abs(_oneYearDays_). 1. Set _years_ to RoundNumberToIncrement(_fractionalYears_, _increment_, _roundingMode_). 1. Set _total_ to _fractionalYears_. 1. Set _months_ and _weeks_ to 0. 1. Else if _unit_ is *"month"*, then - 1. Set _relativeTo_ to ? ToTemporalDate(_relativeTo_). - 1. Let _calendar_ be _relativeTo_.[[Calendar]]. + 1. Let _calendar_ be _plainRelativeTo_.[[Calendar]]. 1. Let _yearsMonths_ be ! CreateTemporalDuration(_years_, _months_, 0, 0, 0, 0, 0, 0, 0, 0). 1. If _calendar_ is an Object, then 1. Let _dateAdd_ be ? GetMethod(_calendar_, *"dateAdd"*). 1. Else, 1. Let _dateAdd_ be ~unused~. - 1. Let _yearsMonthsLater_ be ? CalendarDateAdd(_calendar_, _relativeTo_, _yearsMonths_, *undefined*, _dateAdd_). + 1. Let _yearsMonthsLater_ be ? CalendarDateAdd(_calendar_, _plainRelativeTo_, _yearsMonths_, *undefined*, _dateAdd_). 1. Let _yearsMonthsWeeks_ be ! CreateTemporalDuration(_years_, _months_, _weeks_, 0, 0, 0, 0, 0, 0, 0). - 1. Let _yearsMonthsWeeksLater_ be ? CalendarDateAdd(_calendar_, _relativeTo_, _yearsMonthsWeeks_, *undefined*, _dateAdd_). + 1. Let _yearsMonthsWeeksLater_ be ? CalendarDateAdd(_calendar_, _plainRelativeTo_, _yearsMonthsWeeks_, *undefined*, _dateAdd_). 1. Let _weeksInDays_ be DaysUntil(_yearsMonthsLater_, _yearsMonthsWeeksLater_). - 1. Set _relativeTo_ to _yearsMonthsLater_. + 1. Set _plainRelativeTo_ to _yearsMonthsLater_. 1. Set _fractionalDays_ to _fractionalDays_ + _weeksInDays_. 1. If _fractionalDays_ < 0, let _sign_ be -1; else, let _sign_ be 1. 1. Let _oneMonth_ be ! CreateTemporalDuration(0, _sign_, 0, 0, 0, 0, 0, 0, 0, 0). - 1. Let _moveResult_ be ? MoveRelativeDate(_calendar_, _relativeTo_, _oneMonth_, _dateAdd_). - 1. Set _relativeTo_ to _moveResult_.[[RelativeTo]]. + 1. Let _moveResult_ be ? MoveRelativeDate(_calendar_, _plainRelativeTo_, _oneMonth_, _dateAdd_). + 1. Set _plainRelativeTo_ to _moveResult_.[[RelativeTo]]. 1. Let _oneMonthDays_ be _moveResult_.[[Days]]. 1. Repeat, while abs(_fractionalDays_) ≥ abs(_oneMonthDays_), 1. Set _months_ to _months_ + _sign_. 1. Set _fractionalDays_ to _fractionalDays_ - _oneMonthDays_. - 1. Set _moveResult_ to ? MoveRelativeDate(_calendar_, _relativeTo_, _oneMonth_, _dateAdd_). - 1. Set _relativeTo_ to _moveResult_.[[RelativeTo]]. + 1. Set _moveResult_ to ? MoveRelativeDate(_calendar_, _plainRelativeTo_, _oneMonth_, _dateAdd_). + 1. Set _plainRelativeTo_ to _moveResult_.[[RelativeTo]]. 1. Set _oneMonthDays_ to _moveResult_.[[Days]]. 1. Let _fractionalMonths_ be _months_ + _fractionalDays_ / abs(_oneMonthDays_). 1. Set _months_ to RoundNumberToIncrement(_fractionalMonths_, _increment_, _roundingMode_). 1. Set _total_ to _fractionalMonths_. 1. Set _weeks_ to 0. 1. Else if _unit_ is *"week"*, then - 1. Set _relativeTo_ to ? ToTemporalDate(_relativeTo_). - 1. Let _calendar_ be _relativeTo_.[[Calendar]]. + 1. Let _calendar_ be _plainRelativeTo_.[[Calendar]]. 1. If _fractionalDays_ < 0, let _sign_ be -1; else, let _sign_ be 1. 1. Let _oneWeek_ be ! CreateTemporalDuration(0, 0, _sign_, 0, 0, 0, 0, 0, 0, 0). 1. If _calendar_ is an Object, then 1. Let _dateAdd_ be ? GetMethod(_calendar_, *"dateAdd"*). 1. Else, 1. Let _dateAdd_ be ~unused~. - 1. Let _moveResult_ be ? MoveRelativeDate(_calendar_, _relativeTo_, _oneWeek_, _dateAdd_). - 1. Set _relativeTo_ to _moveResult_.[[RelativeTo]]. + 1. Let _moveResult_ be ? MoveRelativeDate(_calendar_, _plainRelativeTo_, _oneWeek_, _dateAdd_). + 1. Set _plainRelativeTo_ to _moveResult_.[[RelativeTo]]. 1. Let _oneWeekDays_ be _moveResult_.[[Days]]. 1. Repeat, while abs(_fractionalDays_) ≥ abs(_oneWeekDays_), 1. Set _weeks_ to _weeks_ + _sign_. 1. Set _fractionalDays_ to _fractionalDays_ - _oneWeekDays_. - 1. Set _moveResult_ to ? MoveRelativeDate(_calendar_, _relativeTo_, _oneWeek_, _dateAdd_). - 1. Set _relativeTo_ to _moveResult_.[[RelativeTo]]. + 1. Set _moveResult_ to ? MoveRelativeDate(_calendar_, _plainRelativeTo_, _oneWeek_, _dateAdd_). + 1. Set _plainRelativeTo_ to _moveResult_.[[RelativeTo]]. 1. Set _oneWeekDays_ to _moveResult_.[[Days]]. 1. Let _fractionalWeeks_ be _weeks_ + _fractionalDays_ / abs(_oneWeekDays_). 1. Set _weeks_ to RoundNumberToIncrement(_fractionalWeeks_, _increment_, _roundingMode_). @@ -1864,7 +1877,7 @@

_increment_: an integer, _unit_: a String, _roundingMode_: a String, - _relativeTo_: *undefined*, a Temporal.PlainDate, or a Temporal.ZonedDateTime, + _zonedRelativeTo_: a Temporal.ZonedDateTime, ): either a normal completion containing a Duration Record, or a throw completion

@@ -1876,19 +1889,19 @@

- 1. If Type(_relativeTo_) is not Object; or _relativeTo_ does not have an [[InitializedTemporalZonedDateTime]] internal slot; or _unit_ is one of *"year"*, *"month"*, *"week"*, or *"day"*; or _unit_ is *"nanosecond"* and _increment_ is 1, then + 1. If _unit_ is one of *"year"*, *"month"*, *"week"*, or *"day"*; or _unit_ is *"nanosecond"* and _increment_ is 1, then 1. Return ! CreateDurationRecord(_years_, _months_, _weeks_, _days_, _hours_, _minutes_, _seconds_, _milliseconds_, _microseconds_, _nanoseconds_). 1. Let _timeRemainderNs_ be ! TotalDurationNanoseconds(0, _hours_, _minutes_, _seconds_, _milliseconds_, _microseconds_, _nanoseconds_, 0). 1. If _timeRemainderNs_ = 0, let _direction_ be 0. 1. Else if _timeRemainderNs_ < 0, let _direction_ be -1. 1. Else, let _direction_ be 1. - 1. Let _dayStart_ be ? AddZonedDateTime(_relativeTo_.[[Nanoseconds]], _relativeTo_.[[TimeZone]], _relativeTo_.[[Calendar]], _years_, _months_, _weeks_, _days_, 0, 0, 0, 0, 0, 0). - 1. Let _dayEnd_ be ? AddZonedDateTime(_dayStart_, _relativeTo_.[[TimeZone]], _relativeTo_.[[Calendar]], 0, 0, 0, _direction_, 0, 0, 0, 0, 0, 0). + 1. Let _dayStart_ be ? AddZonedDateTime(_zonedRelativeTo_.[[Nanoseconds]], _zonedRelativeTo_.[[TimeZone]], _zonedRelativeTo_.[[Calendar]], _years_, _months_, _weeks_, _days_, 0, 0, 0, 0, 0, 0). + 1. Let _dayEnd_ be ? AddZonedDateTime(_dayStart_, _zonedRelativeTo_.[[TimeZone]], _zonedRelativeTo_.[[Calendar]], 0, 0, 0, _direction_, 0, 0, 0, 0, 0, 0). 1. Let _dayLengthNs_ be ℝ(_dayEnd_ - _dayStart_). 1. Let _oneDayLess_ be _timeRemainderNs_ - _dayLengthNs_. 1. If _oneDayLess_ × _direction_ < 0, then 1. Return ! CreateDurationRecord(_years_, _months_, _weeks_, _days_, _hours_, _minutes_, _seconds_, _milliseconds_, _microseconds_, _nanoseconds_). - 1. Let _adjustedDateDuration_ be ? AddDuration(_years_, _months_, _weeks_, _days_, 0, 0, 0, 0, 0, 0, 0, 0, 0, _direction_, 0, 0, 0, 0, 0, 0, _relativeTo_). + 1. Let _adjustedDateDuration_ be ? AddDuration(_years_, _months_, _weeks_, _days_, 0, 0, 0, 0, 0, 0, 0, 0, 0, _direction_, 0, 0, 0, 0, 0, 0, *undefined*, _zonedRelativeTo_). 1. Let _adjustedTimeDuration_ be ! RoundDuration(_adjustedDateDuration_.[[Years]], _adjustedDateDuration_.[[Months]], _adjustedDateDuration_.[[Weeks]], _adjustedDateDuration_.[[Days]], 0, 0, 0, 0, 0, _oneDayLess_, _increment_, _unit_, _roundingMode_). 1. Set _adjustedTimeDuration_ to ? BalanceTimeDuration(0, _adjustedTimeDuration_.[[Hours]], _adjustedTimeDuration_.[[Minutes]], _adjustedTimeDuration_.[[Seconds]], _adjustedTimeDuration_.[[Milliseconds]], _adjustedTimeDuration_.[[Microseconds]], _adjustedTimeDuration_.[[Nanoseconds]], *"hour"*). 1. Return ! CreateDurationRecord(_adjustedDateDuration_.[[Years]], _adjustedDateDuration_.[[Months]], _adjustedDateDuration_.[[Weeks]], _adjustedDateDuration_.[[Days]], _adjustedTimeDuration_.[[Hours]], _adjustedTimeDuration_.[[Minutes]], _adjustedTimeDuration_.[[Seconds]], _adjustedTimeDuration_.[[Milliseconds]], _adjustedTimeDuration_.[[Microseconds]], _adjustedTimeDuration_.[[Nanoseconds]]). @@ -1971,8 +1984,8 @@

1. If _operation_ is ~subtract~, let _sign_ be -1. Otherwise, let _sign_ be 1. 1. Set _other_ to ? ToTemporalDurationRecord(_other_). 1. Set _options_ to ? GetOptionsObject(_options_). - 1. Let _relativeTo_ be ? ToRelativeTemporalObject(_options_). - 1. Let _result_ be ? AddDuration(_duration_.[[Years]], _duration_.[[Months]], _duration_.[[Weeks]], _duration_.[[Days]], _duration_.[[Hours]], _duration_.[[Minutes]], _duration_.[[Seconds]], _duration_.[[Milliseconds]], _duration_.[[Microseconds]], _duration_.[[Nanoseconds]], _sign_ × _other_.[[Years]], _sign_ × _other_.[[Months]], _sign_ × _other_.[[Weeks]], _sign_ × _other_.[[Days]], _sign_ × _other_.[[Hours]], _sign_ × _other_.[[Minutes]], _sign_ × _other_.[[Seconds]], _sign_ × _other_.[[Milliseconds]], _sign_ × _other_.[[Microseconds]], _sign_ × _other_.[[Nanoseconds]], _relativeTo_). + 1. Let _relativeToRecord_ be ? ToRelativeTemporalObject(_options_). + 1. Let _result_ be ? AddDuration(_duration_.[[Years]], _duration_.[[Months]], _duration_.[[Weeks]], _duration_.[[Days]], _duration_.[[Hours]], _duration_.[[Minutes]], _duration_.[[Seconds]], _duration_.[[Milliseconds]], _duration_.[[Microseconds]], _duration_.[[Nanoseconds]], _sign_ × _other_.[[Years]], _sign_ × _other_.[[Months]], _sign_ × _other_.[[Weeks]], _sign_ × _other_.[[Days]], _sign_ × _other_.[[Hours]], _sign_ × _other_.[[Minutes]], _sign_ × _other_.[[Seconds]], _sign_ × _other_.[[Milliseconds]], _sign_ × _other_.[[Microseconds]], _sign_ × _other_.[[Nanoseconds]], _relativeToRecord_.[[PlainRelativeTo]], _relativeToRecord_.[[ZonedRelativeTo]]). 1. Return ! CreateTemporalDuration(_result_.[[Years]], _result_.[[Months]], _result_.[[Weeks]], _result_.[[Days]], _result_.[[Hours]], _result_.[[Minutes]], _result_.[[Seconds]], _result_.[[Milliseconds]], _result_.[[Microseconds]], _result_.[[Nanoseconds]]). diff --git a/spec/zoneddatetime.html b/spec/zoneddatetime.html index 8cf1e2ea3c..db120eedf4 100644 --- a/spec/zoneddatetime.html +++ b/spec/zoneddatetime.html @@ -1360,7 +1360,7 @@

description
- It converts a number of _nanoseconds_ relative to a Temporal.ZonedDateTime _relativeTo_, and converts it into a number of days and remainder of nanoseconds, taking into account any offset changes in the time zone of _relativeTo_. + It converts a number of _nanoseconds_ relative to a Temporal.ZonedDateTime _zonedRelativeTo_ (if supplied), and converts it into a number of days and remainder of nanoseconds, taking into account any offset changes in the time zone of _zonedRelativeTo_. It also returns the length of the last day in nanoseconds, for rounding purposes.
@@ -1370,12 +1370,12 @@

1. If _nanoseconds_ < 0, let _sign_ be -1; else, let _sign_ be 1. 1. Let _startNs_ be ℝ(_zonedRelativeTo_.[[Nanoseconds]]). 1. Let _startInstant_ be ! CreateTemporalInstant(ℤ(_startNs_)). - 1. Let _startDateTime_ be ? GetPlainDateTimeFor(_zonedRelativeTo_.[[TimeZone]], _startInstant_, _zonedRelativeTo_.[[Calendar]]). 1. Let _endNs_ be _startNs_ + _nanoseconds_. 1. If IsValidEpochNanoseconds(ℤ(_endNs_)) is *false*, throw a *RangeError* exception. 1. Let _endInstant_ be ! CreateTemporalInstant(ℤ(_endNs_)). + 1. Let _startDateTime_ be ? GetPlainDateTimeFor(_zonedRelativeTo_.[[TimeZone]], _startInstant_, _zonedRelativeTo_.[[Calendar]]). 1. Let _endDateTime_ be ? GetPlainDateTimeFor(_zonedRelativeTo_.[[TimeZone]], _endInstant_, _zonedRelativeTo_.[[Calendar]]). - 1. Let _dateDifference_ be ? DifferenceISODateTime(_startDateTime_.[[ISOYear]], _startDateTime_.[[ISOMonth]], _startDateTime_.[[ISODay]], _startDateTime_.[[ISOHour]], _startDateTime_.[[ISOMinute]], _startDateTime_.[[ISOSecond]], _startDateTime_.[[ISOMillisecond]], _startDateTime_.[[ISOMicrosecond]], _startDateTime_.[[ISONanosecond]], _endDateTime_.[[ISOYear]], _endDateTime_.[[ISOMonth]], _endDateTime_.[[ISODay]], _endDateTime_.[[ISOHour]], _endDateTime_.[[ISOMinute]], _endDateTime_.[[ISOSecond]], _endDateTime_.[[ISOMillisecond]], _endDateTime_.[[ISOMicrosecond]], _endDateTime_.[[ISONanosecond]], _relativeTo_.[[Calendar]], *"day"*, OrdinaryObjectCreate(*null*)). + 1. Let _dateDifference_ be ? DifferenceISODateTime(_startDateTime_.[[ISOYear]], _startDateTime_.[[ISOMonth]], _startDateTime_.[[ISODay]], _startDateTime_.[[ISOHour]], _startDateTime_.[[ISOMinute]], _startDateTime_.[[ISOSecond]], _startDateTime_.[[ISOMillisecond]], _startDateTime_.[[ISOMicrosecond]], _startDateTime_.[[ISONanosecond]], _endDateTime_.[[ISOYear]], _endDateTime_.[[ISOMonth]], _endDateTime_.[[ISODay]], _endDateTime_.[[ISOHour]], _endDateTime_.[[ISOMinute]], _endDateTime_.[[ISOSecond]], _endDateTime_.[[ISOMillisecond]], _endDateTime_.[[ISOMicrosecond]], _endDateTime_.[[ISONanosecond]], _zonedRelativeTo_.[[Calendar]], *"day"*, OrdinaryObjectCreate(*null*)). 1. Let _days_ be _dateDifference_.[[Days]]. 1. Let _intermediateNs_ be ℝ(? AddZonedDateTime(ℤ(_startNs_), _zonedRelativeTo_.[[TimeZone]], _zonedRelativeTo_.[[Calendar]], 0, 0, 0, _days_, 0, 0, 0, 0, 0, 0)). 1. If _sign_ is 1, then @@ -1436,7 +1436,11 @@

1. Let _difference_ be ? DifferenceZonedDateTime(_zonedDateTime_.[[Nanoseconds]], _other_.[[Nanoseconds]], _zonedDateTime_.[[TimeZone]], _zonedDateTime_.[[Calendar]], _settings_.[[LargestUnit]], _resolvedOptions_). 1. If _settings_.[[SmallestUnit]] is *"nanosecond"* and _settings_.[[RoundingIncrement]] is 1, then 1. Return ! CreateTemporalDuration(_sign_ × _difference_.[[Years]], _sign_ × _difference_.[[Months]], _sign_ × _difference_.[[Weeks]], _sign_ × _difference_.[[Days]], _sign_ × _difference_.[[Hours]], _sign_ × _difference_.[[Minutes]], _sign_ × _difference_.[[Seconds]], _sign_ × _difference_.[[Milliseconds]], _sign_ × _difference_.[[Microseconds]], _sign_ × _difference_.[[Nanoseconds]]). - 1. Let _roundRecord_ be ? RoundDuration(_difference_.[[Years]], _difference_.[[Months]], _difference_.[[Weeks]], _difference_.[[Days]], _difference_.[[Hours]], _difference_.[[Minutes]], _difference_.[[Seconds]], _difference_.[[Milliseconds]], _difference_.[[Microseconds]], _difference_.[[Nanoseconds]], _settings_.[[RoundingIncrement]], _settings_.[[SmallestUnit]], _settings_.[[RoundingMode]], _zonedDateTime_). + 1. Let _plainRelativeTo_ be *undefined*. + 1. If _settings_.[[SmallestUnit]] is one of *"year"*, *"month"*, *"week"*, then + 1. NOTE: The above condition means that the corresponding `Temporal.PlainDate` for _zonedDateTime_ will be used in one of the operations below. + 1. Set _plainRelativeTo_ to ? ToTemporalDate(_zonedDateTime_). + 1. Let _roundRecord_ be ? RoundDuration(_difference_.[[Years]], _difference_.[[Months]], _difference_.[[Weeks]], _difference_.[[Days]], _difference_.[[Hours]], _difference_.[[Minutes]], _difference_.[[Seconds]], _difference_.[[Milliseconds]], _difference_.[[Microseconds]], _difference_.[[Nanoseconds]], _settings_.[[RoundingIncrement]], _settings_.[[SmallestUnit]], _settings_.[[RoundingMode]], _plainRelativeTo_, _zonedDateTime_). 1. Let _roundResult_ be _roundRecord_.[[DurationRecord]]. 1. Let _result_ be ? AdjustRoundedDurationDays(_roundResult_.[[Years]], _roundResult_.[[Months]], _roundResult_.[[Weeks]], _roundResult_.[[Days]], _roundResult_.[[Hours]], _roundResult_.[[Minutes]], _roundResult_.[[Seconds]], _roundResult_.[[Milliseconds]], _roundResult_.[[Microseconds]], _roundResult_.[[Nanoseconds]], _settings_.[[RoundingIncrement]], _settings_.[[SmallestUnit]], _settings_.[[RoundingMode]], _zonedDateTime_). 1. Return ! CreateTemporalDuration(_sign_ × _result_.[[Years]], _sign_ × _result_.[[Months]], _sign_ × _result_.[[Weeks]], _sign_ × _result_.[[Days]], _sign_ × _result_.[[Hours]], _sign_ × _result_.[[Minutes]], _sign_ × _result_.[[Seconds]], _sign_ × _result_.[[Milliseconds]], _sign_ × _result_.[[Microseconds]], _sign_ × _result_.[[Nanoseconds]]).