diff --git a/polyfill/lib/calendar.mjs b/polyfill/lib/calendar.mjs index 3d72741f04..a494a7bf94 100644 --- a/polyfill/lib/calendar.mjs +++ b/polyfill/lib/calendar.mjs @@ -2160,3 +2160,10 @@ impl['indian'] = ObjectAssign({}, nonIsoGeneralImpl, { helper: helperIndian }); impl['buddhist'] = ObjectAssign({}, nonIsoGeneralImpl, { helper: helperBuddhist }); impl['japanese'] = ObjectAssign({}, nonIsoGeneralImpl, { helper: helperJapanese }); impl['gregory'] = ObjectAssign({}, nonIsoGeneralImpl, { helper: helperGregory }); + +function calendarFieldsImpl(calendar, fieldNames) { + return impl[calendar].fields(fieldNames); +} +// Probably not what the intrinsics mechanism was intended for, but view this as +// an export of calendarFieldsImpl while avoiding circular dependencies +DefineIntrinsic('calendarFieldsImpl', calendarFieldsImpl); diff --git a/polyfill/lib/duration.mjs b/polyfill/lib/duration.mjs index 698da89d73..2e618b01d6 100644 --- a/polyfill/lib/duration.mjs +++ b/polyfill/lib/duration.mjs @@ -1,5 +1,7 @@ /* global __debug__ */ +import bigInt from 'big-integer'; + import * as ES from './ecmascript.mjs'; import { MakeIntrinsicClass } from './intrinsicclass.mjs'; import { @@ -13,6 +15,9 @@ import { MILLISECONDS, MICROSECONDS, NANOSECONDS, + CALENDAR, + INSTANT, + TIME_ZONE, CreateSlots, GetSlot, SetSlot @@ -223,7 +228,7 @@ export class Duration { let microseconds = GetSlot(this, MICROSECONDS); let nanoseconds = GetSlot(this, NANOSECONDS); - let defaultLargestUnit = ES.DefaultTemporalLargestUnit( + const existingLargestUnit = ES.DefaultTemporalLargestUnit( years, months, weeks, @@ -244,7 +249,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); @@ -254,7 +259,7 @@ export class Duration { smallestUnitPresent = false; smallestUnit = 'nanosecond'; } - defaultLargestUnit = ES.LargerOfTwoTemporalUnits(defaultLargestUnit, smallestUnit); + const defaultLargestUnit = ES.LargerOfTwoTemporalUnits(existingLargestUnit, smallestUnit); let largestUnitPresent = true; if (!largestUnit) { largestUnitPresent = false; @@ -279,13 +284,43 @@ export class Duration { const maximum = maximumIncrements[smallestUnit]; if (maximum !== undefined) ES.ValidateTemporalRoundingIncrement(roundingIncrement, maximum, false); + const roundingGranularityIsNoop = smallestUnit === 'nanosecond' && roundingIncrement === 1; + const balancingRequested = largestUnit !== existingLargestUnit; + const calendarUnitsPresent = years !== 0 || months !== 0 || weeks !== 0; + const timeUnitsOverflowWillOccur = + minutes >= 60 || seconds >= 60 || milliseconds >= 1000 || microseconds >= 1000 || nanoseconds >= 1000; + const hoursToDaysConversionMayOccur = (days !== 0 && zonedRelativeTo) || hours >= 24; + if ( + roundingGranularityIsNoop && + !balancingRequested && + !calendarUnitsPresent && + !timeUnitsOverflowWillOccur && + !hoursToDaysConversionMayOccur + ) { + 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( @@ -302,9 +337,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, @@ -320,7 +356,7 @@ export class Duration { roundingIncrement, smallestUnit, roundingMode, - relativeTo + zonedRelativeTo )); ({ days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = ES.BalanceTimeDurationRelative( days, @@ -331,7 +367,7 @@ export class Duration { microseconds, nanoseconds, largestUnit, - relativeTo + zonedRelativeTo )); } else { ({ days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = ES.BalanceTimeDuration( @@ -351,7 +387,7 @@ export class Duration { weeks, days, largestUnit, - relativeTo + plainRelativeTo )); return new Duration(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds); @@ -377,15 +413,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, @@ -430,7 +481,8 @@ export class Duration { 1, unit, 'trunc', - relativeTo + plainRelativeTo, + zonedRelativeTo ); return total; } @@ -532,12 +584,11 @@ export class Duration { one = ES.ToTemporalDuration(one); two = ES.ToTemporalDuration(two); options = ES.GetOptionsObject(options); - const relativeTo = ES.ToRelativeTemporalObject(options); const y1 = GetSlot(one, YEARS); const mon1 = GetSlot(one, MONTHS); const w1 = GetSlot(one, WEEKS); let d1 = GetSlot(one, DAYS); - const h1 = GetSlot(one, HOURS); + let h1 = GetSlot(one, HOURS); const min1 = GetSlot(one, MINUTES); const s1 = GetSlot(one, SECONDS); const ms1 = GetSlot(one, MILLISECONDS); @@ -547,20 +598,81 @@ export class Duration { const mon2 = GetSlot(two, MONTHS); const w2 = GetSlot(two, WEEKS); let d2 = GetSlot(two, DAYS); - const h2 = GetSlot(two, HOURS); + let h2 = GetSlot(two, HOURS); const min2 = GetSlot(two, MINUTES); const s2 = GetSlot(two, SECONDS); 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); - if (y1 !== 0 || y2 !== 0 || mon1 !== 0 || mon2 !== 0 || w1 !== 0 || w2 !== 0) { - ({ days: d1 } = ES.UnbalanceDateDurationRelative(y1, mon1, w1, d1, 'day', relativeTo)); - ({ days: d2 } = ES.UnbalanceDateDurationRelative(y2, mon2, w2, d2, 'day', relativeTo)); + + if ( + y1 === y2 && + mon1 === mon2 && + w1 === w2 && + d1 === d2 && + h1 === h2 && + min1 === min2 && + s1 === s2 && + ms1 === ms2 && + µs1 === µs2 && + ns1 === ns2 + ) { + return 0; + } + const { plainRelativeTo, zonedRelativeTo } = ES.ToRelativeTemporalObject(options); + + const calendarUnitsPresent = y1 !== 0 || y2 !== 0 || mon1 !== 0 || mon2 !== 0 || w1 !== 0 || w2 !== 0; + + if (zonedRelativeTo && (calendarUnitsPresent || d1 != 0 || d2 !== 0)) { + const instant = GetSlot(zonedRelativeTo, INSTANT); + const timeZone = GetSlot(zonedRelativeTo, TIME_ZONE); + const calendar = GetSlot(zonedRelativeTo, CALENDAR); + const precalculatedPlainDateTime = ES.GetPlainDateTimeFor(timeZone, instant, calendar); + + const after1 = ES.AddZonedDateTime( + instant, + timeZone, + calendar, + y1, + mon1, + w1, + d1, + h1, + min1, + s1, + ms1, + µs1, + ns1, + precalculatedPlainDateTime + ); + const after2 = ES.AddZonedDateTime( + instant, + timeZone, + calendar, + y2, + mon2, + w2, + d2, + h2, + min2, + s2, + ms2, + µs2, + ns2, + precalculatedPlainDateTime + ); + return ES.ComparisonResult(after1.minus(after2).toJSNumber()); + } + + if (calendarUnitsPresent) { + // plainRelativeTo may be undefined, and if so Unbalance will throw + ({ 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); + h1 = bigInt(h1).add(bigInt(d1).multiply(24)); + h2 = bigInt(h2).add(bigInt(d2).multiply(24)); + ns1 = ES.TotalDurationNanoseconds(h1, min1, s1, ms1, µs1, ns1); + ns2 = ES.TotalDurationNanoseconds(h2, min2, s2, ms2, µs2, ns2); return ES.ComparisonResult(ns1.minus(ns2).toJSNumber()); } } diff --git a/polyfill/lib/ecmascript.mjs b/polyfill/lib/ecmascript.mjs index 63e19822a5..f7622d99c4 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( @@ -1797,9 +1803,8 @@ export function CreateTemporalZonedDateTime(epochNanoseconds, timeZone, calendar export function CalendarFields(calendar, fieldNames) { if (typeof calendar === 'string') { - const TemporalCalendar = GetIntrinsic('%Temporal.Calendar%'); - calendar = new TemporalCalendar(calendar); - return Call(GetIntrinsic('%Temporal.Calendar.prototype.fields%'), calendar, [fieldNames]); + if (calendar === 'iso8601') return fieldNames; + return GetIntrinsic('%calendarFieldsImpl%')(calendar, fieldNames); } const fields = GetMethod(calendar, 'fields'); fieldNames = Call(fields, calendar, [fieldNames]); @@ -2602,7 +2607,7 @@ export function TemporalDurationToString( ) { const sign = DurationSign(years, months, weeks, days, hours, minutes, seconds, ms, µs, ns); - let total = TotalDurationNanoseconds(0, 0, 0, seconds, ms, µs, ns, 0); + let total = TotalDurationNanoseconds(0, 0, seconds, ms, µs, ns); ({ quotient: total, remainder: ns } = total.divmod(1000)); ({ quotient: total, remainder: µs } = total.divmod(1000)); ({ quotient: seconds, remainder: ms } = total.divmod(1000)); @@ -3275,19 +3280,8 @@ export function BalanceTime(hour, minute, second, millisecond, microsecond, nano }; } -export function TotalDurationNanoseconds( - days, - hours, - minutes, - seconds, - milliseconds, - microseconds, - nanoseconds, - offsetShift -) { - if (days !== 0) nanoseconds = bigInt(nanoseconds).subtract(offsetShift); - hours = bigInt(hours).add(bigInt(days).multiply(24)); - minutes = bigInt(minutes).add(hours.multiply(60)); +export function TotalDurationNanoseconds(hours, minutes, seconds, milliseconds, microseconds, nanoseconds) { + minutes = bigInt(minutes).add(bigInt(hours).multiply(60)); seconds = bigInt(seconds).add(minutes.multiply(60)); milliseconds = bigInt(milliseconds).add(seconds.multiply(1000)); microseconds = bigInt(microseconds).add(milliseconds.multiply(1000)); @@ -3333,7 +3327,7 @@ export function NanosecondsToDays(nanoseconds, zonedRelativeTo) { 'day', ObjectCreate(null) ); - let intermediateNs = AddZonedDateTime(start, timeZone, calendar, 0, 0, 0, days, 0, 0, 0, 0, 0, 0); + let intermediateNs = AddZonedDateTime(start, timeZone, calendar, 0, 0, 0, days, 0, 0, 0, 0, 0, 0, dtStart); // may disambiguate // If clock time after addition was in the middle of a skipped period, the @@ -3348,7 +3342,22 @@ export function NanosecondsToDays(nanoseconds, zonedRelativeTo) { if (sign === 1) { while (days.greater(0) && intermediateNs.greater(endNs)) { days = days.prev(); - intermediateNs = AddZonedDateTime(start, timeZone, calendar, 0, 0, 0, days.toJSNumber(), 0, 0, 0, 0, 0, 0); + intermediateNs = AddZonedDateTime( + start, + timeZone, + calendar, + 0, + 0, + 0, + days.toJSNumber(), + 0, + 0, + 0, + 0, + 0, + 0, + dtStart + ); // may do disambiguation } } @@ -3421,7 +3430,8 @@ export function BalancePossiblyInfiniteTimeDuration( nanoseconds, largestUnit ) { - nanoseconds = TotalDurationNanoseconds(days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds, 0); + hours = bigInt(hours).add(bigInt(days).multiply(24)); + nanoseconds = TotalDurationNanoseconds(hours, minutes, seconds, milliseconds, microseconds, nanoseconds); const sign = nanoseconds.lesser(0) ? -1 : 1; nanoseconds = nanoseconds.abs(); @@ -3574,16 +3584,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); @@ -3601,6 +3607,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; @@ -3609,12 +3616,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); } @@ -3622,12 +3629,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); } @@ -3635,7 +3648,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); } @@ -3649,7 +3667,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); } @@ -3657,7 +3680,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); } @@ -3665,7 +3693,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); } @@ -3681,17 +3714,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); @@ -3704,72 +3736,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; } @@ -3786,21 +3855,6 @@ export function BalanceDateDurationRelative(years, months, weeks, days, largestU }; } -export function CalculateOffsetShift(relativeTo, y, mon, w, d) { - if (IsTemporalZonedDateTime(relativeTo)) { - const instant = GetSlot(relativeTo, INSTANT); - const timeZone = GetSlot(relativeTo, TIME_ZONE); - const calendar = GetSlot(relativeTo, CALENDAR); - const offsetBefore = GetOffsetNanosecondsFor(timeZone, instant); - const after = AddZonedDateTime(instant, timeZone, calendar, y, mon, w, d, 0, 0, 0, 0, 0, 0); - const TemporalInstant = GetIntrinsic('%Temporal.Instant%'); - const instantAfter = new TemporalInstant(after); - const offsetAfter = GetOffsetNanosecondsFor(timeZone, instantAfter); - return offsetAfter - offsetBefore; - } - return 0; -} - export function CreateNegatedTemporalDuration(duration) { const TemporalDuration = GetIntrinsic('%Temporal.Duration%'); return new TemporalDuration( @@ -4045,21 +4099,23 @@ export function DifferenceInstant(ns1, ns2, increment, smallestUnit, largestUnit let milliseconds = diff.divide(1e6).mod(1e3).toJSNumber(); let seconds = diff.divide(1e9).toJSNumber(); - ({ hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = RoundDuration( - 0, - 0, - 0, - 0, - 0, - 0, - seconds, - milliseconds, - microseconds, - nanoseconds, - increment, - smallestUnit, - roundingMode - )); + if (smallestUnit !== 'nanosecond' || increment !== 1) { + ({ hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = RoundDuration( + 0, + 0, + 0, + 0, + 0, + 0, + seconds, + milliseconds, + microseconds, + nanoseconds, + increment, + smallestUnit, + roundingMode + )); + } return BalanceTimeDuration(0, hours, minutes, seconds, milliseconds, microseconds, nanoseconds, largestUnit); } @@ -4187,7 +4243,7 @@ export function DifferenceZonedDateTime(ns1, ns2, timeZone, calendar, largestUni largestUnit, options ); - let intermediateNs = AddZonedDateTime(start, timeZone, calendar, years, months, weeks, 0, 0, 0, 0, 0, 0, 0); + let intermediateNs = AddZonedDateTime(start, timeZone, calendar, years, months, weeks, 0, 0, 0, 0, 0, 0, 0, dtStart); // may disambiguate let timeRemainderNs = ns2.subtract(intermediateNs); const intermediate = CreateTemporalZonedDateTime(intermediateNs, timeZone, calendar); @@ -4359,33 +4415,35 @@ export function DifferenceTemporalPlainDateTime(operation, plainDateTime, other, resolvedOptions ); - const relativeTo = TemporalDateTimeToDate(plainDateTime); - ({ years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = RoundDuration( - years, - months, - weeks, - days, - hours, - minutes, - seconds, - milliseconds, - microseconds, - nanoseconds, - settings.roundingIncrement, - settings.smallestUnit, - settings.roundingMode, - relativeTo - )); - ({ days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = BalanceTimeDuration( - days, - hours, - minutes, - seconds, - milliseconds, - microseconds, - nanoseconds, - settings.largestUnit - )); + if (settings.smallestUnit !== 'nanosecond' || settings.roundingIncrement !== 1) { + const relativeTo = TemporalDateTimeToDate(plainDateTime); + ({ years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = RoundDuration( + years, + months, + weeks, + days, + hours, + minutes, + seconds, + milliseconds, + microseconds, + nanoseconds, + settings.roundingIncrement, + settings.smallestUnit, + settings.roundingMode, + relativeTo + )); + ({ days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = BalanceTimeDuration( + days, + hours, + minutes, + seconds, + milliseconds, + microseconds, + nanoseconds, + settings.largestUnit + )); + } const Duration = GetIntrinsic('%Temporal.Duration%'); return new Duration( @@ -4423,21 +4481,23 @@ export function DifferenceTemporalPlainTime(operation, plainTime, other, options GetSlot(other, ISO_MICROSECOND), GetSlot(other, ISO_NANOSECOND) ); - ({ hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = RoundDuration( - 0, - 0, - 0, - 0, - hours, - minutes, - seconds, - milliseconds, - microseconds, - nanoseconds, - settings.roundingIncrement, - settings.smallestUnit, - settings.roundingMode - )); + if (settings.smallestUnit !== 'nanosecond' || settings.roundingIncrement !== 1) { + ({ hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = RoundDuration( + 0, + 0, + 0, + 0, + hours, + minutes, + seconds, + milliseconds, + microseconds, + nanoseconds, + settings.roundingIncrement, + settings.smallestUnit, + settings.roundingMode + )); + } ({ hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = BalanceTimeDuration( 0, hours, @@ -4550,24 +4610,12 @@ export function DifferenceTemporalZonedDateTime(operation, zonedDateTime, other, } ({ years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = DifferenceZonedDateTime(ns1, ns2, timeZone, calendar, settings.largestUnit, resolvedOptions)); - ({ years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = RoundDuration( - years, - months, - weeks, - days, - hours, - minutes, - seconds, - milliseconds, - microseconds, - nanoseconds, - settings.roundingIncrement, - settings.smallestUnit, - settings.roundingMode, - zonedDateTime - )); - ({ years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = - AdjustRoundedDurationDays( + + 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, weeks, @@ -4581,8 +4629,27 @@ export function DifferenceTemporalZonedDateTime(operation, zonedDateTime, other, settings.roundingIncrement, settings.smallestUnit, settings.roundingMode, + plainRelativeTo, zonedDateTime )); + ({ years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = + AdjustRoundedDurationDays( + years, + months, + weeks, + days, + hours, + minutes, + seconds, + milliseconds, + microseconds, + nanoseconds, + settings.roundingIncrement, + settings.smallestUnit, + settings.roundingMode, + zonedDateTime + )); + } } const Duration = GetIntrinsic('%Temporal.Duration%'); @@ -4664,14 +4731,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'); } @@ -4686,20 +4754,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); @@ -4716,12 +4784,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, @@ -4757,7 +4825,7 @@ export function AddDuration( weeks = 0; days = 0; ({ hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = DifferenceInstant( - GetSlot(relativeTo, EPOCHNANOSECONDS), + GetSlot(zonedRelativeTo, EPOCHNANOSECONDS), endNs, 1, 'nanosecond', @@ -4767,7 +4835,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, @@ -4869,7 +4937,8 @@ export function AddZonedDateTime( ms, µs, ns, - options + precalculatedPlainDateTime = undefined, + options = undefined ) { // If only time is to be added, then use Instant math. It's not OK to fall // through to the date/time code below because compatible disambiguation in @@ -4886,7 +4955,7 @@ export function AddZonedDateTime( // RFC 5545 requires the date portion to be added in calendar days and the // time portion to be added in exact time. - let dt = GetPlainDateTimeFor(timeZone, instant, calendar); + const dt = precalculatedPlainDateTime ?? GetPlainDateTimeFor(timeZone, instant, calendar); const datePart = CreateTemporalDate(GetSlot(dt, ISO_YEAR), GetSlot(dt, ISO_MONTH), GetSlot(dt, ISO_DAY), calendar); const dateDuration = new TemporalDuration(years, months, weeks, days, 0, 0, 0, 0, 0, 0); const addedDate = CalendarDateAdd(calendar, datePart, dateDuration, options); @@ -4914,7 +4983,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), @@ -4936,7 +5005,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); @@ -5091,6 +5161,7 @@ export function AddDurationToOrSubtractDurationFromZonedDateTime(operation, zone sign * milliseconds, sign * microseconds, sign * nanoseconds, + undefined, options ); return CreateTemporalZonedDateTime(epochNanoseconds, timeZone, calendar); @@ -5285,10 +5356,9 @@ export function AdjustRoundedDurationDays( increment, unit, roundingMode, - relativeTo + zonedRelativeTo ) { if ( - !IsTemporalZonedDateTime(relativeTo) || unit === 'year' || unit === 'month' || unit === 'week' || @@ -5306,22 +5376,13 @@ export function AdjustRoundedDurationDays( // duration, there's no way for another full day to come from the next // round of rounding. And if it were possible (e.g. contrived calendar // with 30-minute-long "days") then it'd risk an infinite loop. - let timeRemainderNs = TotalDurationNanoseconds( - 0, - hours, - minutes, - seconds, - milliseconds, - microseconds, - nanoseconds, - 0 - ); + let timeRemainderNs = TotalDurationNanoseconds(hours, minutes, seconds, milliseconds, microseconds, nanoseconds); 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, @@ -5376,7 +5437,8 @@ export function AdjustRoundedDurationDays( 0, 0, 0, - relativeTo + /* plainRelativeTo = */ undefined, + zonedRelativeTo )); ({ hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = RoundDuration( years, @@ -5421,25 +5483,20 @@ export function RoundDuration( increment, unit, roundingMode, - relativeTo = undefined + plainRelativeTo = undefined, + zonedRelativeTo = undefined ) { const TemporalDuration = GetIntrinsic('%Temporal.Duration%'); - let calendar, zonedRelativeTo; - if (relativeTo) { - if (IsTemporalZonedDateTime(relativeTo)) { - zonedRelativeTo = relativeTo; - relativeTo = ToTemporalDate(relativeTo); - } else if (!IsTemporalDate(relativeTo)) { - throw new Error('assertion failure in RoundDuration: _relativeTo_ must be PlainDate'); - } - calendar = GetSlot(relativeTo, CALENDAR); + + if ((unit === 'year' || unit === 'month' || unit === 'week') && !plainRelativeTo) { + throw new RangeError(`A starting point is required for ${unit}s rounding`); } // First convert time units up to days, if rounding to days or higher units. // If rounding relative to a ZonedDateTime, then some days may not be 24h. let dayLengthNs; if (unit === 'year' || unit === 'month' || unit === 'week' || unit === 'day') { - nanoseconds = TotalDurationNanoseconds(0, hours, minutes, seconds, milliseconds, microseconds, nanoseconds, 0); + nanoseconds = TotalDurationNanoseconds(hours, minutes, seconds, milliseconds, microseconds, nanoseconds); let deltaDays; if (zonedRelativeTo) { const intermediate = MoveRelativeZonedDateTime(zonedRelativeTo, years, months, weeks, days); @@ -5456,31 +5513,36 @@ export function RoundDuration( let total; switch (unit) { case 'year': { - if (!calendar) throw new RangeError('A starting point is required for years rounding'); + 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 @@ -5499,17 +5561,17 @@ export function RoundDuration( break; } case 'month': { - if (!calendar) throw new RangeError('A starting point is required for months rounding'); + 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, @@ -5517,11 +5579,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); @@ -5534,18 +5606,29 @@ export function RoundDuration( break; } case 'week': { - if (!calendar) throw new RangeError('A starting point is required for weeks rounding'); + 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'. const sign = MathSign(days); 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/lib/plaindatetime.mjs b/polyfill/lib/plaindatetime.mjs index 9648bedaf2..72aa4c6a83 100644 --- a/polyfill/lib/plaindatetime.mjs +++ b/polyfill/lib/plaindatetime.mjs @@ -310,6 +310,20 @@ export class PlainDateTime { let millisecond = GetSlot(this, ISO_MILLISECOND); let microsecond = GetSlot(this, ISO_MICROSECOND); let nanosecond = GetSlot(this, ISO_NANOSECOND); + if (roundingIncrement === 1 && smallestUnit === 'nanosecond') { + return ES.CreateTemporalDateTime( + year, + month, + day, + hour, + minute, + second, + millisecond, + microsecond, + nanosecond, + GetSlot(this, CALENDAR) + ); + } ({ year, month, day, hour, minute, second, millisecond, microsecond, nanosecond } = ES.RoundISODateTime( year, month, diff --git a/polyfill/lib/zoneddatetime.mjs b/polyfill/lib/zoneddatetime.mjs index fedbd4785e..60a6110d95 100644 --- a/polyfill/lib/zoneddatetime.mjs +++ b/polyfill/lib/zoneddatetime.mjs @@ -364,6 +364,14 @@ export class ZonedDateTime { const inclusive = maximum === 1; ES.ValidateTemporalRoundingIncrement(roundingIncrement, maximum, inclusive); + if (smallestUnit === 'nanosecond' && roundingIncrement === 1) { + return ES.CreateTemporalZonedDateTime( + GetSlot(this, EPOCHNANOSECONDS), + GetSlot(this, TIME_ZONE), + GetSlot(this, CALENDAR) + ); + } + // first, round the underlying DateTime fields const timeZone = GetSlot(this, TIME_ZONE); const offsetNs = ES.GetOffsetNanosecondsFor(timeZone, GetSlot(this, INSTANT)); @@ -379,20 +387,9 @@ export class ZonedDateTime { let nanosecond = GetSlot(dt, ISO_NANOSECOND); const calendar = GetSlot(this, CALENDAR); - const dtStart = ES.CreateTemporalDateTime( - GetSlot(dt, ISO_YEAR), - GetSlot(dt, ISO_MONTH), - GetSlot(dt, ISO_DAY), - 0, - 0, - 0, - 0, - 0, - 0, - 'iso8601' - ); + const dtStart = ES.CreateTemporalDateTime(year, month, day, 0, 0, 0, 0, 0, 0, 'iso8601'); const instantStart = ES.GetInstantFor(timeZone, dtStart, 'compatible'); - const endNs = ES.AddZonedDateTime(instantStart, timeZone, calendar, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0); + const endNs = ES.AddZonedDateTime(instantStart, timeZone, calendar, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, dtStart); const dayLengthNs = endNs.subtract(GetSlot(instantStart, EPOCHNANOSECONDS)); if (dayLengthNs.leq(0)) { throw new RangeError('cannot round a ZonedDateTime in a calendar with zero- or negative-length days'); 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/polyfill/test262 b/polyfill/test262 index bdddd9e2d2..e98bfb332e 160000 --- a/polyfill/test262 +++ b/polyfill/test262 @@ -1 +1 @@ -Subproject commit bdddd9e2d286600462958c7bac6af10a2946134b +Subproject commit e98bfb332e653a5c8c38763574140dae1417b7a8 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/calendar.html b/spec/calendar.html index 42bca64e90..75fdf17ada 100644 --- a/spec/calendar.html +++ b/spec/calendar.html @@ -99,9 +99,12 @@

