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
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,
- )
-
-
-
- 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
- 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,
)
@@ -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
- 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
- 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 @@
@@ -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_).