Temporal: Expand order-of-operations tests to cover different types of relativeTo

The `relativeTo` parameter in an options bag may be undefined, a PlainDate
instance, or a ZonedDateTime instance. Each of these three possibilities
causes a different set of observable operations, which we can test in our
existing order-of-operations tests.
This commit is contained in:
Philip Chimento 2022-11-01 16:15:55 -07:00 committed by Ms2ger
parent 1c2508e801
commit 22e01996f3
5 changed files with 853 additions and 262 deletions

View File

@ -73,6 +73,86 @@ const expected = [
"call two.years.valueOf", "call two.years.valueOf",
// ToRelativeTemporalObject // ToRelativeTemporalObject
"get options.relativeTo", "get options.relativeTo",
];
const actual = [];
// basic order of observable operations with no relativeTo
Temporal.Duration.compare(
createDurationPropertyBagObserver("one", 0, 0, 0, 7),
createDurationPropertyBagObserver("two", 0, 0, 0, 6),
createOptionsObserver(undefined)
);
assert.compareArray(actual, expected, "order of operations");
actual.splice(0); // clear
const expectedOpsForPlainRelativeTo = expected.concat([
// ToRelativeTemporalObject
"get options.relativeTo.calendar",
"has options.relativeTo.calendar.calendar",
"get options.relativeTo.calendar.fields",
"call options.relativeTo.calendar.fields",
"get options.relativeTo.day",
"get options.relativeTo.day.valueOf",
"call options.relativeTo.day.valueOf",
"get options.relativeTo.hour",
"get options.relativeTo.microsecond",
"get options.relativeTo.millisecond",
"get options.relativeTo.minute",
"get options.relativeTo.month",
"get options.relativeTo.month.valueOf",
"call options.relativeTo.month.valueOf",
"get options.relativeTo.monthCode",
"get options.relativeTo.monthCode.toString",
"call options.relativeTo.monthCode.toString",
"get options.relativeTo.nanosecond",
"get options.relativeTo.second",
"get options.relativeTo.year",
"get options.relativeTo.year.valueOf",
"call options.relativeTo.year.valueOf",
"get options.relativeTo.calendar.dateFromFields",
"call options.relativeTo.calendar.dateFromFields",
"get options.relativeTo.offset",
"get options.relativeTo.timeZone",
]);
const plainRelativeTo = TemporalHelpers.propertyBagObserver(actual, {
year: 2001,
month: 5,
monthCode: "M05",
day: 2,
calendar: TemporalHelpers.calendarObserver(actual, "options.relativeTo.calendar"),
}, "options.relativeTo");
function createOptionsObserver(relativeTo = undefined) {
return TemporalHelpers.propertyBagObserver(actual, { relativeTo }, "options");
}
function createDurationPropertyBagObserver(name, y = 0, mon = 0, w = 0, d = 0, h = 0, min = 0, s = 0, ms = 0, µs = 0, ns = 0) {
return TemporalHelpers.propertyBagObserver(actual, {
years: y,
months: mon,
weeks: w,
days: d,
hours: h,
minutes: min,
seconds: s,
milliseconds: ms,
microseconds: µs,
nanoseconds: ns,
}, name);
}
// order of observable operations with plain relativeTo and without calendar units
Temporal.Duration.compare(
createDurationPropertyBagObserver("one", 0, 0, 0, 7),
createDurationPropertyBagObserver("two", 0, 0, 0, 6),
createOptionsObserver(plainRelativeTo)
);
assert.compareArray(actual, expectedOpsForPlainRelativeTo, "order of operations with PlainDate relativeTo and no calendar units");
actual.splice(0); // clear
const expectedOpsForZonedRelativeTo = expected.concat([
// ToRelativeTemporalObject
"get options.relativeTo.calendar", "get options.relativeTo.calendar",
"has options.relativeTo.calendar.calendar", "has options.relativeTo.calendar.calendar",
"get options.relativeTo.calendar.fields", "get options.relativeTo.calendar.fields",
@ -142,10 +222,9 @@ const expected = [
"call options.relativeTo.timeZone.getPossibleInstantsFor", "call options.relativeTo.timeZone.getPossibleInstantsFor",
"get options.relativeTo.timeZone.getOffsetNanosecondsFor", "get options.relativeTo.timeZone.getOffsetNanosecondsFor",
"call options.relativeTo.timeZone.getOffsetNanosecondsFor", "call options.relativeTo.timeZone.getOffsetNanosecondsFor",
]; ]);
const actual = [];
const relativeTo = TemporalHelpers.propertyBagObserver(actual, { const zonedRelativeTo = TemporalHelpers.propertyBagObserver(actual, {
year: 2001, year: 2001,
month: 5, month: 5,
monthCode: "M05", monthCode: "M05",
@ -161,37 +240,18 @@ const relativeTo = TemporalHelpers.propertyBagObserver(actual, {
timeZone: TemporalHelpers.timeZoneObserver(actual, "options.relativeTo.timeZone"), timeZone: TemporalHelpers.timeZoneObserver(actual, "options.relativeTo.timeZone"),
}, "options.relativeTo"); }, "options.relativeTo");
function createOptionsObserver(relativeTo = undefined) { // order of observable operations with zoned relativeTo and without calendar units
return TemporalHelpers.propertyBagObserver(actual, { relativeTo }, "options");
}
function createDurationPropertyBagObserver(name, y = 0, mon = 0, w = 0, d = 0, h = 0, min = 0, s = 0, ms = 0, µs = 0, ns = 0) {
return TemporalHelpers.propertyBagObserver(actual, {
years: y,
months: mon,
weeks: w,
days: d,
hours: h,
minutes: min,
seconds: s,
milliseconds: ms,
microseconds: µs,
nanoseconds: ns,
}, name);
}
// basic order of observable operations, without
Temporal.Duration.compare( Temporal.Duration.compare(
createDurationPropertyBagObserver("one", 0, 0, 0, 7), createDurationPropertyBagObserver("one", 0, 0, 0, 7),
createDurationPropertyBagObserver("two", 0, 0, 0, 6), createDurationPropertyBagObserver("two", 0, 0, 0, 6),
createOptionsObserver(relativeTo) createOptionsObserver(zonedRelativeTo)
); );
assert.compareArray(actual, expected, "order of operations"); assert.compareArray(actual, expectedOpsForZonedRelativeTo, "order of operations with ZonedDateTime relativeTo and no calendar units");
actual.splice(0, actual.length); // clear actual.splice(0, actual.length); // clear
// code path through UnbalanceDurationRelative that balances higher units down // code path through UnbalanceDurationRelative that balances higher units down
// to days: // to days:
const expectedOpsForDayBalancing = expected.concat([ const expectedOpsForDayBalancing = expectedOpsForZonedRelativeTo.concat([
// UnbalanceDurationRelative // UnbalanceDurationRelative
"get options.relativeTo.timeZone.getOffsetNanosecondsFor", // 7.a ToTemporalDate "get options.relativeTo.timeZone.getOffsetNanosecondsFor", // 7.a ToTemporalDate
"call options.relativeTo.timeZone.getOffsetNanosecondsFor", "call options.relativeTo.timeZone.getOffsetNanosecondsFor",
@ -210,7 +270,6 @@ const expectedOpsForDayBalancing = expected.concat([
Temporal.Duration.compare( Temporal.Duration.compare(
createDurationPropertyBagObserver("one", 1, 1, 1), createDurationPropertyBagObserver("one", 1, 1, 1),
createDurationPropertyBagObserver("two", 1, 1, 1, 1), createDurationPropertyBagObserver("two", 1, 1, 1, 1),
createOptionsObserver(relativeTo) createOptionsObserver(zonedRelativeTo)
); );
assert.compareArray(actual.slice(expected.length), expectedOpsForDayBalancing.slice(expected.length), "order of operations with calendar units"); assert.compareArray(actual, expectedOpsForDayBalancing, "order of operations with calendar units");
actual.splice(0, actual.length); // clear

View File

@ -8,9 +8,8 @@ includes: [compareArray.js, temporalHelpers.js]
features: [Temporal] features: [Temporal]
---*/ ---*/
const instance = new Temporal.Duration(1, 2, 0, 4, 5, 6, 7, 987, 654, 321);
const relativeTo = new Temporal.PlainDateTime(2000, 1, 1);
const expected = [ const expected = [
// ToTemporalDurationRecord
"get fields.days", "get fields.days",
"get fields.days.valueOf", "get fields.days.valueOf",
"call fields.days.valueOf", "call fields.days.valueOf",
@ -41,8 +40,75 @@ const expected = [
"get fields.years", "get fields.years",
"get fields.years.valueOf", "get fields.years.valueOf",
"call fields.years.valueOf", "call fields.years.valueOf",
// ToRelativeTemporalObject
"get options.relativeTo",
]; ];
const actual = []; const actual = [];
const simpleFields = TemporalHelpers.propertyBagObserver(actual, {
years: 0,
months: 0,
weeks: 0,
days: 1,
hours: 1,
minutes: 1,
seconds: 1,
milliseconds: 1,
microseconds: 1,
nanoseconds: 1,
}, "fields");
function createOptionsObserver(relativeTo = undefined) {
return TemporalHelpers.propertyBagObserver(actual, { relativeTo }, "options");
}
// basic order of observable operations, without any calendar units:
const simpleInstance = new Temporal.Duration(0, 0, 0, 1, 1, 1, 1, 1, 1, 1);
simpleInstance.add(simpleFields, createOptionsObserver());
assert.compareArray(actual, expected, "order of operations");
actual.splice(0); // clear
const expectedOpsForPlainRelativeTo = expected.concat([
// ToRelativeTemporalObject
"get options.relativeTo.calendar",
"has options.relativeTo.calendar.calendar",
"get options.relativeTo.calendar.fields",
"call options.relativeTo.calendar.fields",
// PrepareTemporalFields
"get options.relativeTo.day",
"get options.relativeTo.day.valueOf",
"call options.relativeTo.day.valueOf",
"get options.relativeTo.hour",
"get options.relativeTo.microsecond",
"get options.relativeTo.millisecond",
"get options.relativeTo.minute",
"get options.relativeTo.month",
"get options.relativeTo.month.valueOf",
"call options.relativeTo.month.valueOf",
"get options.relativeTo.monthCode",
"get options.relativeTo.monthCode.toString",
"call options.relativeTo.monthCode.toString",
"get options.relativeTo.nanosecond",
"get options.relativeTo.second",
"get options.relativeTo.year",
"get options.relativeTo.year.valueOf",
"call options.relativeTo.year.valueOf",
// InterpretTemporalDateTimeFields
"get options.relativeTo.calendar.dateFromFields",
"call options.relativeTo.calendar.dateFromFields",
// ToRelativeTemporalObject again
"get options.relativeTo.offset",
"get options.relativeTo.timeZone",
// AddDuration
"get options.relativeTo.calendar.dateAdd",
"call options.relativeTo.calendar.dateAdd",
"call options.relativeTo.calendar.dateAdd",
"get options.relativeTo.calendar.dateUntil",
"call options.relativeTo.calendar.dateUntil",
]);
const instance = new Temporal.Duration(1, 2, 0, 4, 5, 6, 7, 987, 654, 321);
const fields = TemporalHelpers.propertyBagObserver(actual, { const fields = TemporalHelpers.propertyBagObserver(actual, {
years: 1, years: 1,
months: 1, months: 1,
@ -55,6 +121,138 @@ const fields = TemporalHelpers.propertyBagObserver(actual, {
microseconds: 1, microseconds: 1,
nanoseconds: 1, nanoseconds: 1,
}, "fields"); }, "fields");
const result = instance.add(fields, { relativeTo });
TemporalHelpers.assertDuration(result, 2, 3, 0, 12, 6, 7, 8, 988, 655, 322); const plainRelativeTo = TemporalHelpers.propertyBagObserver(actual, {
assert.compareArray(actual, expected, "order of operations"); year: 2000,
month: 1,
monthCode: "M01",
day: 1,
calendar: TemporalHelpers.calendarObserver(actual, "options.relativeTo.calendar"),
}, "options.relativeTo");
instance.add(fields, createOptionsObserver(plainRelativeTo));
assert.compareArray(actual, expectedOpsForPlainRelativeTo, "order of operations with PlainDate relativeTo");
actual.splice(0); // clear
const expectedOpsForZonedRelativeTo = expected.concat([
// ToRelativeTemporalObject
"get options.relativeTo.calendar",
"has options.relativeTo.calendar.calendar",
"get options.relativeTo.calendar.fields",
"call options.relativeTo.calendar.fields",
// PrepareTemporalFields
"get options.relativeTo.day",
"get options.relativeTo.day.valueOf",
"call options.relativeTo.day.valueOf",
"get options.relativeTo.hour",
"get options.relativeTo.hour.valueOf",
"call options.relativeTo.hour.valueOf",
"get options.relativeTo.microsecond",
"get options.relativeTo.microsecond.valueOf",
"call options.relativeTo.microsecond.valueOf",
"get options.relativeTo.millisecond",
"get options.relativeTo.millisecond.valueOf",
"call options.relativeTo.millisecond.valueOf",
"get options.relativeTo.minute",
"get options.relativeTo.minute.valueOf",
"call options.relativeTo.minute.valueOf",
"get options.relativeTo.month",
"get options.relativeTo.month.valueOf",
"call options.relativeTo.month.valueOf",
"get options.relativeTo.monthCode",
"get options.relativeTo.monthCode.toString",
"call options.relativeTo.monthCode.toString",
"get options.relativeTo.nanosecond",
"get options.relativeTo.nanosecond.valueOf",
"call options.relativeTo.nanosecond.valueOf",
"get options.relativeTo.second",
"get options.relativeTo.second.valueOf",
"call options.relativeTo.second.valueOf",
"get options.relativeTo.year",
"get options.relativeTo.year.valueOf",
"call options.relativeTo.year.valueOf",
// InterpretTemporalDateTimeFields
"get options.relativeTo.calendar.dateFromFields",
"call options.relativeTo.calendar.dateFromFields",
// ToRelativeTemporalObject again
"get options.relativeTo.offset",
"get options.relativeTo.timeZone",
"has options.relativeTo.timeZone.timeZone",
"get options.relativeTo.offset.toString",
"call options.relativeTo.offset.toString",
// InterpretISODateTimeOffset
"get options.relativeTo.timeZone.getPossibleInstantsFor",
"call options.relativeTo.timeZone.getPossibleInstantsFor",
"get options.relativeTo.timeZone.getOffsetNanosecondsFor",
"call options.relativeTo.timeZone.getOffsetNanosecondsFor",
// AddDuration → AddZonedDateTime 1
"get options.relativeTo.timeZone.getOffsetNanosecondsFor",
"call options.relativeTo.timeZone.getOffsetNanosecondsFor",
"get options.relativeTo.calendar.dateAdd",
"call options.relativeTo.calendar.dateAdd",
"get options.relativeTo.timeZone.getPossibleInstantsFor",
"call options.relativeTo.timeZone.getPossibleInstantsFor",
// AddDuration → AddZonedDateTime 2
"get options.relativeTo.timeZone.getOffsetNanosecondsFor",
"call options.relativeTo.timeZone.getOffsetNanosecondsFor",
"get options.relativeTo.calendar.dateAdd",
"call options.relativeTo.calendar.dateAdd",
"get options.relativeTo.timeZone.getPossibleInstantsFor",
"call options.relativeTo.timeZone.getPossibleInstantsFor",
// AddDuration → DifferenceZonedDateTime
"get options.relativeTo.timeZone.getOffsetNanosecondsFor",
"call options.relativeTo.timeZone.getOffsetNanosecondsFor",
"get options.relativeTo.timeZone.getOffsetNanosecondsFor",
"call options.relativeTo.timeZone.getOffsetNanosecondsFor",
// AddDuration → DifferenceZonedDateTime → DifferenceISODateTime
"get options.relativeTo.calendar.dateUntil",
"call options.relativeTo.calendar.dateUntil",
// AddDuration → DifferenceZonedDateTime → AddZonedDateTime
"get options.relativeTo.timeZone.getOffsetNanosecondsFor",
"call options.relativeTo.timeZone.getOffsetNanosecondsFor",
"get options.relativeTo.calendar.dateAdd",
"call options.relativeTo.calendar.dateAdd",
"get options.relativeTo.timeZone.getPossibleInstantsFor",
"call options.relativeTo.timeZone.getPossibleInstantsFor",
// AddDuration → DifferenceZonedDateTime → NanosecondsToDays
"get options.relativeTo.timeZone.getOffsetNanosecondsFor",
"call options.relativeTo.timeZone.getOffsetNanosecondsFor",
"get options.relativeTo.timeZone.getOffsetNanosecondsFor",
"call options.relativeTo.timeZone.getOffsetNanosecondsFor",
// AddDuration → DifferenceZonedDateTime → NanosecondsToDays → DifferenceISODateTime
"get options.relativeTo.calendar.dateUntil",
"call options.relativeTo.calendar.dateUntil",
// AddDuration → DifferenceZonedDateTime → NanosecondsToDays → AddZonedDateTime 1
"get options.relativeTo.timeZone.getOffsetNanosecondsFor",
"call options.relativeTo.timeZone.getOffsetNanosecondsFor",
"get options.relativeTo.calendar.dateAdd",
"call options.relativeTo.calendar.dateAdd",
"get options.relativeTo.timeZone.getPossibleInstantsFor",
"call options.relativeTo.timeZone.getPossibleInstantsFor",
// AddDuration → DifferenceZonedDateTime → NanosecondsToDays → AddZonedDateTime 2
"get options.relativeTo.timeZone.getOffsetNanosecondsFor",
"call options.relativeTo.timeZone.getOffsetNanosecondsFor",
"get options.relativeTo.calendar.dateAdd",
"call options.relativeTo.calendar.dateAdd",
"get options.relativeTo.timeZone.getPossibleInstantsFor",
"call options.relativeTo.timeZone.getPossibleInstantsFor",
]);
const zonedRelativeTo = TemporalHelpers.propertyBagObserver(actual, {
year: 2000,
month: 1,
monthCode: "M01",
day: 1,
hour: 0,
minute: 0,
second: 0,
millisecond: 0,
microsecond: 0,
nanosecond: 0,
offset: "+00:00",
calendar: TemporalHelpers.calendarObserver(actual, "options.relativeTo.calendar"),
timeZone: TemporalHelpers.timeZoneObserver(actual, "options.relativeTo.timeZone"),
}, "options.relativeTo");
instance.add(fields, createOptionsObserver(zonedRelativeTo));
assert.compareArray(actual, expectedOpsForZonedRelativeTo, "order of operations with ZonedDateTime relativeTo");

View File

@ -23,6 +23,199 @@ const expected = [
"call options.roundingIncrement.valueOf", "call options.roundingIncrement.valueOf",
// ToRelativeTemporalObject // ToRelativeTemporalObject
"get options.relativeTo", "get options.relativeTo",
];
const actual = [];
function createOptionsObserver({ smallestUnit = "nanoseconds", largestUnit = "auto", roundingMode = "halfExpand", roundingIncrement = 1, relativeTo = undefined } = {}) {
return TemporalHelpers.propertyBagObserver(actual, {
smallestUnit,
largestUnit,
roundingMode,
roundingIncrement,
relativeTo,
}, "options");
}
const instance = new Temporal.Duration(0, 0, 0, 0, /* hours = */ 2400);
// basic order of operations, without relativeTo:
instance.round(createOptionsObserver({ smallestUnit: "microseconds" }));
assert.compareArray(actual, expected, "order of operations");
actual.splice(0); // clear
const expectedOpsForPlainRelativeTo = expected.concat([
// ToRelativeTemporalObject
"get options.relativeTo.calendar",
"has options.relativeTo.calendar.calendar",
"get options.relativeTo.calendar.fields",
"call options.relativeTo.calendar.fields",
"get options.relativeTo.day",
"get options.relativeTo.day.valueOf",
"call options.relativeTo.day.valueOf",
"get options.relativeTo.hour",
"get options.relativeTo.microsecond",
"get options.relativeTo.millisecond",
"get options.relativeTo.minute",
"get options.relativeTo.month",
"get options.relativeTo.month.valueOf",
"call options.relativeTo.month.valueOf",
"get options.relativeTo.monthCode",
"get options.relativeTo.monthCode.toString",
"call options.relativeTo.monthCode.toString",
"get options.relativeTo.nanosecond",
"get options.relativeTo.second",
"get options.relativeTo.year",
"get options.relativeTo.year.valueOf",
"call options.relativeTo.year.valueOf",
"get options.relativeTo.calendar.dateFromFields",
"call options.relativeTo.calendar.dateFromFields",
"get options.relativeTo.offset",
"get options.relativeTo.timeZone",
]);
const plainRelativeTo = TemporalHelpers.propertyBagObserver(actual, {
year: 2001,
month: 5,
monthCode: "M05",
day: 2,
calendar: TemporalHelpers.calendarObserver(actual, "options.relativeTo.calendar"),
}, "options.relativeTo");
// basic order of observable operations, without rounding:
instance.round(createOptionsObserver({ relativeTo: plainRelativeTo }));
assert.compareArray(actual, expectedOpsForPlainRelativeTo, "order of operations for PlainDate relativeTo");
actual.splice(0, actual.length); // clear
// code path through RoundDuration that rounds to the nearest year:
const expectedOpsForYearRounding = expectedOpsForPlainRelativeTo.concat([
"get options.relativeTo.calendar.dateAdd", // 9.b
"call options.relativeTo.calendar.dateAdd", // 9.c
"call options.relativeTo.calendar.dateAdd", // 9.e
"call options.relativeTo.calendar.dateAdd", // 9.j
"get options.relativeTo.calendar.dateUntil", // 9.m
"call options.relativeTo.calendar.dateUntil", // 9.m
"call options.relativeTo.calendar.dateAdd", // 9.r
"call options.relativeTo.calendar.dateAdd", // 9.w MoveRelativeDate
]);
instance.round(createOptionsObserver({ smallestUnit: "years", relativeTo: plainRelativeTo }));
assert.compareArray(actual, expectedOpsForYearRounding, "order of operations with smallestUnit = years");
actual.splice(0, actual.length); // clear
// code path through Duration.prototype.round that rounds to the nearest month:
const expectedOpsForMonthRounding = expectedOpsForPlainRelativeTo.concat([
// UnbalanceDurationRelative
"get options.relativeTo.calendar.dateAdd", // 9.b
"get options.relativeTo.calendar.dateUntil", // 9.c
"call options.relativeTo.calendar.dateAdd", // 9.d.i
"call options.relativeTo.calendar.dateUntil", // 9.d.iv
// RoundDuration
"get options.relativeTo.calendar.dateAdd", // 10.b
"call options.relativeTo.calendar.dateAdd", // 10.c
"call options.relativeTo.calendar.dateAdd", // 10.e
"call options.relativeTo.calendar.dateAdd", // 10.k MoveRelativeDate
], Array(2).fill("call options.relativeTo.calendar.dateAdd"), [ // 2× 10.n.iii MoveRelativeDate
// BalanceDurationRelative
"get options.relativeTo.calendar.dateAdd",
"call options.relativeTo.calendar.dateAdd",
]);
const instance2 = new Temporal.Duration(1, 0, 0, 62);
instance2.round(createOptionsObserver({ largestUnit: "months", smallestUnit: "months", relativeTo: plainRelativeTo }));
assert.compareArray(actual, expectedOpsForMonthRounding, "order of operations with largestUnit = smallestUnit = months");
actual.splice(0, actual.length); // clear
// code path through Duration.prototype.round that rounds to the nearest week:
const expectedOpsForWeekRounding = expectedOpsForPlainRelativeTo.concat([
// UnbalanceDurationRelative
"get options.relativeTo.calendar.dateAdd", // 10.b
"call options.relativeTo.calendar.dateAdd", // 10.c.i MoveRelativeDate
"call options.relativeTo.calendar.dateAdd", // 10.d.i MoveRelativeDate
// RoundDuration
"get options.relativeTo.calendar.dateAdd", // 11.c
"call options.relativeTo.calendar.dateAdd", // 11.d MoveRelativeDate
], Array(58).fill("call options.relativeTo.calendar.dateAdd"), [ // 58× 11.g.iii MoveRelativeDate (52 + 4 + 2)
// BalanceDurationRelative
"get options.relativeTo.calendar.dateAdd", // 12.b
"call options.relativeTo.calendar.dateAdd", // 12.c
]);
const instance3 = new Temporal.Duration(1, 1, 0, 15);
instance3.round(createOptionsObserver({ largestUnit: "weeks", smallestUnit: "weeks", relativeTo: plainRelativeTo }));
assert.compareArray(actual, expectedOpsForWeekRounding, "order of operations with largestUnit = smallestUnit = weeks");
actual.splice(0, actual.length); // clear
// code path through UnbalanceDurationRelative that rounds to the nearest day:
const expectedOpsForDayRounding = expectedOpsForPlainRelativeTo.concat([
"get options.relativeTo.calendar.dateAdd", // 11.a.ii
"call options.relativeTo.calendar.dateAdd", // 11.a.iii.1 MoveRelativeDate
"call options.relativeTo.calendar.dateAdd", // 11.a.iv.1 MoveRelativeDate
"call options.relativeTo.calendar.dateAdd", // 11.a.v.1 MoveRelativeDate
]);
const instance4 = new Temporal.Duration(1, 1, 1)
instance4.round(createOptionsObserver({ largestUnit: "days", smallestUnit: "days", relativeTo: plainRelativeTo }));
assert.compareArray(actual, expectedOpsForDayRounding, "order of operations with largestUnit = smallestUnit = days");
actual.splice(0, actual.length); // clear
// code path through BalanceDurationRelative balancing from days up to years:
const expectedOpsForDayToYearBalancing = expectedOpsForPlainRelativeTo.concat([
"get options.relativeTo.calendar.dateAdd", // 10.a
"call options.relativeTo.calendar.dateAdd", // 10.b MoveRelativeDate
"call options.relativeTo.calendar.dateAdd", // 10.e.iv MoveRelativeDate
"call options.relativeTo.calendar.dateAdd", // 10.f MoveRelativeDate
"call options.relativeTo.calendar.dateAdd", // 10.i.iv MoveRelativeDate
"call options.relativeTo.calendar.dateAdd", // 10.j
"get options.relativeTo.calendar.dateUntil", // 10.k
"call options.relativeTo.calendar.dateUntil", // 10.n
]);
const instance5 = new Temporal.Duration(0, 0, 0, 0, /* hours = */ 396 * 24);
instance5.round(createOptionsObserver({ largestUnit: "years", smallestUnit: "days", relativeTo: plainRelativeTo }));
assert.compareArray(actual, expectedOpsForDayToYearBalancing, "order of operations with largestUnit = years, smallestUnit = days");
actual.splice(0, actual.length); // clear
// code path through Duration.prototype.round balancing from months up to years:
const expectedOpsForMonthToYearBalancing = expectedOpsForPlainRelativeTo.concat([
// RoundDuration
"get options.relativeTo.calendar.dateAdd", // 10.b
"call options.relativeTo.calendar.dateAdd", // 10.c
"call options.relativeTo.calendar.dateAdd", // 10.e
"call options.relativeTo.calendar.dateAdd", // 10.k MoveRelativeDate
// BalanceDurationRelative
"get options.relativeTo.calendar.dateAdd", // 10.a
"call options.relativeTo.calendar.dateAdd", // 10.b MoveRelativeDate
"call options.relativeTo.calendar.dateAdd", // 10.f MoveRelativeDate
"call options.relativeTo.calendar.dateAdd", // 10.j
"get options.relativeTo.calendar.dateUntil", // 10.k
"call options.relativeTo.calendar.dateUntil", // 10.n
"call options.relativeTo.calendar.dateAdd", // 10.p.iv
"call options.relativeTo.calendar.dateUntil", // 10.p.vii
]);
const instance6 = new Temporal.Duration(0, 12);
instance6.round(createOptionsObserver({ largestUnit: "years", smallestUnit: "months", relativeTo: plainRelativeTo }));
assert.compareArray(actual, expectedOpsForMonthToYearBalancing, "order of operations with largestUnit = years, smallestUnit = months");
actual.splice(0, actual.length); // clear
const expectedOpsForDayToMonthBalancing = expectedOpsForPlainRelativeTo.concat([
// BalanceDurationRelative
"get options.relativeTo.calendar.dateAdd", // 11.a
"call options.relativeTo.calendar.dateAdd", // 11.b MoveRelativeDate
"call options.relativeTo.calendar.dateAdd", // 11.e.iv MoveRelativeDate
]);
const instance7 = new Temporal.Duration(0, 0, 0, 0, /* hours = */ 32 * 24);
instance7.round(createOptionsObserver({ largestUnit: "months", smallestUnit: "days", relativeTo: plainRelativeTo }));
assert.compareArray(actual, expectedOpsForDayToMonthBalancing, "order of operations with largestUnit = months, smallestUnit = days");
actual.splice(0, actual.length); // clear
const expectedOpsForDayToWeekBalancing = expectedOpsForPlainRelativeTo.concat([
// BalanceDurationRelative
"get options.relativeTo.calendar.dateAdd", // 12.b
"call options.relativeTo.calendar.dateAdd", // 12.c MoveRelativeDate
"call options.relativeTo.calendar.dateAdd", // 12.f.iv MoveRelativeDate
]);
const instance8 = new Temporal.Duration(0, 0, 0, 0, /* hours = */ 8 * 24);
instance8.round(createOptionsObserver({ largestUnit: "weeks", smallestUnit: "days", relativeTo: plainRelativeTo }));
assert.compareArray(actual, expectedOpsForDayToWeekBalancing, "order of operations with largestUnit = weeks, smallestUnit = days");
actual.splice(0, actual.length); // clear
const expectedOpsForZonedRelativeTo = expected.concat([
// ToRelativeTemporalObject
"get options.relativeTo.calendar", "get options.relativeTo.calendar",
"has options.relativeTo.calendar.calendar", "has options.relativeTo.calendar.calendar",
"get options.relativeTo.calendar.fields", "get options.relativeTo.calendar.fields",
@ -61,10 +254,20 @@ const expected = [
"call options.relativeTo.calendar.dateFromFields", "call options.relativeTo.calendar.dateFromFields",
"get options.relativeTo.offset", "get options.relativeTo.offset",
"get options.relativeTo.timeZone", "get options.relativeTo.timeZone",
]; "has options.relativeTo.timeZone.timeZone",
const actual = []; "get options.relativeTo.offset.toString",
"call options.relativeTo.offset.toString",
// InterpretISODateTimeOffset
"get options.relativeTo.timeZone.getPossibleInstantsFor",
"call options.relativeTo.timeZone.getPossibleInstantsFor",
"get options.relativeTo.timeZone.getOffsetNanosecondsFor",
"call options.relativeTo.timeZone.getOffsetNanosecondsFor",
// RoundDuration → ToTemporalDate
"get options.relativeTo.timeZone.getOffsetNanosecondsFor",
"call options.relativeTo.timeZone.getOffsetNanosecondsFor",
]);
const relativeTo = TemporalHelpers.propertyBagObserver(actual, { const zonedRelativeTo = TemporalHelpers.propertyBagObserver(actual, {
year: 2001, year: 2001,
month: 5, month: 5,
monthCode: "M05", monthCode: "M05",
@ -75,150 +278,11 @@ const relativeTo = TemporalHelpers.propertyBagObserver(actual, {
millisecond: 987, millisecond: 987,
microsecond: 654, microsecond: 654,
nanosecond: 321, nanosecond: 321,
offset: "+00:00",
calendar: TemporalHelpers.calendarObserver(actual, "options.relativeTo.calendar"), calendar: TemporalHelpers.calendarObserver(actual, "options.relativeTo.calendar"),
timeZone: TemporalHelpers.timeZoneObserver(actual, "options.relativeTo.timeZone"),
}, "options.relativeTo"); }, "options.relativeTo");
function createOptionsObserver({ smallestUnit = "nanoseconds", largestUnit = "auto", roundingMode = "halfExpand", roundingIncrement = 1, relativeTo = undefined } = {}) { // basic order of operations with ZonedDateTime relativeTo:
return TemporalHelpers.propertyBagObserver(actual, { instance.round(createOptionsObserver({ relativeTo: zonedRelativeTo }));
smallestUnit, assert.compareArray(actual, expectedOpsForZonedRelativeTo, "order of operations for ZonedDateTime relativeTo");
largestUnit,
roundingMode,
roundingIncrement,
relativeTo,
}, "options");
}
const instance = new Temporal.Duration(0, 0, 0, 0, /* hours = */ 2400);
// basic order of observable operations, without rounding:
instance.round(createOptionsObserver({ relativeTo }));
assert.compareArray(actual, expected, "order of operations");
actual.splice(0, actual.length); // clear
// code path through RoundDuration that rounds to the nearest year:
const expectedOpsForYearRounding = expected.concat([
"get options.relativeTo.calendar.dateAdd", // 9.b
"call options.relativeTo.calendar.dateAdd", // 9.c
"call options.relativeTo.calendar.dateAdd", // 9.e
"call options.relativeTo.calendar.dateAdd", // 9.j
"get options.relativeTo.calendar.dateUntil", // 9.m
"call options.relativeTo.calendar.dateUntil", // 9.m
"call options.relativeTo.calendar.dateAdd", // 9.r
"call options.relativeTo.calendar.dateAdd", // 9.w MoveRelativeDate
]);
instance.round(createOptionsObserver({ smallestUnit: "years", relativeTo }));
assert.compareArray(actual, expectedOpsForYearRounding, "order of operations with smallestUnit = years");
actual.splice(0, actual.length); // clear
// code path through Duration.prototype.round that rounds to the nearest month:
const expectedOpsForMonthRounding = expected.concat([
// UnbalanceDurationRelative
"get options.relativeTo.calendar.dateAdd", // 9.b
"get options.relativeTo.calendar.dateUntil", // 9.c
"call options.relativeTo.calendar.dateAdd", // 9.d.i
"call options.relativeTo.calendar.dateUntil", // 9.d.iv
// RoundDuration
"get options.relativeTo.calendar.dateAdd", // 10.b
"call options.relativeTo.calendar.dateAdd", // 10.c
"call options.relativeTo.calendar.dateAdd", // 10.e
"call options.relativeTo.calendar.dateAdd", // 10.k MoveRelativeDate
], Array(2).fill("call options.relativeTo.calendar.dateAdd"), [ // 2× 10.n.iii MoveRelativeDate
// BalanceDurationRelative
"get options.relativeTo.calendar.dateAdd",
"call options.relativeTo.calendar.dateAdd",
]);
const instance2 = new Temporal.Duration(1, 0, 0, 62);
instance2.round(createOptionsObserver({ largestUnit: "months", smallestUnit: "months", relativeTo }));
assert.compareArray(actual, expectedOpsForMonthRounding, "order of operations with largestUnit = smallestUnit = months");
actual.splice(0, actual.length); // clear
// code path through Duration.prototype.round that rounds to the nearest week:
const expectedOpsForWeekRounding = expected.concat([
// UnbalanceDurationRelative
"get options.relativeTo.calendar.dateAdd", // 10.b
"call options.relativeTo.calendar.dateAdd", // 10.c.i MoveRelativeDate
"call options.relativeTo.calendar.dateAdd", // 10.d.i MoveRelativeDate
// RoundDuration
"get options.relativeTo.calendar.dateAdd", // 11.c
"call options.relativeTo.calendar.dateAdd", // 11.d MoveRelativeDate
], Array(58).fill("call options.relativeTo.calendar.dateAdd"), [ // 58× 11.g.iii MoveRelativeDate (52 + 4 + 2)
// BalanceDurationRelative
"get options.relativeTo.calendar.dateAdd", // 12.b
"call options.relativeTo.calendar.dateAdd", // 12.c
]);
const instance3 = new Temporal.Duration(1, 1, 0, 15);
instance3.round(createOptionsObserver({ largestUnit: "weeks", smallestUnit: "weeks", relativeTo }));
assert.compareArray(actual, expectedOpsForWeekRounding, "order of operations with largestUnit = smallestUnit = weeks");
actual.splice(0, actual.length); // clear
// code path through UnbalanceDurationRelative that rounds to the nearest day:
const expectedOpsForDayRounding = expected.concat([
"get options.relativeTo.calendar.dateAdd", // 11.a.ii
"call options.relativeTo.calendar.dateAdd", // 11.a.iii.1 MoveRelativeDate
"call options.relativeTo.calendar.dateAdd", // 11.a.iv.1 MoveRelativeDate
"call options.relativeTo.calendar.dateAdd", // 11.a.v.1 MoveRelativeDate
]);
const instance4 = new Temporal.Duration(1, 1, 1)
instance4.round(createOptionsObserver({ largestUnit: "days", smallestUnit: "days", relativeTo }));
assert.compareArray(actual, expectedOpsForDayRounding, "order of operations with largestUnit = smallestUnit = days");
actual.splice(0, actual.length); // clear
// code path through BalanceDurationRelative balancing from days up to years:
const expectedOpsForDayToYearBalancing = expected.concat([
"get options.relativeTo.calendar.dateAdd", // 10.a
"call options.relativeTo.calendar.dateAdd", // 10.b MoveRelativeDate
"call options.relativeTo.calendar.dateAdd", // 10.e.iv MoveRelativeDate
"call options.relativeTo.calendar.dateAdd", // 10.f MoveRelativeDate
"call options.relativeTo.calendar.dateAdd", // 10.i.iv MoveRelativeDate
"call options.relativeTo.calendar.dateAdd", // 10.j
"get options.relativeTo.calendar.dateUntil", // 10.k
"call options.relativeTo.calendar.dateUntil", // 10.n
]);
const instance5 = new Temporal.Duration(0, 0, 0, 0, /* hours = */ 396 * 24);
instance5.round(createOptionsObserver({ largestUnit: "years", smallestUnit: "days", relativeTo }));
assert.compareArray(actual, expectedOpsForDayToYearBalancing, "order of operations with largestUnit = years, smallestUnit = days");
actual.splice(0, actual.length); // clear
// code path through Duration.prototype.round balancing from months up to years:
const expectedOpsForMonthToYearBalancing = expected.concat([
// RoundDuration
"get options.relativeTo.calendar.dateAdd", // 10.b
"call options.relativeTo.calendar.dateAdd", // 10.c
"call options.relativeTo.calendar.dateAdd", // 10.e
"call options.relativeTo.calendar.dateAdd", // 10.k MoveRelativeDate
// BalanceDurationRelative
"get options.relativeTo.calendar.dateAdd", // 10.a
"call options.relativeTo.calendar.dateAdd", // 10.b MoveRelativeDate
"call options.relativeTo.calendar.dateAdd", // 10.f MoveRelativeDate
"call options.relativeTo.calendar.dateAdd", // 10.j
"get options.relativeTo.calendar.dateUntil", // 10.k
"call options.relativeTo.calendar.dateUntil", // 10.n
"call options.relativeTo.calendar.dateAdd", // 10.p.iv
"call options.relativeTo.calendar.dateUntil", // 10.p.vii
]);
const instance6 = new Temporal.Duration(0, 12);
instance6.round(createOptionsObserver({ largestUnit: "years", smallestUnit: "months", relativeTo }));
assert.compareArray(actual, expectedOpsForMonthToYearBalancing, "order of operations with largestUnit = years, smallestUnit = months");
actual.splice(0, actual.length); // clear
const expectedOpsForDayToMonthBalancing = expected.concat([
// BalanceDurationRelative
"get options.relativeTo.calendar.dateAdd", // 11.a
"call options.relativeTo.calendar.dateAdd", // 11.b MoveRelativeDate
"call options.relativeTo.calendar.dateAdd", // 11.e.iv MoveRelativeDate
]);
const instance7 = new Temporal.Duration(0, 0, 0, 0, /* hours = */ 32 * 24);
instance7.round(createOptionsObserver({ largestUnit: "months", smallestUnit: "days", relativeTo }));
assert.compareArray(actual, expectedOpsForDayToMonthBalancing, "order of operations with largestUnit = months, smallestUnit = days");
actual.splice(0, actual.length); // clear
const expectedOpsForDayToWeekBalancing = expected.concat([
// BalanceDurationRelative
"get options.relativeTo.calendar.dateAdd", // 12.b
"call options.relativeTo.calendar.dateAdd", // 12.c MoveRelativeDate
"call options.relativeTo.calendar.dateAdd", // 12.f.iv MoveRelativeDate
]);
const instance8 = new Temporal.Duration(0, 0, 0, 0, /* hours = */ 8 * 24);
instance8.round(createOptionsObserver({ largestUnit: "weeks", smallestUnit: "days", relativeTo }));
assert.compareArray(actual, expectedOpsForDayToWeekBalancing, "order of operations with largestUnit = weeks, smallestUnit = days");
actual.splice(0, actual.length); // clear

View File

@ -8,9 +8,8 @@ includes: [compareArray.js, temporalHelpers.js]
features: [Temporal] features: [Temporal]
---*/ ---*/
const instance = new Temporal.Duration(1, 2, 1, 4, 5, 6, 7, 987, 654, 321);
const relativeTo = new Temporal.PlainDateTime(2000, 1, 1);
const expected = [ const expected = [
// ToTemporalDurationRecord
"get fields.days", "get fields.days",
"get fields.days.valueOf", "get fields.days.valueOf",
"call fields.days.valueOf", "call fields.days.valueOf",
@ -41,8 +40,75 @@ const expected = [
"get fields.years", "get fields.years",
"get fields.years.valueOf", "get fields.years.valueOf",
"call fields.years.valueOf", "call fields.years.valueOf",
// ToRelativeTemporalObject
"get options.relativeTo",
]; ];
const actual = []; const actual = [];
const simpleFields = TemporalHelpers.propertyBagObserver(actual, {
years: 0,
months: 0,
weeks: 0,
days: 1,
hours: 1,
minutes: 1,
seconds: 1,
milliseconds: 1,
microseconds: 1,
nanoseconds: 1,
}, "fields");
function createOptionsObserver(relativeTo = undefined) {
return TemporalHelpers.propertyBagObserver(actual, { relativeTo }, "options");
}
// basic order of observable operations, without any calendar units:
const simpleInstance = new Temporal.Duration(0, 0, 0, 1, 1, 1, 1, 1, 1, 1);
simpleInstance.subtract(simpleFields, createOptionsObserver());
assert.compareArray(actual, expected, "order of operations");
actual.splice(0); // clear
const expectedOpsForPlainRelativeTo = expected.concat([
// ToRelativeTemporalObject
"get options.relativeTo.calendar",
"has options.relativeTo.calendar.calendar",
"get options.relativeTo.calendar.fields",
"call options.relativeTo.calendar.fields",
// PrepareTemporalFields
"get options.relativeTo.day",
"get options.relativeTo.day.valueOf",
"call options.relativeTo.day.valueOf",
"get options.relativeTo.hour",
"get options.relativeTo.microsecond",
"get options.relativeTo.millisecond",
"get options.relativeTo.minute",
"get options.relativeTo.month",
"get options.relativeTo.month.valueOf",
"call options.relativeTo.month.valueOf",
"get options.relativeTo.monthCode",
"get options.relativeTo.monthCode.toString",
"call options.relativeTo.monthCode.toString",
"get options.relativeTo.nanosecond",
"get options.relativeTo.second",
"get options.relativeTo.year",
"get options.relativeTo.year.valueOf",
"call options.relativeTo.year.valueOf",
// InterpretTemporalDateTimeFields
"get options.relativeTo.calendar.dateFromFields",
"call options.relativeTo.calendar.dateFromFields",
// ToRelativeTemporalObject again
"get options.relativeTo.offset",
"get options.relativeTo.timeZone",
// AddDuration
"get options.relativeTo.calendar.dateAdd",
"call options.relativeTo.calendar.dateAdd",
"call options.relativeTo.calendar.dateAdd",
"get options.relativeTo.calendar.dateUntil",
"call options.relativeTo.calendar.dateUntil",
]);
const instance = new Temporal.Duration(1, 2, 1, 4, 5, 6, 7, 987, 654, 321);
const fields = TemporalHelpers.propertyBagObserver(actual, { const fields = TemporalHelpers.propertyBagObserver(actual, {
years: 1, years: 1,
months: 1, months: 1,
@ -55,6 +121,138 @@ const fields = TemporalHelpers.propertyBagObserver(actual, {
microseconds: 1, microseconds: 1,
nanoseconds: 1, nanoseconds: 1,
}, "fields"); }, "fields");
const result = instance.subtract(fields, { relativeTo });
TemporalHelpers.assertDuration(result, 0, 1, 0, 3, 4, 5, 6, 986, 653, 320); const plainRelativeTo = TemporalHelpers.propertyBagObserver(actual, {
assert.compareArray(actual, expected, "order of operations"); year: 2000,
month: 1,
monthCode: "M01",
day: 1,
calendar: TemporalHelpers.calendarObserver(actual, "options.relativeTo.calendar"),
}, "options.relativeTo");
instance.subtract(fields, createOptionsObserver(plainRelativeTo));
assert.compareArray(actual, expectedOpsForPlainRelativeTo, "order of operations with PlainDate relativeTo");
actual.splice(0); // clear
const expectedOpsForZonedRelativeTo = expected.concat([
// ToRelativeTemporalObject
"get options.relativeTo.calendar",
"has options.relativeTo.calendar.calendar",
"get options.relativeTo.calendar.fields",
"call options.relativeTo.calendar.fields",
// PrepareTemporalFields
"get options.relativeTo.day",
"get options.relativeTo.day.valueOf",
"call options.relativeTo.day.valueOf",
"get options.relativeTo.hour",
"get options.relativeTo.hour.valueOf",
"call options.relativeTo.hour.valueOf",
"get options.relativeTo.microsecond",
"get options.relativeTo.microsecond.valueOf",
"call options.relativeTo.microsecond.valueOf",
"get options.relativeTo.millisecond",
"get options.relativeTo.millisecond.valueOf",
"call options.relativeTo.millisecond.valueOf",
"get options.relativeTo.minute",
"get options.relativeTo.minute.valueOf",
"call options.relativeTo.minute.valueOf",
"get options.relativeTo.month",
"get options.relativeTo.month.valueOf",
"call options.relativeTo.month.valueOf",
"get options.relativeTo.monthCode",
"get options.relativeTo.monthCode.toString",
"call options.relativeTo.monthCode.toString",
"get options.relativeTo.nanosecond",
"get options.relativeTo.nanosecond.valueOf",
"call options.relativeTo.nanosecond.valueOf",
"get options.relativeTo.second",
"get options.relativeTo.second.valueOf",
"call options.relativeTo.second.valueOf",
"get options.relativeTo.year",
"get options.relativeTo.year.valueOf",
"call options.relativeTo.year.valueOf",
// InterpretTemporalDateTimeFields
"get options.relativeTo.calendar.dateFromFields",
"call options.relativeTo.calendar.dateFromFields",
// ToRelativeTemporalObject again
"get options.relativeTo.offset",
"get options.relativeTo.timeZone",
"has options.relativeTo.timeZone.timeZone",
"get options.relativeTo.offset.toString",
"call options.relativeTo.offset.toString",
// InterpretISODateTimeOffset
"get options.relativeTo.timeZone.getPossibleInstantsFor",
"call options.relativeTo.timeZone.getPossibleInstantsFor",
"get options.relativeTo.timeZone.getOffsetNanosecondsFor",
"call options.relativeTo.timeZone.getOffsetNanosecondsFor",
// AddDuration → AddZonedDateTime 1
"get options.relativeTo.timeZone.getOffsetNanosecondsFor",
"call options.relativeTo.timeZone.getOffsetNanosecondsFor",
"get options.relativeTo.calendar.dateAdd",
"call options.relativeTo.calendar.dateAdd",
"get options.relativeTo.timeZone.getPossibleInstantsFor",
"call options.relativeTo.timeZone.getPossibleInstantsFor",
// AddDuration → AddZonedDateTime 2
"get options.relativeTo.timeZone.getOffsetNanosecondsFor",
"call options.relativeTo.timeZone.getOffsetNanosecondsFor",
"get options.relativeTo.calendar.dateAdd",
"call options.relativeTo.calendar.dateAdd",
"get options.relativeTo.timeZone.getPossibleInstantsFor",
"call options.relativeTo.timeZone.getPossibleInstantsFor",
// AddDuration → DifferenceZonedDateTime
"get options.relativeTo.timeZone.getOffsetNanosecondsFor",
"call options.relativeTo.timeZone.getOffsetNanosecondsFor",
"get options.relativeTo.timeZone.getOffsetNanosecondsFor",
"call options.relativeTo.timeZone.getOffsetNanosecondsFor",
// AddDuration → DifferenceZonedDateTime → DifferenceISODateTime
"get options.relativeTo.calendar.dateUntil",
"call options.relativeTo.calendar.dateUntil",
// AddDuration → DifferenceZonedDateTime → AddZonedDateTime
"get options.relativeTo.timeZone.getOffsetNanosecondsFor",
"call options.relativeTo.timeZone.getOffsetNanosecondsFor",
"get options.relativeTo.calendar.dateAdd",
"call options.relativeTo.calendar.dateAdd",
"get options.relativeTo.timeZone.getPossibleInstantsFor",
"call options.relativeTo.timeZone.getPossibleInstantsFor",
// AddDuration → DifferenceZonedDateTime → NanosecondsToDays
"get options.relativeTo.timeZone.getOffsetNanosecondsFor",
"call options.relativeTo.timeZone.getOffsetNanosecondsFor",
"get options.relativeTo.timeZone.getOffsetNanosecondsFor",
"call options.relativeTo.timeZone.getOffsetNanosecondsFor",
// AddDuration → DifferenceZonedDateTime → NanosecondsToDays → DifferenceISODateTime
"get options.relativeTo.calendar.dateUntil",
"call options.relativeTo.calendar.dateUntil",
// AddDuration → DifferenceZonedDateTime → NanosecondsToDays → AddZonedDateTime 1
"get options.relativeTo.timeZone.getOffsetNanosecondsFor",
"call options.relativeTo.timeZone.getOffsetNanosecondsFor",
"get options.relativeTo.calendar.dateAdd",
"call options.relativeTo.calendar.dateAdd",
"get options.relativeTo.timeZone.getPossibleInstantsFor",
"call options.relativeTo.timeZone.getPossibleInstantsFor",
// AddDuration → DifferenceZonedDateTime → NanosecondsToDays → AddZonedDateTime 2
"get options.relativeTo.timeZone.getOffsetNanosecondsFor",
"call options.relativeTo.timeZone.getOffsetNanosecondsFor",
"get options.relativeTo.calendar.dateAdd",
"call options.relativeTo.calendar.dateAdd",
"get options.relativeTo.timeZone.getPossibleInstantsFor",
"call options.relativeTo.timeZone.getPossibleInstantsFor",
]);
const zonedRelativeTo = TemporalHelpers.propertyBagObserver(actual, {
year: 2000,
month: 1,
monthCode: "M01",
day: 1,
hour: 0,
minute: 0,
second: 0,
millisecond: 0,
microsecond: 0,
nanosecond: 0,
offset: "+00:00",
calendar: TemporalHelpers.calendarObserver(actual, "options.relativeTo.calendar"),
timeZone: TemporalHelpers.timeZoneObserver(actual, "options.relativeTo.timeZone"),
}, "options.relativeTo");
instance.subtract(fields, createOptionsObserver(zonedRelativeTo));
assert.compareArray(actual, expectedOpsForZonedRelativeTo, "order of operations with ZonedDateTime relativeTo");

View File

@ -9,6 +9,138 @@ features: [Temporal]
---*/ ---*/
const expected = [ const expected = [
"get options.relativeTo",
"get options.unit",
"get options.unit.toString",
"call options.unit.toString",
];
const actual = [];
function createOptionsObserver({ unit = "nanoseconds", roundingMode = "halfExpand", roundingIncrement = 1, relativeTo = undefined } = {}) {
return TemporalHelpers.propertyBagObserver(actual, {
unit,
roundingMode,
roundingIncrement,
relativeTo,
}, "options");
}
const instance = new Temporal.Duration(0, 0, 0, 0, 2400);
// basic order of observable operations, with no relativeTo
instance.total(createOptionsObserver({ unit: "nanoseconds" }));
assert.compareArray(actual, expected, "order of operations");
actual.splice(0); // clear
const expectedOpsForPlainRelativeTo = [
// ToRelativeTemporalObject
"get options.relativeTo",
"get options.relativeTo.calendar",
"has options.relativeTo.calendar.calendar",
"get options.relativeTo.calendar.fields",
"call options.relativeTo.calendar.fields",
"get options.relativeTo.day",
"get options.relativeTo.day.valueOf",
"call options.relativeTo.day.valueOf",
"get options.relativeTo.hour",
"get options.relativeTo.microsecond",
"get options.relativeTo.millisecond",
"get options.relativeTo.minute",
"get options.relativeTo.month",
"get options.relativeTo.month.valueOf",
"call options.relativeTo.month.valueOf",
"get options.relativeTo.monthCode",
"get options.relativeTo.monthCode.toString",
"call options.relativeTo.monthCode.toString",
"get options.relativeTo.nanosecond",
"get options.relativeTo.second",
"get options.relativeTo.year",
"get options.relativeTo.year.valueOf",
"call options.relativeTo.year.valueOf",
"get options.relativeTo.calendar.dateFromFields",
"call options.relativeTo.calendar.dateFromFields",
"get options.relativeTo.offset",
"get options.relativeTo.timeZone",
// GetTemporalUnit
"get options.unit",
"get options.unit.toString",
"call options.unit.toString",
];
const plainRelativeTo = TemporalHelpers.propertyBagObserver(actual, {
year: 2001,
month: 5,
monthCode: "M05",
day: 2,
calendar: TemporalHelpers.calendarObserver(actual, "options.relativeTo.calendar"),
}, "options.relativeTo");
// basic order of observable operations, without rounding:
instance.total(createOptionsObserver({ unit: "nanoseconds", relativeTo: plainRelativeTo }));
assert.compareArray(actual, expectedOpsForPlainRelativeTo, "order of operations for PlainDate relativeTo");
actual.splice(0, actual.length); // clear
// code path through RoundDuration that rounds to the nearest year:
const expectedOpsForYearRounding = expectedOpsForPlainRelativeTo.concat([
"get options.relativeTo.calendar.dateAdd", // 9.b
"call options.relativeTo.calendar.dateAdd", // 9.c
"call options.relativeTo.calendar.dateAdd", // 9.e
"call options.relativeTo.calendar.dateAdd", // 9.j
"get options.relativeTo.calendar.dateUntil", // 9.m
"call options.relativeTo.calendar.dateUntil", // 9.m
"call options.relativeTo.calendar.dateAdd", // 9.r
"call options.relativeTo.calendar.dateAdd", // 9.w MoveRelativeDate
]);
instance.total(createOptionsObserver({ unit: "years", relativeTo: plainRelativeTo }));
assert.compareArray(actual, expectedOpsForYearRounding, "order of operations with unit = years");
actual.splice(0, actual.length); // clear
// code path through Duration.prototype.total that rounds to the nearest month:
const expectedOpsForMonthRounding = expectedOpsForPlainRelativeTo.concat([
// UnbalanceDurationRelative
"get options.relativeTo.calendar.dateAdd", // 9.b
"get options.relativeTo.calendar.dateUntil", // 9.c
"call options.relativeTo.calendar.dateAdd", // 9.d.i
"call options.relativeTo.calendar.dateUntil", // 9.d.iv
// RoundDuration
"get options.relativeTo.calendar.dateAdd", // 10.b
"call options.relativeTo.calendar.dateAdd", // 10.c
"call options.relativeTo.calendar.dateAdd", // 10.e
"call options.relativeTo.calendar.dateAdd", // 10.k MoveRelativeDate
], Array(2).fill("call options.relativeTo.calendar.dateAdd")); // 2× 10.n.iii MoveRelativeDate
const instance2 = new Temporal.Duration(1, 0, 0, 62);
instance2.total(createOptionsObserver({ unit: "months", relativeTo: plainRelativeTo }));
assert.compareArray(actual, expectedOpsForMonthRounding, "order of operations with unit = months");
actual.splice(0, actual.length); // clear
// code path through Duration.prototype.total that rounds to the nearest week:
const expectedOpsForWeekRounding = expectedOpsForPlainRelativeTo.concat([
// UnbalanceDurationRelative
"get options.relativeTo.calendar.dateAdd", // 10.b
"call options.relativeTo.calendar.dateAdd", // 10.c.i MoveRelativeDate
"call options.relativeTo.calendar.dateAdd", // 10.d.i MoveRelativeDate
// RoundDuration
"get options.relativeTo.calendar.dateAdd", // 11.c
"call options.relativeTo.calendar.dateAdd", // 11.d MoveRelativeDate
], Array(58).fill("call options.relativeTo.calendar.dateAdd")); // 58× 11.g.iii MoveRelativeDate (52 + 4 + 2)
const instance3 = new Temporal.Duration(1, 1, 0, 15);
instance3.total(createOptionsObserver({ unit: "weeks", relativeTo: plainRelativeTo }));
assert.compareArray(actual, expectedOpsForWeekRounding, "order of operations with unit = weeks");
actual.splice(0, actual.length); // clear
// code path through UnbalanceDurationRelative that rounds to the nearest day:
const expectedOpsForDayRounding = expectedOpsForPlainRelativeTo.concat([
"get options.relativeTo.calendar.dateAdd", // 11.a.ii
"call options.relativeTo.calendar.dateAdd", // 11.a.iii.1 MoveRelativeDate
"call options.relativeTo.calendar.dateAdd", // 11.a.iv.1 MoveRelativeDate
"call options.relativeTo.calendar.dateAdd", // 11.a.v.1 MoveRelativeDate
]);
const instance4 = new Temporal.Duration(1, 1, 1)
instance4.total(createOptionsObserver({ unit: "days", relativeTo: plainRelativeTo }));
assert.compareArray(actual, expectedOpsForDayRounding, "order of operations with unit = days");
actual.splice(0, actual.length); // clear
const expectedOpsForZonedRelativeTo = [
// ToRelativeTemporalObject // ToRelativeTemporalObject
"get options.relativeTo", "get options.relativeTo",
"get options.relativeTo.calendar", "get options.relativeTo.calendar",
@ -49,14 +181,24 @@ const expected = [
"call options.relativeTo.calendar.dateFromFields", "call options.relativeTo.calendar.dateFromFields",
"get options.relativeTo.offset", "get options.relativeTo.offset",
"get options.relativeTo.timeZone", "get options.relativeTo.timeZone",
"has options.relativeTo.timeZone.timeZone",
"get options.relativeTo.offset.toString",
"call options.relativeTo.offset.toString",
// InterpretISODateTimeOffset
"get options.relativeTo.timeZone.getPossibleInstantsFor",
"call options.relativeTo.timeZone.getPossibleInstantsFor",
"get options.relativeTo.timeZone.getOffsetNanosecondsFor",
"call options.relativeTo.timeZone.getOffsetNanosecondsFor",
// GetTemporalUnit // GetTemporalUnit
"get options.unit", "get options.unit",
"get options.unit.toString", "get options.unit.toString",
"call options.unit.toString", "call options.unit.toString",
// RoundDuration → ToTemporalDate
"get options.relativeTo.timeZone.getOffsetNanosecondsFor",
"call options.relativeTo.timeZone.getOffsetNanosecondsFor",
]; ];
const actual = [];
const relativeTo = TemporalHelpers.propertyBagObserver(actual, { const zonedRelativeTo = TemporalHelpers.propertyBagObserver(actual, {
year: 2001, year: 2001,
month: 5, month: 5,
monthCode: "M05", monthCode: "M05",
@ -67,81 +209,11 @@ const relativeTo = TemporalHelpers.propertyBagObserver(actual, {
millisecond: 987, millisecond: 987,
microsecond: 654, microsecond: 654,
nanosecond: 321, nanosecond: 321,
offset: "+00:00",
calendar: TemporalHelpers.calendarObserver(actual, "options.relativeTo.calendar"), calendar: TemporalHelpers.calendarObserver(actual, "options.relativeTo.calendar"),
timeZone: TemporalHelpers.timeZoneObserver(actual, "options.relativeTo.timeZone"),
}, "options.relativeTo"); }, "options.relativeTo");
function createOptionsObserver({ unit = "nanoseconds", roundingMode = "halfExpand", roundingIncrement = 1, relativeTo = undefined } = {}) {
return TemporalHelpers.propertyBagObserver(actual, {
unit,
roundingMode,
roundingIncrement,
relativeTo,
}, "options");
}
const instance = new Temporal.Duration(0, 0, 0, 0, 2400);
// basic order of observable operations, without rounding: // basic order of observable operations, without rounding:
instance.total(createOptionsObserver({ unit: "nanoseconds", relativeTo })); instance.total(createOptionsObserver({ unit: "nanoseconds", relativeTo: zonedRelativeTo }));
assert.compareArray(actual, expected, "order of operations"); assert.compareArray(actual, expectedOpsForZonedRelativeTo, "order of operations for ZonedDateTime relativeTo");
actual.splice(0, actual.length); // clear
// code path through RoundDuration that rounds to the nearest year:
const expectedOpsForYearRounding = expected.concat([
"get options.relativeTo.calendar.dateAdd", // 9.b
"call options.relativeTo.calendar.dateAdd", // 9.c
"call options.relativeTo.calendar.dateAdd", // 9.e
"call options.relativeTo.calendar.dateAdd", // 9.j
"get options.relativeTo.calendar.dateUntil", // 9.m
"call options.relativeTo.calendar.dateUntil", // 9.m
"call options.relativeTo.calendar.dateAdd", // 9.r
"call options.relativeTo.calendar.dateAdd", // 9.w MoveRelativeDate
]);
instance.total(createOptionsObserver({ unit: "years", relativeTo }));
assert.compareArray(actual, expectedOpsForYearRounding, "order of operations with unit = years");
actual.splice(0, actual.length); // clear
// code path through Duration.prototype.total that rounds to the nearest month:
const expectedOpsForMonthRounding = expected.concat([
// UnbalanceDurationRelative
"get options.relativeTo.calendar.dateAdd", // 9.b
"get options.relativeTo.calendar.dateUntil", // 9.c
"call options.relativeTo.calendar.dateAdd", // 9.d.i
"call options.relativeTo.calendar.dateUntil", // 9.d.iv
// RoundDuration
"get options.relativeTo.calendar.dateAdd", // 10.b
"call options.relativeTo.calendar.dateAdd", // 10.c
"call options.relativeTo.calendar.dateAdd", // 10.e
"call options.relativeTo.calendar.dateAdd", // 10.k MoveRelativeDate
], Array(2).fill("call options.relativeTo.calendar.dateAdd")); // 2× 10.n.iii MoveRelativeDate
const instance2 = new Temporal.Duration(1, 0, 0, 62);
instance2.total(createOptionsObserver({ unit: "months", relativeTo }));
assert.compareArray(actual, expectedOpsForMonthRounding, "order of operations with unit = months");
actual.splice(0, actual.length); // clear
// code path through Duration.prototype.total that rounds to the nearest week:
const expectedOpsForWeekRounding = expected.concat([
// UnbalanceDurationRelative
"get options.relativeTo.calendar.dateAdd", // 10.b
"call options.relativeTo.calendar.dateAdd", // 10.c.i MoveRelativeDate
"call options.relativeTo.calendar.dateAdd", // 10.d.i MoveRelativeDate
// RoundDuration
"get options.relativeTo.calendar.dateAdd", // 11.c
"call options.relativeTo.calendar.dateAdd", // 11.d MoveRelativeDate
], Array(58).fill("call options.relativeTo.calendar.dateAdd")); // 58× 11.g.iii MoveRelativeDate (52 + 4 + 2)
const instance3 = new Temporal.Duration(1, 1, 0, 15);
instance3.total(createOptionsObserver({ unit: "weeks", relativeTo }));
assert.compareArray(actual, expectedOpsForWeekRounding, "order of operations with unit = weeks");
actual.splice(0, actual.length); // clear
// code path through UnbalanceDurationRelative that rounds to the nearest day:
const expectedOpsForDayRounding = expected.concat([
"get options.relativeTo.calendar.dateAdd", // 11.a.ii
"call options.relativeTo.calendar.dateAdd", // 11.a.iii.1 MoveRelativeDate
"call options.relativeTo.calendar.dateAdd", // 11.a.iv.1 MoveRelativeDate
"call options.relativeTo.calendar.dateAdd", // 11.a.v.1 MoveRelativeDate
]);
const instance4 = new Temporal.Duration(1, 1, 1)
instance4.total(createOptionsObserver({ unit: "days", relativeTo }));
assert.compareArray(actual, expectedOpsForDayRounding, "order of operations with unit = days");
actual.splice(0, actual.length); // clear