1. If _calendar_ is a String, then - 1. Set _calendar_ to ! CreateTemporalCalendar(_calendar_). - 1. Let _fieldsArray_ be ? Call(%Temporal.Calendar.prototype.fields%, _calendar_, « CreateArrayFromList(_fieldNames_) »). - 1. Return ! CreateListFromArrayLike(_fieldsArray_, « String »). + 1. Assert: _fieldNames_ contains no String other than *"year"*, *"month"*, *"monthCode"*, or *"day"*. + 1. If _calendar_ is *"iso8601"*, return _fieldNames_. + 1. Let _extraFieldDescriptors_ be CalendarFieldDescriptors(_calendar_, _fieldNames_). + 1. For each Calendar Field Descriptor Record _desc_ of _extraFieldDescriptors_, do + 1. Append _desc_.[[Property]] to _fieldNames_. + 1. Return _fieldNames_. 1. Let _fieldsArray_ be ? Invoke(_calendar_, *"fields"*, « CreateArrayFromList(_fieldNames_) »). 1. Let _iteratorRecord_ be ? GetIterator(_fieldsArray_, ~sync~). 1. Return ? IteratorToListOfType(_iteratorRecord_, « String »). diff --git a/spec/duration.html b/spec/duration.html index f09027c90c..d654773334 100644 --- a/spec/duration.html +++ b/spec/duration.html @@ -94,19 +94,35 @@

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. 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. 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 _one_.[[Years]] = _two_.[[Years]], and _one_.[[Months]] = _two_.[[Months]], and _one_.[[Weeks]] = _two_.[[Weeks]], and _one_.[[Days]] = _two_.[[Days]], and _one_.[[Hours]] = _two_.[[Hours]], and _one_.[[Minutes]] = _two_.[[Minutes]], and _one_.[[Seconds]] = _two_.[[Seconds]], and _one_.[[Millieconds]] = _two_.[[Millieconds]], and _one_.[[Microseconds]] = _two_.[[Microseconds]], and _one_.[[Nanoseconds]] = _two_.[[Nanoseconds]], then + 1. Return *+0*𝔽. + 1. Let _relativeToRecord_ be ? ToRelativeTemporalObject(_options_). + 1. Let _zonedRelativeTo_ be _relativeToRecord_.[[ZonedRelativeTo]]. + 1. Let _plainRelativeTo_ be _relativeToRecord_.[[PlainRelativeTo]]. + 1. Let _calendarUnitsPresent_ be *false*. + 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, set _calendarUnitsPresent_ to *true*. + 1. If _zonedRelativeTo_ is not *undefined*, and either _calendarUnitsPresent_ is *true*, or _one_.[[Days]] ≠ 0, or _two_.[[Days]] ≠ 0, then + 1. Let _timeZone_ be _zonedRelativeTo_.[[TimeZone]]. + 1. Let _calendar_ be _zonedRelativeTo_.[[Calendar]]. + 1. Let _instant_ be ! CreateTemporalInstant(_zonedRelativeTo_.[[Nanoseconds]]). + 1. Let _precalculatedPlainDateTime_ be ? GetPlainDateTimeFor(_timeZone_, _instant_, _calendar_). + 1. Let _after1_ be ? AddZonedDateTime(_zonedRelativeTo_.[[Nanoseconds]], _timeZone_, _calendar_, _one_.[[Years]], _one_.[[Months]], _one_.[[Weeks]], _one_.[[Days]], _one_.[[Hours]], _one_.[[Minutes]], _one_.[[Seconds]], _one_.[[Milliseconds]], _one_.[[Microseconds]], _one_.[[Nanoseconds]], _precalculatedPlainDateTime_). + 1. Let _after2_ be ? AddZonedDateTime(_zonedRelativeTo_.[[Nanoseconds]], _timeZone_, _calendar_, _two_.[[Years]], _two_.[[Months]], _two_.[[Weeks]], _two_.[[Days]], _two_.[[Hours]], _two_.[[Minutes]], _two_.[[Seconds]], _two_.[[Milliseconds]], _two_.[[Microseconds]], _two_.[[Nanoseconds]], _precalculatedPlainDateTime_). + 1. If _after1_ > _after2_, return *1*𝔽. + 1. If _after1_ < _after2_, return *-1*𝔽. + 1. Return *+0*𝔽. + 1. If _calendarUnitsPresent_ is *true*, then + 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, 1. Let _days1_ be _one_.[[Days]]. 1. Let _days2_ be _two_.[[Days]]. - 1. Let _ns1_ be ! TotalDurationNanoseconds(_days1_, _one_.[[Hours]], _one_.[[Minutes]], _one_.[[Seconds]], _one_.[[Milliseconds]], _one_.[[Microseconds]], _one_.[[Nanoseconds]], _shift1_). - 1. Let _ns2_ be ! TotalDurationNanoseconds(_days2_, _two_.[[Hours]], _two_.[[Minutes]], _two_.[[Seconds]], _two_.[[Milliseconds]], _two_.[[Microseconds]], _two_.[[Nanoseconds]], _shift2_). + 1. Let _hours1_ be _one_.[[Hours]] + _days1_ × 24. + 1. Let _hours2_ be _two_.[[Hours]] + _days2_ × 24. + 1. Let _ns1_ be TotalDurationNanoseconds(_hours1_, _one_.[[Minutes]], _one_.[[Seconds]], _one_.[[Milliseconds]], _one_.[[Microseconds]], _one_.[[Nanoseconds]]). + 1. Let _ns2_ be TotalDurationNanoseconds(_hours2_, _two_.[[Minutes]], _two_.[[Seconds]], _two_.[[Milliseconds]], _two_.[[Microseconds]], _two_.[[Nanoseconds]]). 1. If _ns1_ > _ns2_, return *1*𝔽. 1. If _ns1_ < _ns2_, return *-1*𝔽. 1. Return *+0*𝔽. @@ -414,15 +430,17 @@

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*). 1. If _smallestUnit_ is *undefined*, then 1. Set _smallestUnitPresent_ to *false*. 1. Set _smallestUnit_ to *"nanosecond"*. - 1. Let _defaultLargestUnit_ be ! DefaultTemporalLargestUnit(_duration_.[[Years]], _duration_.[[Months]], _duration_.[[Weeks]], _duration_.[[Days]], _duration_.[[Hours]], _duration_.[[Minutes]], _duration_.[[Seconds]], _duration_.[[Milliseconds]], _duration_.[[Microseconds]]). - 1. Set _defaultLargestUnit_ to ! LargerOfTwoTemporalUnits(_defaultLargestUnit_, _smallestUnit_). + 1. Let _existingLargestUnit_ be ! DefaultTemporalLargestUnit(_duration_.[[Years]], _duration_.[[Months]], _duration_.[[Weeks]], _duration_.[[Days]], _duration_.[[Hours]], _duration_.[[Minutes]], _duration_.[[Seconds]], _duration_.[[Milliseconds]], _duration_.[[Microseconds]]). + 1. Let _defaultLargestUnit_ be ! LargerOfTwoTemporalUnits(_existingLargestUnit_, _smallestUnit_). 1. If _largestUnit_ is *undefined*, then 1. Set _largestUnitPresent_ to *false*. 1. Set _largestUnit_ to _defaultLargestUnit_. @@ -433,15 +451,24 @@

Temporal.Duration.prototype.round ( _roundTo_ )

1. If LargerOfTwoTemporalUnits(_largestUnit_, _smallestUnit_) is not _largestUnit_, throw a *RangeError* exception. 1. Let _maximum_ be ! MaximumTemporalDurationRoundingIncrement(_smallestUnit_). 1. If _maximum_ is not *undefined*, perform ? ValidateTemporalRoundingIncrement(_roundingIncrement_, _maximum_, *false*). - 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. Let _hoursToDaysConversionMayOccur_ be *false*. + 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. 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]]).
@@ -462,18 +489,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]]).
@@ -1115,52 +1147,24 @@

- -

- CalculateOffsetShift ( - _relativeTo_: *undefined*, a Temporal.PlainDate, or a Temporal.ZonedDateTime, - _y_: an integer, - _mon_: an integer, - _w_: an integer, - _d_: an integer, - ) -

-
-
description
-
It returns an integer difference in nanoseconds between the time zone offset at the time of _relativeTo_, and the time zone offset at the time of _relativeTo_ plus the given duration.
-
- - 1. If Type(_relativeTo_) is not Object or _relativeTo_ does not have an [[InitializedTemporalZonedDateTime]] internal slot, return 0. - 1. Let _instant_ be ! CreateTemporalInstant(_relativeTo_.[[Nanoseconds]]). - 1. Let _offsetBefore_ be ? GetOffsetNanosecondsFor(_relativeTo_.[[TimeZone]], _instant_). - 1. Let _after_ be ? AddZonedDateTime(_relativeTo_.[[Nanoseconds]], _relativeTo_.[[TimeZone]], _relativeTo_.[[Calendar]], _y_, _mon_, _w_, _d_, 0, 0, 0, 0, 0, 0). - 1. Let _instantAfter_ be ! CreateTemporalInstant(_after_). - 1. Let _offsetAfter_ be ? GetOffsetNanosecondsFor(_relativeTo_.[[TimeZone]], _instantAfter_). - 1. Return _offsetAfter_ - _offsetBefore_. - -
-

TotalDurationNanoseconds ( - _days_: an integer, _hours_: an integer, _minutes_: an integer, _seconds_: an integer, _milliseconds_: an integer, _microseconds_: an integer, _nanoseconds_: an integer, - _offsetShift_: an integer, - ) + ): an integer

description
-
It computes an integer number of nanoseconds from the given units, applying a given time zone offset shift in nanoseconds when converting from days to hours.
+
+ It computes an integer number of nanoseconds from the given units. +
- 1. If _days_ ≠ 0, then - 1. Set _nanoseconds_ to _nanoseconds_ - _offsetShift_. - 1. Set _hours_ to _hours_ + _days_ × 24. 1. Set _minutes_ to _minutes_ + _hours_ × 60. 1. Set _seconds_ to _seconds_ + _minutes_ × 60. 1. Set _milliseconds_ to _milliseconds_ + _seconds_ × 1000. @@ -1213,7 +1217,8 @@

It converts the time units of a duration into a form where lower units are converted into higher units as much as possible, up to _largestUnit_. If the Number value for any unit is infinite, it returns a special value indicating the direction of overflow.
- 1. Set _nanoseconds_ to ! TotalDurationNanoseconds(_days_, _hours_, _minutes_, _seconds_, _milliseconds_, _microseconds_, _nanoseconds_, 0). + 1. Set _hours_ to _hours_ + _days_ × 24. + 1. Set _nanoseconds_ to TotalDurationNanoseconds(_hours_, _minutes_, _seconds_, _milliseconds_, _microseconds_, _nanoseconds_). 1. Set _days_, _hours_, _minutes_, _seconds_, _milliseconds_, and _microseconds_ to 0. 1. If _nanoseconds_ < 0, let _sign_ be -1; else, let _sign_ be 1. 1. Set _nanoseconds_ to abs(_nanoseconds_). @@ -1350,7 +1355,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, )

@@ -1367,12 +1372,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 @@ -1382,15 +1387,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 @@ -1398,13 +1404,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, @@ -1416,18 +1422,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_). @@ -1442,7 +1448,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, )

@@ -1454,71 +1460,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, @@ -1527,14 +1532,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_). @@ -1564,47 +1569,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*)). @@ -1689,7 +1696,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

@@ -1701,21 +1709,12 @@

- 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. 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. Set _relativeTo_ to ? ToTemporalDate(_relativeTo_). - 1. Else, - 1. Assert: _relativeTo_ has an [[InitializedTemporalDate]] internal slot. - 1. Let _calendar_ be _relativeTo_.[[Calendar]]. - 1. Else, - 1. NOTE: _calendar_ will not be used below. 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. Let _nanoseconds_ be TotalDurationNanoseconds(_hours_, _minutes_, _seconds_, _milliseconds_, _microseconds_, _nanoseconds_). 1. If _zonedRelativeTo_ is not *undefined*, then 1. Let _intermediate_ be ? MoveRelativeZonedDateTime(_zonedRelativeTo_, _years_, _months_, _weeks_, _days_). 1. Let _result_ be ? NanosecondsToDays(_nanoseconds_, _intermediate_). @@ -1729,79 +1728,82 @@

1. Assert: _fractionalDays_ is not used below. 1. Let _total_ be ~unset~. 1. If _unit_ is *"year"*, then + 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. 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. 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_). @@ -1861,7 +1863,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

@@ -1873,19 +1875,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. Let _timeRemainderNs_ be TotalDurationNanoseconds(_hours_, _minutes_, _seconds_, _milliseconds_, _microseconds_, _nanoseconds_). 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]]). @@ -1968,8 +1970,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/instant.html b/spec/instant.html index 2c70abf046..967bcbfcc6 100644 --- a/spec/instant.html +++ b/spec/instant.html @@ -596,6 +596,8 @@

1. Let _microseconds_ be remainder(truncate(_difference_ / 1000), 1000). 1. Let _milliseconds_ be remainder(truncate(_difference_ / 106), 1000). 1. Let _seconds_ be truncate(_difference_ / 109). + 1. If _smallestUnit_ is *"nanosecond"* and _roundingIncrement_ is 1, then + 1. Return ! BalanceTimeDuration(0, 0, 0, _seconds_, _milliseconds_, _microseconds_, _nanoseconds_, _largestUnit_). 1. Let _roundResult_ be ! RoundDuration(0, 0, 0, 0, 0, 0, _seconds_, _milliseconds_, _microseconds_, _nanoseconds_, _roundingIncrement_, _smallestUnit_, _roundingMode_). 1. Assert: _roundResult_.[[Days]] is 0. 1. Return ! BalanceTimeDuration(0, _roundResult_.[[Hours]], _roundResult_.[[Minutes]], _roundResult_.[[Seconds]], _roundResult_.[[Milliseconds]], _roundResult_.[[Microseconds]], _roundResult_.[[Nanoseconds]], _largestUnit_). diff --git a/spec/plaindatetime.html b/spec/plaindatetime.html index eaa9c80d82..107d647722 100644 --- a/spec/plaindatetime.html +++ b/spec/plaindatetime.html @@ -537,6 +537,8 @@

Temporal.PlainDateTime.prototype.round ( _roundTo_ )

1. Assert: _maximum_ is not *undefined*. 1. Let _inclusive_ be *false*. 1. Perform ? ValidateTemporalRoundingIncrement(_roundingIncrement_, _maximum_, _inclusive_). + 1. If _smallestUnit_ is *"nanosecond"* and _roundingIncrement_ is 1, then + 1. Return ! CreateTemporalDateTime(_dateTime_.[[ISOYear]], _dateTime_.[[ISOMonth]], _dateTime_.[[ISODay]], _dateTime_.[[ISOHour]], _dateTime_.[[ISOMinute]], _dateTime_.[[ISOSecond]], _dateTime_.[[ISOMillisecond]], _dateTime_.[[ISOMicrosecond]], _dateTime_.[[ISONanosecond]], _dateTime_.[[Calendar]]). 1. Let _result_ be RoundISODateTime(_dateTime_.[[ISOYear]], _dateTime_.[[ISOMonth]], _dateTime_.[[ISODay]], _dateTime_.[[ISOHour]], _dateTime_.[[ISOMinute]], _dateTime_.[[ISOSecond]], _dateTime_.[[ISOMillisecond]], _dateTime_.[[ISOMicrosecond]], _dateTime_.[[ISONanosecond]], _roundingIncrement_, _smallestUnit_, _roundingMode_). 1. Return ? CreateTemporalDateTime(_result_.[[Year]], _result_.[[Month]], _result_.[[Day]], _result_.[[Hour]], _result_.[[Minute]], _result_.[[Second]], _result_.[[Millisecond]], _result_.[[Microsecond]], _result_.[[Nanosecond]], _dateTime_.[[Calendar]]).
@@ -1280,6 +1282,8 @@

1. Let _resolvedOptions_ be ? SnapshotOwnProperties(? GetOptionsObject(_options_), *null*). 1. Let _settings_ be ? GetDifferenceSettings(_operation_, _resolvedOptions_, ~datetime~, « », *"nanosecond"*, *"day"*). 1. Let _diff_ be ? DifferenceISODateTime(_dateTime_.[[ISOYear]], _dateTime_.[[ISOMonth]], _dateTime_.[[ISODay]], _dateTime_.[[ISOHour]], _dateTime_.[[ISOMinute]], _dateTime_.[[ISOSecond]], _dateTime_.[[ISOMillisecond]], _dateTime_.[[ISOMicrosecond]], _dateTime_.[[ISONanosecond]], _other_.[[ISOYear]], _other_.[[ISOMonth]], _other_.[[ISODay]], _other_.[[ISOHour]], _other_.[[ISOMinute]], _other_.[[ISOSecond]], _other_.[[ISOMillisecond]], _other_.[[ISOMicrosecond]], _other_.[[ISONanosecond]], _dateTime_.[[Calendar]], _settings_.[[LargestUnit]], _resolvedOptions_). + 1. If _settings_.[[SmallestUnit]] is *"nanosecond"* and _settings_.[[RoundingIncrement]] is 1, then + 1. Return ! CreateTemporalDuration(_sign_ × _diff_.[[Years]], _sign_ × _diff_.[[Months]], _sign_ × _diff_.[[Weeks]], _sign_ × _diff_.[[Days]], _sign_ × _diff_.[[Hours]], _sign_ × _diff_.[[Minutes]], _sign_ × _diff_.[[Seconds]], _sign_ × _diff_.[[Milliseconds]], _sign_ × _diff_.[[Microseconds]], _sign_ × _diff_.[[Nanoseconds]]). 1. Let _relativeTo_ be ! CreateTemporalDate(_dateTime_.[[ISOYear]], _dateTime_.[[ISOMonth]], _dateTime_.[[ISODay]], _dateTime_.[[Calendar]]). 1. Let _roundRecord_ be ? RoundDuration(_diff_.[[Years]], _diff_.[[Months]], _diff_.[[Weeks]], _diff_.[[Days]], _diff_.[[Hours]], _diff_.[[Minutes]], _diff_.[[Seconds]], _diff_.[[Milliseconds]], _diff_.[[Microseconds]], _diff_.[[Nanoseconds]], _settings_.[[RoundingIncrement]], _settings_.[[SmallestUnit]], _settings_.[[RoundingMode]], _relativeTo_). 1. Let _roundResult_ be _roundRecord_.[[DurationRecord]]. diff --git a/spec/plaintime.html b/spec/plaintime.html index 577ce215af..481a0faab4 100644 --- a/spec/plaintime.html +++ b/spec/plaintime.html @@ -1018,8 +1018,9 @@

1. Let _resolvedOptions_ be ? SnapshotOwnProperties(? GetOptionsObject(_options_), *null*). 1. Let _settings_ be ? GetDifferenceSettings(_operation_, _resolvedOptions_, ~time~, « », *"nanosecond"*, *"hour"*). 1. Let _result_ be ! DifferenceTime(_temporalTime_.[[ISOHour]], _temporalTime_.[[ISOMinute]], _temporalTime_.[[ISOSecond]], _temporalTime_.[[ISOMillisecond]], _temporalTime_.[[ISOMicrosecond]], _temporalTime_.[[ISONanosecond]], _other_.[[ISOHour]], _other_.[[ISOMinute]], _other_.[[ISOSecond]], _other_.[[ISOMillisecond]], _other_.[[ISOMicrosecond]], _other_.[[ISONanosecond]]). - 1. Let _roundRecord_ be ! RoundDuration(0, 0, 0, 0, _result_.[[Hours]], _result_.[[Minutes]], _result_.[[Seconds]], _result_.[[Milliseconds]], _result_.[[Microseconds]], _result_.[[Nanoseconds]], _settings_.[[RoundingIncrement]], _settings_.[[SmallestUnit]], _settings_.[[RoundingMode]]). - 1. Set _result_ to _roundRecord_.[[DurationRecord]]. + 1. If _settings_.[[SmallestUnit]] is not *"nanosecond"* or _settings_.[[RoundingIncrement]] ≠ 1, then + 1. Let _roundRecord_ be ! RoundDuration(0, 0, 0, 0, _result_.[[Hours]], _result_.[[Minutes]], _result_.[[Seconds]], _result_.[[Milliseconds]], _result_.[[Microseconds]], _result_.[[Nanoseconds]], _settings_.[[RoundingIncrement]], _settings_.[[SmallestUnit]], _settings_.[[RoundingMode]]). + 1. Set _result_ to _roundRecord_.[[DurationRecord]]. 1. Set _result_ to ! BalanceTimeDuration(0, _result_.[[Hours]], _result_.[[Minutes]], _result_.[[Seconds]], _result_.[[Milliseconds]], _result_.[[Microseconds]], _result_.[[Nanoseconds]], _settings_.[[LargestUnit]]). 1. Return ! CreateTemporalDuration(0, 0, 0, 0, _sign_ × _result_.[[Hours]], _sign_ × _result_.[[Minutes]], _sign_ × _result_.[[Seconds]], _sign_ × _result_.[[Milliseconds]], _sign_ × _result_.[[Microseconds]], _sign_ × _result_.[[Nanoseconds]]). diff --git a/spec/zoneddatetime.html b/spec/zoneddatetime.html index 39be0dca50..364538fd68 100644 --- a/spec/zoneddatetime.html +++ b/spec/zoneddatetime.html @@ -758,6 +758,8 @@

Temporal.ZonedDateTime.prototype.round ( _roundTo_ )

1. Assert: _maximum_ is not *undefined*. 1. Let _inclusive_ be *false*. 1. Perform ? ValidateTemporalRoundingIncrement(_roundingIncrement_, _maximum_, _inclusive_). + 1. If _smallestUnit_ is *"nanosecond"* and _roundingIncrement_ is 1, then + 1. Return ! CreateTemporalZonedDateTime(_zonedDateTime_.[[Nanoseconds]], _zonedDateTime_.[[TimeZone]], _zonedDateTime_.[[Calendar]]). 1. Let _timeZone_ be _zonedDateTime_.[[TimeZone]]. 1. Let _instant_ be ! CreateTemporalInstant(_zonedDateTime_.[[Nanoseconds]]). 1. Let _calendar_ be _zonedDateTime_.[[Calendar]]. @@ -766,7 +768,7 @@

Temporal.ZonedDateTime.prototype.round ( _roundTo_ )

1. Let _dtStart_ be ? CreateTemporalDateTime(_temporalDateTime_.[[ISOYear]], _temporalDateTime_.[[ISOMonth]], _temporalDateTime_.[[ISODay]], 0, 0, 0, 0, 0, 0, *"iso8601"*). 1. Let _instantStart_ be ? GetInstantFor(_timeZone_, _dtStart_, *"compatible"*). 1. Let _startNs_ be _instantStart_.[[Nanoseconds]]. - 1. Let _endNs_ be ? AddZonedDateTime(_startNs_, _timeZone_, _calendar_, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0). + 1. Let _endNs_ be ? AddZonedDateTime(_startNs_, _timeZone_, _calendar_, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, _dtStart_). 1. Let _dayLengthNs_ be ℝ(_endNs_ - _startNs_). 1. If _dayLengthNs_ ≤ 0, then 1. Throw a *RangeError* exception. @@ -1288,6 +1290,7 @@

_milliseconds_: an integer, _microseconds_: an integer, _nanoseconds_: an integer, + optional _precalculatedPlainDateTime_: a Temporal.PlainDateTime or *undefined*, optional _options_: an Object, ): either a normal completion containing a BigInt or an abrupt completion

@@ -1298,13 +1301,17 @@

As specified in RFC 5545, the date portion of the duration is added in calendar days, and the time portion is added in exact time.

+

Unless _precalculatedPlainDateTime_ is supplied, the given _timeZone_'s `getOffsetNanosecondsFor` method will be called to convert _epochNanoseconds_ to a wall-clock time.

1. If _options_ is not present, set _options_ to *undefined*. 1. Assert: Type(_options_) is Object or Undefined. 1. If _years_ = 0, _months_ = 0, _weeks_ = 0, and _days_ = 0, then 1. Return ? AddInstant(_epochNanoseconds_, _hours_, _minutes_, _seconds_, _milliseconds_, _microseconds_, _nanoseconds_). - 1. Let _instant_ be ! CreateTemporalInstant(_epochNanoseconds_). - 1. Let _temporalDateTime_ be ? GetPlainDateTimeFor(_timeZone_, _instant_, _calendar_). + 1. If _precalculatedPlainDateTime_ is not *undefined*, then + 1. Let _temporalDateTime_ be _precalculatedPlainDateTime_. + 1. Else, + 1. Let _instant_ be ! CreateTemporalInstant(_epochNanoseconds_). + 1. Let _temporalDateTime_ be ? GetPlainDateTimeFor(_timeZone_, _instant_, _calendar_). 1. Let _datePart_ be ! CreateTemporalDate(_temporalDateTime_.[[ISOYear]], _temporalDateTime_.[[ISOMonth]], _temporalDateTime_.[[ISODay]], _calendar_). 1. Let _dateDuration_ be ! CreateTemporalDuration(_years_, _months_, _weeks_, _days_, 0, 0, 0, 0, 0, 0). 1. Let _addedDate_ be ? CalendarDateAdd(_calendar_, _datePart_, _dateDuration_, _options_). @@ -1339,7 +1346,7 @@

1. Let _endInstant_ be ! CreateTemporalInstant(_ns2_). 1. Let _endDateTime_ be ? GetPlainDateTimeFor(_timeZone_, _endInstant_, _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]], _calendar_, _largestUnit_, _options_). - 1. Let _intermediateNs_ be ? AddZonedDateTime(_ns1_, _timeZone_, _calendar_, _dateDifference_.[[Years]], _dateDifference_.[[Months]], _dateDifference_.[[Weeks]], 0, 0, 0, 0, 0, 0, 0). + 1. Let _intermediateNs_ be ? AddZonedDateTime(_ns1_, _timeZone_, _calendar_, _dateDifference_.[[Years]], _dateDifference_.[[Months]], _dateDifference_.[[Weeks]], 0, 0, 0, 0, 0, 0, 0, _startDateTime_). 1. Let _timeRemainderNs_ be _ns2_ - _intermediateNs_. 1. Let _intermediate_ be ! CreateTemporalZonedDateTime(_intermediateNs_, _timeZone_, _calendar_). 1. Let _result_ be ? NanosecondsToDays(ℝ(_timeRemainderNs_), _intermediate_). @@ -1358,7 +1365,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.
@@ -1368,18 +1375,18 @@

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. Let _intermediateNs_ be ℝ(? AddZonedDateTime(ℤ(_startNs_), _zonedRelativeTo_.[[TimeZone]], _zonedRelativeTo_.[[Calendar]], 0, 0, 0, _days_, 0, 0, 0, 0, 0, 0, _startDateTime_)). 1. If _sign_ is 1, then 1. Repeat, while _days_ > 0 and _intermediateNs_ > _endNs_, 1. Set _days_ to _days_ - 1. - 1. Set _intermediateNs_ to ℝ(? AddZonedDateTime(ℤ(_startNs_), _zonedRelativeTo_.[[TimeZone]], _zonedRelativeTo_.[[Calendar]], 0, 0, 0, _days_, 0, 0, 0, 0, 0, 0)). + 1. Set _intermediateNs_ to ℝ(? AddZonedDateTime(ℤ(_startNs_), _zonedRelativeTo_.[[TimeZone]], _zonedRelativeTo_.[[Calendar]], 0, 0, 0, _days_, 0, 0, 0, 0, 0, 0, _startDateTime_)). 1. Set _nanoseconds_ to _endNs_ - _intermediateNs_. 1. Let _done_ be *false*. 1. Let _dayLengthNs_ be ~unset~. @@ -1432,7 +1439,13 @@

1. If ? TimeZoneEquals(_zonedDateTime_.[[TimeZone]], _other_.[[TimeZone]]) is *false*, then 1. Throw a *RangeError* exception. 1. Let _difference_ be ? DifferenceZonedDateTime(_zonedDateTime_.[[Nanoseconds]], _other_.[[Nanoseconds]], _zonedDateTime_.[[TimeZone]], _zonedDateTime_.[[Calendar]], _settings_.[[LargestUnit]], _resolvedOptions_). - 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. 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 _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]]). @@ -1457,7 +1470,7 @@

1. Set _options_ to ? GetOptionsObject(_options_). 1. Let _timeZone_ be _zonedDateTime_.[[TimeZone]]. 1. Let _calendar_ be _zonedDateTime_.[[Calendar]]. - 1. Let _epochNanoseconds_ be ? AddZonedDateTime(_zonedDateTime_.[[Nanoseconds]], _timeZone_, _calendar_, _sign_ × _duration_.[[Years]], _sign_ × _duration_.[[Months]], _sign_ × _duration_.[[Weeks]], _sign_ × _duration_.[[Days]], _sign_ × _duration_.[[Hours]], _sign_ × _duration_.[[Minutes]], _sign_ × _duration_.[[Seconds]], _sign_ × _duration_.[[Milliseconds]], _sign_ × _duration_.[[Microseconds]], _sign_ × _duration_.[[Nanoseconds]], _options_). + 1. Let _epochNanoseconds_ be ? AddZonedDateTime(_zonedDateTime_.[[Nanoseconds]], _timeZone_, _calendar_, _sign_ × _duration_.[[Years]], _sign_ × _duration_.[[Months]], _sign_ × _duration_.[[Weeks]], _sign_ × _duration_.[[Days]], _sign_ × _duration_.[[Hours]], _sign_ × _duration_.[[Minutes]], _sign_ × _duration_.[[Seconds]], _sign_ × _duration_.[[Milliseconds]], _sign_ × _duration_.[[Microseconds]], _sign_ × _duration_.[[Nanoseconds]], *undefined*, _options_). 1. Return ! CreateTemporalZonedDateTime(_epochNanoseconds_, _timeZone_, _calendar_).