Temporal: Move some round() and total() tests out of staging

Including tests for every possible combination of largest and smallest
unit, for each type of relativeTo (undefined, PlainDate, ZonedDateTime).
This commit is contained in:
Philip Chimento 2024-04-02 16:32:05 -07:00 committed by Ms2ger
parent 96e31e7e28
commit e02220badd
8 changed files with 421 additions and 273 deletions

View File

@ -0,0 +1,111 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-temporal.duration.prototype.round
description: Test for all combinations of largestUnit and smallestUnit with relativeTo
includes: [temporalHelpers.js]
features: [Temporal]
---*/
const duration = new Temporal.Duration(5, 5, 5, 5, 5, 5, 5, 5, 5, 5);
const plainRelativeTo = new Temporal.PlainDate(2000, 1, 1);
const zonedRelativeTo = new Temporal.ZonedDateTime(63072000_000_000_000n /* = 1972-01-01T00Z */, "UTC");
const exactResults = {
years: {
years: [6],
months: [5, 6],
weeks: [5, 6, 1],
days: [5, 6, 0, 10],
hours: [5, 6, 0, 10, 5],
minutes: [5, 6, 0, 10, 5, 5],
seconds: [5, 6, 0, 10, 5, 5, 5],
milliseconds: [5, 6, 0, 10, 5, 5, 5, 5],
microseconds: [5, 6, 0, 10, 5, 5, 5, 5, 5],
nanoseconds: [5, 6, 0, 10, 5, 5, 5, 5, 5, 5],
},
months: {
months: [0, 66],
weeks: [0, 66, 1],
days: [0, 66, 0, 10],
hours: [0, 66, 0, 10, 5],
minutes: [0, 66, 0, 10, 5, 5],
seconds: [0, 66, 0, 10, 5, 5, 5],
milliseconds: [0, 66, 0, 10, 5, 5, 5, 5],
microseconds: [0, 66, 0, 10, 5, 5, 5, 5, 5],
nanoseconds: [0, 66, 0, 10, 5, 5, 5, 5, 5, 5],
},
weeks: {
weeks: [0, 0, 288],
days: [0, 0, 288, 2],
hours: [0, 0, 288, 2, 5],
minutes: [0, 0, 288, 2, 5, 5],
seconds: [0, 0, 288, 2, 5, 5, 5],
milliseconds: [0, 0, 288, 2, 5, 5, 5, 5],
microseconds: [0, 0, 288, 2, 5, 5, 5, 5, 5],
nanoseconds: [0, 0, 288, 2, 5, 5, 5, 5, 5, 5],
},
days: {
days: [0, 0, 0, 2018],
hours: [0, 0, 0, 2018, 5],
minutes: [0, 0, 0, 2018, 5, 5],
seconds: [0, 0, 0, 2018, 5, 5, 5],
milliseconds: [0, 0, 0, 2018, 5, 5, 5, 5],
microseconds: [0, 0, 0, 2018, 5, 5, 5, 5, 5],
nanoseconds: [0, 0, 0, 2018, 5, 5, 5, 5, 5, 5],
},
hours: {
hours: [0, 0, 0, 0, 48437],
minutes: [0, 0, 0, 0, 48437, 5],
seconds: [0, 0, 0, 0, 48437, 5, 5],
milliseconds: [0, 0, 0, 0, 48437, 5, 5, 5],
microseconds: [0, 0, 0, 0, 48437, 5, 5, 5, 5],
nanoseconds: [0, 0, 0, 0, 48437, 5, 5, 5, 5, 5],
},
minutes: {
minutes: [0, 0, 0, 0, 0, 2906225],
seconds: [0, 0, 0, 0, 0, 2906225, 5],
milliseconds: [0, 0, 0, 0, 0, 2906225, 5, 5],
microseconds: [0, 0, 0, 0, 0, 2906225, 5, 5, 5],
nanoseconds: [0, 0, 0, 0, 0, 2906225, 5, 5, 5, 5],
},
seconds: {
seconds: [0, 0, 0, 0, 0, 0, 174373505],
milliseconds: [0, 0, 0, 0, 0, 0, 174373505, 5],
microseconds: [0, 0, 0, 0, 0, 0, 174373505, 5, 5],
nanoseconds: [0, 0, 0, 0, 0, 0, 174373505, 5, 5, 5],
},
milliseconds: {
milliseconds: [0, 0, 0, 0, 0, 0, 0, 174373505005],
microseconds: [0, 0, 0, 0, 0, 0, 0, 174373505005, 5],
nanoseconds: [0, 0, 0, 0, 0, 0, 0, 174373505005, 5, 5],
},
microseconds: {
microseconds: [0, 0, 0, 0, 0, 0, 0, 0, 174373505005005],
nanoseconds: [0, 0, 0, 0, 0, 0, 0, 0, 174373505005005, 5],
},
};
for (const [largestUnit, entry] of Object.entries(exactResults)) {
for (const [smallestUnit, expected] of Object.entries(entry)) {
for (const relativeTo of [plainRelativeTo, zonedRelativeTo]) {
const [y, mon = 0, w = 0, d = 0, h = 0, min = 0, s = 0, ms = 0, µs = 0, ns = 0] = expected;
TemporalHelpers.assertDuration(
duration.round({ largestUnit, smallestUnit, relativeTo }),
y, mon, w, d, h, min, s, ms, µs, ns,
`Combination of largestUnit ${largestUnit} and smallestUnit ${smallestUnit}, relative to ${relativeTo}`
);
}
}
}
// 174373505005005005 is not a safe integer.
// (𝔽(174373505005005005)) == 174373505005004992
for (const relativeTo of [plainRelativeTo, zonedRelativeTo]) {
TemporalHelpers.assertDuration(
duration.round({ largestUnit: "nanoseconds", smallestUnit: "nanoseconds", relativeTo }),
0, 0, 0, 0, 0, 0, 0, 0, 0, 174373505005004992,
`Combination of largestUnit nanoseconds and smallestUnit nanoseconds, with precision loss, relative to ${relativeTo}`
);
}

View File

@ -0,0 +1,66 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-temporal.duration.prototype.round
description: Test for all combinations of largestUnit and smallestUnit without relativeTo
includes: [temporalHelpers.js]
features: [Temporal]
---*/
const duration = new Temporal.Duration(0, 0, 0, 5, 5, 5, 5, 5, 5, 5);
const exactResults = {
days: {
days: [5],
hours: [5, 5],
minutes: [5, 5, 5],
seconds: [5, 5, 5, 5],
milliseconds: [5, 5, 5, 5, 5],
microseconds: [5, 5, 5, 5, 5, 5],
nanoseconds: [5, 5, 5, 5, 5, 5, 5],
},
hours: {
hours: [0, 125],
minutes: [0, 125, 5],
seconds: [0, 125, 5, 5],
milliseconds: [0, 125, 5, 5, 5],
microseconds: [0, 125, 5, 5, 5, 5],
nanoseconds: [0, 125, 5, 5, 5, 5, 5],
},
minutes: {
minutes: [0, 0, 7505],
seconds: [0, 0, 7505, 5],
milliseconds: [0, 0, 7505, 5, 5],
microseconds: [0, 0, 7505, 5, 5, 5],
nanoseconds: [0, 0, 7505, 5, 5, 5, 5],
},
seconds: {
seconds: [0, 0, 0, 450305],
milliseconds: [0, 0, 0, 450305, 5],
microseconds: [0, 0, 0, 450305, 5, 5],
nanoseconds: [0, 0, 0, 450305, 5, 5, 5],
},
milliseconds: {
milliseconds: [0, 0, 0, 0, 450305005],
microseconds: [0, 0, 0, 0, 450305005, 5],
nanoseconds: [0, 0, 0, 0, 450305005, 5, 5],
},
microseconds: {
microseconds: [0, 0, 0, 0, 0, 450305005005],
nanoseconds: [0, 0, 0, 0, 0, 450305005005, 5],
},
nanoseconds: {
nanoseconds: [0, 0, 0, 0, 0, 0, 450305005005005],
},
};
for (const [largestUnit, entry] of Object.entries(exactResults)) {
for (const [smallestUnit, expected] of Object.entries(entry)) {
const [d = 0, h = 0, min = 0, s = 0, ms = 0, µs = 0, ns = 0] = expected;
TemporalHelpers.assertDuration(
duration.round({ largestUnit, smallestUnit }),
0, 0, 0, d, h, min, s, ms, µs, ns,
`Combination of largestUnit ${largestUnit} and smallestUnit ${smallestUnit}`
);
}
}

View File

@ -0,0 +1,146 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-temporal.duration.prototype.total
description: >
ZonedDateTime relativeTo affects day length when the duration encompasses a
DST change
includes: [temporalHelpers.js]
features: [Temporal]
---*/
const oneDay = new Temporal.Duration(0, 0, 0, 1);
const oneDayNeg = new Temporal.Duration(0, 0, 0, -1);
const hours12 = new Temporal.Duration(0, 0, 0, 0, 12);
const hours12Neg = new Temporal.Duration(0, 0, 0, 0, -12);
const hours25 = new Temporal.Duration(0, 0, 0, 0, 25);
const hours25Neg = new Temporal.Duration(0, 0, 0, 0, -25);
const hours48 = new Temporal.Duration(0, 0, 0, 0, 48);
const timeZone = TemporalHelpers.springForwardFallBackTimeZone();
const skippedHourDay = new Temporal.ZonedDateTime(
954662400_000_000_000n /* = 2000-04-02T08Z */,
timeZone); /* = 2000-04-02T00-08 in local time */
const repeatedHourDay = new Temporal.ZonedDateTime(
972802800_000_000_000n /* = 2000-10-29T07Z */,
timeZone); /* = 2000-10-29T00-07 in local time */
const inRepeatedHour = new Temporal.ZonedDateTime(
972806400_000_000_000n /* = 2000-10-29T08Z */,
timeZone); /* = 2000-10-29T01-07 in local time */
const oneDayAfterRepeatedHour = new Temporal.ZonedDateTime(
972896400_000_000_000n /* = 2000-10-30T09Z */,
timeZone); /* = 2000-10-30T01-08 in local time */
const beforeSkippedHour = new Temporal.ZonedDateTime(
954585000_000_000_000n /* = 2000-04-01T10:30Z */,
timeZone); /* = 2000-04-01T02:30-08 in local time */
const dayAfterSkippedHour = new Temporal.ZonedDateTime(
954745200_000_000_000n /* = 2000-04-03T07Z */,
timeZone); /* = 2000-04-03T00-07 in local time */
const afterSkippedHour = new Temporal.ZonedDateTime(
954702000_000_000_000n /* = 2000-04-02T19Z */,
timeZone); /* = 2000-04-02T12-07 in local time */
const afterRepeatedHour = new Temporal.ZonedDateTime(
972892800_000_000_000n /* = 2000-10-30T08Z */,
timeZone); /* = 2000-10-30T00-08 in local time */
const afterRepeatedHourSameDay = new Temporal.ZonedDateTime(
972849600_000_000_000n /* = 2000-10-29T20Z */,
timeZone); /* = 2000-10-29T12-08 in local time */
const beforeRepeatedHour = new Temporal.ZonedDateTime(
972716400_000_000_000n /* = 2000-10-28T07Z */,
timeZone); /* = 2000-10-28T00-07 in local time */
assert.sameValue(hours25.total({
unit: "days",
relativeTo: inRepeatedHour
}), 1, "start inside repeated hour, end after: 25 hours = 1 day");
assert.sameValue(oneDay.total({
unit: "hours",
relativeTo: inRepeatedHour
}), 25, "start inside repeated hour, end after: 1 day = 25 hours");
assert.sameValue(hours25Neg.total({
unit: "days",
relativeTo: oneDayAfterRepeatedHour
}), -1, "start after repeated hour, end inside: -25 hours = 1 day");
assert.sameValue(oneDayNeg.total({
unit: "hours",
relativeTo: oneDayAfterRepeatedHour
}), -25, "start after repeated hour, end inside: -1 day = -25 hours");
assert.sameValue(hours25.total({
unit: "days",
relativeTo: beforeSkippedHour
}), 24 / 23, "start in normal hour, end in skipped hour: 25 hours = 1 1/23 day");
assert.sameValue(oneDay.total({
unit: "hours",
relativeTo: beforeSkippedHour
}), 24, "start in normal hour, end in skipped hour: 1 day = 24 hours");
assert.sameValue(hours25.total({
unit: "days",
relativeTo: skippedHourDay
}), 13 / 12, "start before skipped hour, end >1 day after: 25 hours = 1 2/24 day");
assert.sameValue(oneDay.total({
unit: "hours",
relativeTo: skippedHourDay
}), 23, "start before skipped hour, end >1 day after: 1 day = 23 hours");
assert.sameValue(hours25Neg.total({
unit: "days",
relativeTo: dayAfterSkippedHour
}), -13 / 12, "start after skipped hour, end >1 day before: -25 hours = -1 2/24 day");
assert.sameValue(oneDayNeg.total({
unit: "hours",
relativeTo: dayAfterSkippedHour
}), -23, "start after skipped hour, end >1 day before: -1 day = -23 hours");
assert.sameValue(hours12.total({
unit: "days",
relativeTo: skippedHourDay
}), 12 / 23, "start before skipped hour, end <1 day after: 12 hours = 12/23 days");
assert.sameValue(hours12Neg.total({
unit: "days",
relativeTo: afterSkippedHour
}), -12 / 23, "start after skipped hour, end <1 day before: -12 hours = -12/23 days");
assert.sameValue(hours25.total({
unit: "days",
relativeTo: repeatedHourDay
}), 1, "start before repeated hour, end >1 day after: 25 hours = 1 day");
assert.sameValue(oneDay.total({
unit: "hours",
relativeTo: repeatedHourDay
}), 25, "start before repeated hour, end >1 day after: 1 day = 25 hours");
assert.sameValue(hours25Neg.total({
unit: "days",
relativeTo: afterRepeatedHour
}), -1, "start after repeated hour, end >1 day before: -25 hours = -1 day");
assert.sameValue(oneDayNeg.total({
unit: "hours",
relativeTo: afterRepeatedHour
}), -25, "start after repeated hour, end >1 day before: -1 day = -25 hours");
assert.sameValue(hours12.total({
unit: "days",
relativeTo: repeatedHourDay
}), 12 / 25, "start before repeated hour, end <1 day after: 12 hours = 12/25 days");
assert.sameValue(hours12Neg.total({
unit: "days",
relativeTo: afterRepeatedHourSameDay
}), -12 / 25, "start after repeated hour, end <1 day before: -12 hours = -12/25 days");
assert.sameValue(hours48.total({
unit: "days",
relativeTo: beforeRepeatedHour
}), 49 / 25, "start before repeated hour, end after: 48 hours = 1 24/25 days");

View File

@ -0,0 +1,27 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-temporal.duration.prototype.total
description: Total day length is 24 hours when not affected by DST
features: [Temporal]
---*/
const oneDay = new Temporal.Duration(0, 0, 0, 1);
const hours48 = new Temporal.Duration(0, 0, 0, 0, 48);
assert.sameValue(oneDay.total("hours"), 24, "with no relativeTo, days are 24 hours");
assert.sameValue(hours48.total({ unit: "days" }), 2, "with no relativeTo, 48 hours = 2 days");
const plainRelativeTo = new Temporal.PlainDate(2017, 1, 1);
assert.sameValue(oneDay.total({ unit: "hours", relativeTo: plainRelativeTo }), 24,
"with PlainDate relativeTo, days are 24 hours");
assert.sameValue(hours48.total({ unit: "days", relativeTo: plainRelativeTo }), 2,
"with PlainDate relativeTo, 48 hours = 2 days")
const zonedRelativeTo = new Temporal.ZonedDateTime(1_000_000_000_000_000_000n, "+04:30");
assert.sameValue(oneDay.total({ unit: "hours", relativeTo: zonedRelativeTo }), 24,
"with ZonedDateTime relativeTo, days are 24 hours if the duration encompasses no DST change");
assert.sameValue(hours48.total({ unit: "days", relativeTo: zonedRelativeTo }), 2,
"with ZonedDateTime relativeTo, 48 hours = 2 days if the duration encompasses no DST change");

View File

@ -0,0 +1,43 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-temporal.duration.prototype.total
description: Test representative result for all units, with relativeTo
features: [Temporal]
---*/
const duration = new Temporal.Duration(5, 5, 5, 5, 5, 5, 5, 5, 5, 5);
const plainRelativeTo = new Temporal.PlainDate(2000, 1, 1);
const zonedRelativeTo = new Temporal.ZonedDateTime(63072000_000_000_000n /* = 1972-01-01T00Z */, "UTC");
const dayMilliseconds = 24 * 3600 * 1000;
const fullYears = 5;
const fullMonths = fullYears * 12 + 5 + 1;
const fullDays = 366 + 365 + 365 + 365 + 366 + 31 + 28 + 31 + 30 + 31 + 5 * 7 + 5;
const fullMilliseconds = fullDays * dayMilliseconds + 5 * 3600_000 + 5 * 60_000 + 5000 + 5;
const partialDayMilliseconds = fullMilliseconds - fullDays * dayMilliseconds + 0.005005;
const fractionalDay = partialDayMilliseconds / dayMilliseconds;
const partialYearDays = fullDays - (fullYears * 365 + 2);
const fractionalYear = partialYearDays / 365 + fractionalDay / 365;
const fractionalMonths = (10 /* = 2025-07-11 - 2025-07-01 */ * dayMilliseconds + partialDayMilliseconds) / (31 * dayMilliseconds);
const totalResults = {
years: fullYears + fractionalYear,
months: fullMonths + fractionalMonths,
weeks: Math.floor(fullDays / 7) + (2 + fractionalDay) / 7,
days: fullDays + fractionalDay,
hours: fullDays * 24 + partialDayMilliseconds / 3600000,
minutes: fullDays * 24 * 60 + partialDayMilliseconds / 60000,
seconds: fullDays * 24 * 60 * 60 + partialDayMilliseconds / 1000,
milliseconds: fullMilliseconds + 0.005005,
microseconds: fullMilliseconds * 1000 + 5.005,
nanoseconds: fullMilliseconds * 1000000 + 5005
};
for (const [unit, expected] of Object.entries(totalResults)) {
for (const relativeTo of [plainRelativeTo, zonedRelativeTo]) {
assert.sameValue(
duration.total({ unit, relativeTo }), expected,
`Duration.total results for ${unit} relative to ${relativeTo}`
);
}
}

View File

@ -0,0 +1,28 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-temporal.duration.prototype.total
description: Test representative result for all units, without relativeTo
features: [Temporal]
---*/
const duration = new Temporal.Duration(0, 0, 0, 5, 5, 5, 5, 5, 5, 5);
const dayMilliseconds = 24 * 3600 * 1000;
const fullDays = 5;
const fullMilliseconds = fullDays * dayMilliseconds + 5 * 3600_000 + 5 * 60_000 + 5000 + 5;
const partialDayMilliseconds = fullMilliseconds - fullDays * dayMilliseconds + 0.005005;
const fractionalDay = partialDayMilliseconds / dayMilliseconds;
const totalResults = {
days: fullDays + fractionalDay,
hours: fullDays * 24 + partialDayMilliseconds / 3600000,
minutes: fullDays * 24 * 60 + partialDayMilliseconds / 60000,
seconds: fullDays * 24 * 60 * 60 + partialDayMilliseconds / 1000,
milliseconds: fullMilliseconds + 0.005005,
microseconds: fullMilliseconds * 1000 + 5.005,
nanoseconds: fullMilliseconds * 1000000 + 5005
};
for (const [unit, expected] of Object.entries(totalResults)) {
assert.sameValue(duration.total(unit), expected, `Duration.total results for ${unit}`);
}

View File

@ -320,103 +320,6 @@ assert.throws(RangeError, () => d.round({ largestUnit: "nanoseconds" }));
var relativeTo = Temporal.PlainDate.from("2020-01-01");
var fortyDays = Temporal.Duration.from({ days: 40 });
assert.sameValue(`${ fortyDays.round({ smallestUnit: "seconds" }) }`, "P40D");
var roundAndBalanceResults = {
years: {
years: "P6Y",
months: "P5Y6M",
weeks: "P5Y6M1W",
days: "P5Y6M10D",
hours: "P5Y6M10DT5H",
minutes: "P5Y6M10DT5H5M",
seconds: "P5Y6M10DT5H5M5S",
milliseconds: "P5Y6M10DT5H5M5.005S",
microseconds: "P5Y6M10DT5H5M5.005005S",
nanoseconds: "P5Y6M10DT5H5M5.005005005S"
},
months: {
months: "P66M",
weeks: "P66M1W",
days: "P66M10D",
hours: "P66M10DT5H",
minutes: "P66M10DT5H5M",
seconds: "P66M10DT5H5M5S",
milliseconds: "P66M10DT5H5M5.005S",
microseconds: "P66M10DT5H5M5.005005S",
nanoseconds: "P66M10DT5H5M5.005005005S"
},
weeks: {
weeks: "P288W",
days: "P288W2D",
hours: "P288W2DT5H",
minutes: "P288W2DT5H5M",
seconds: "P288W2DT5H5M5S",
milliseconds: "P288W2DT5H5M5.005S",
microseconds: "P288W2DT5H5M5.005005S",
nanoseconds: "P288W2DT5H5M5.005005005S"
},
days: {
days: "P2018D",
hours: "P2018DT5H",
minutes: "P2018DT5H5M",
seconds: "P2018DT5H5M5S",
milliseconds: "P2018DT5H5M5.005S",
microseconds: "P2018DT5H5M5.005005S",
nanoseconds: "P2018DT5H5M5.005005005S"
},
hours: {
hours: "PT48437H",
minutes: "PT48437H5M",
seconds: "PT48437H5M5S",
milliseconds: "PT48437H5M5.005S",
microseconds: "PT48437H5M5.005005S",
nanoseconds: "PT48437H5M5.005005005S"
},
minutes: {
minutes: "PT2906225M",
seconds: "PT2906225M5S",
milliseconds: "PT2906225M5.005S",
microseconds: "PT2906225M5.005005S",
nanoseconds: "PT2906225M5.005005005S"
},
seconds: {
seconds: "PT174373505S",
milliseconds: "PT174373505.005S",
microseconds: "PT174373505.005005S",
nanoseconds: "PT174373505.005005005S"
},
milliseconds: {
milliseconds: "PT174373505.005S",
microseconds: "PT174373505.005005S",
nanoseconds: "PT174373505.005005005S"
}
};
for (var [largestUnit, entry] of Object.entries(roundAndBalanceResults)) {
for (var [smallestUnit, expected] of Object.entries(entry)) {
assert.sameValue(`${ d.round({
largestUnit,
smallestUnit,
relativeTo
}) }`, expected);
}
}
var balanceLosePrecisionResults = {
microseconds: [
"microseconds",
"nanoseconds"
],
nanoseconds: ["nanoseconds"]
};
// Round may lose precision below ms
for (var [largestUnit, entry] of Object.entries(balanceLosePrecisionResults)) {
for (var smallestUnit of entry) {
assert(`${ d.round({
largestUnit,
smallestUnit,
relativeTo
}) }`.startsWith("PT174373505.005"));
}
}
// halfExpand is the default
assert.sameValue(`${ d.round({

View File

@ -172,47 +172,6 @@ assert(Math.abs(negativeD2.total({ unit: "seconds" }) - -totalD2.seconds) < Numb
assert(Math.abs(negativeD2.total({ unit: "milliseconds" }) - -totalD2.milliseconds) < Number.EPSILON);
assert(Math.abs(negativeD2.total({ unit: "microseconds" }) - -totalD2.microseconds) < Number.EPSILON);
assert.sameValue(negativeD2.total({ unit: "nanoseconds" }), -totalD2.nanoseconds);
var endpoint = relativeTo.toPlainDateTime().add(d);
var options = unit => ({
largestUnit: unit,
smallestUnit: unit,
roundingMode: "trunc"
});
var fullYears = 5;
var fullDays = endpoint.since(relativeTo, options("days")).days;
var fullMilliseconds = endpoint.since(relativeTo, options("milliseconds")).milliseconds;
var partialDayMilliseconds = fullMilliseconds - fullDays * 24 * 3600000 + 0.005005;
var fractionalDay = partialDayMilliseconds / (24 * 3600000);
var partialYearDays = fullDays - (fullYears * 365 + 2);
var fractionalYear = partialYearDays / 365 + fractionalDay / 365;
var fractionalMonths = ((endpoint.day - 1) * (24 * 3600000) + partialDayMilliseconds) / (31 * 24 * 3600000);
var totalResults = {
years: fullYears + fractionalYear,
months: 66 + fractionalMonths,
weeks: (fullDays + fractionalDay) / 7,
days: fullDays + fractionalDay,
hours: fullDays * 24 + partialDayMilliseconds / 3600000,
minutes: fullDays * 24 * 60 + partialDayMilliseconds / 60000,
seconds: fullDays * 24 * 60 * 60 + partialDayMilliseconds / 1000,
milliseconds: fullMilliseconds + 0.005005,
microseconds: fullMilliseconds * 1000 + 5.005,
nanoseconds: fullMilliseconds * 1000000 + 5005
};
for (var [unit, expected] of Object.entries(totalResults)) {
assert.sameValue(d.total({
unit,
relativeTo
}).toPrecision(15), expected.toPrecision(15));
}
for (var unit of [
"microseconds",
"nanoseconds"
]) {
assert(d.total({
unit,
relativeTo
}).toString().startsWith("174373505005"));
}
// balances differently depending on relativeTo
var fortyDays = Temporal.Duration.from({ days: 40 });
@ -237,135 +196,9 @@ assert.sameValue(negativeFortyDays.total({
}).toPrecision(16), (-(1 + 9 / 29)).toPrecision(16));
var oneDay = new Temporal.Duration(0, 0, 0, 1);
// relativeTo does not affect days if PlainDate
var relativeTo = Temporal.PlainDate.from("2017-01-01");
assert.sameValue(oneDay.total({
unit: "hours",
relativeTo
}), 24);
// relativeTo does not affect days if ZonedDateTime, and duration encompasses no DST change
var relativeTo = Temporal.ZonedDateTime.from("2017-01-01T00:00[+04:30]");
assert.sameValue(oneDay.total({
unit: "hours",
relativeTo
}), 24);
// relativeTo affects days if ZonedDateTime, and duration encompasses DST change"
var timeZone = TemporalHelpers.springForwardFallBackTimeZone();
var skippedHourDay = Temporal.PlainDateTime.from("2000-04-02").toZonedDateTime(timeZone);
var repeatedHourDay = Temporal.PlainDateTime.from("2000-10-29").toZonedDateTime(timeZone);
var inRepeatedHour = new Temporal.ZonedDateTime(972806400_000_000_000n, timeZone);
var hours12 = new Temporal.Duration(0, 0, 0, 0, 12);
var hours25 = new Temporal.Duration(0, 0, 0, 0, 25);
// start inside repeated hour, end after
assert.sameValue(hours25.total({
unit: "days",
relativeTo: inRepeatedHour
}), 1);
assert.sameValue(oneDay.total({
unit: "hours",
relativeTo: inRepeatedHour
}), 25);
// start after repeated hour, end inside (negative)
var relativeTo = Temporal.PlainDateTime.from("2000-10-30T01:00").toZonedDateTime(timeZone);
assert.sameValue(hours25.negated().total({
unit: "days",
relativeTo
}), -1);
assert.sameValue(oneDay.negated().total({
unit: "hours",
relativeTo
}), -25);
// start in normal hour, end in skipped hour
var relativeTo = Temporal.PlainDateTime.from("2000-04-01T02:30").toZonedDateTime(timeZone);
var totalDays = hours25.total({
unit: "days",
relativeTo
});
assert(Math.abs(totalDays - (1 + 1 / 23)) < Number.EPSILON);
assert.sameValue(oneDay.total({
unit: "hours",
relativeTo
}), 24);
// start before skipped hour, end >1 day after
var totalDays = hours25.total({
unit: "days",
relativeTo: skippedHourDay
});
assert(Math.abs(totalDays - (1 + 2 / 24)) < Number.EPSILON);
assert.sameValue(oneDay.total({
unit: "hours",
relativeTo: skippedHourDay
}), 23);
// start after skipped hour, end >1 day before (negative)
var relativeTo = Temporal.PlainDateTime.from("2000-04-03T00:00").toZonedDateTime(timeZone);
var totalDays = hours25.negated().total({
unit: "days",
relativeTo
});
assert(Math.abs(totalDays - (-1 - 2 / 24)) < Number.EPSILON);
assert.sameValue(oneDay.negated().total({
unit: "hours",
relativeTo
}), -23);
// start before skipped hour, end <1 day after
var totalDays = hours12.total({
unit: "days",
relativeTo: skippedHourDay
});
assert(Math.abs(totalDays - 12 / 23) < Number.EPSILON);
// start after skipped hour, end <1 day before (negative)
var relativeTo = Temporal.PlainDateTime.from("2000-04-02T12:00").toZonedDateTime(timeZone);
var totalDays = hours12.negated().total({
unit: "days",
relativeTo
});
assert(Math.abs(totalDays - -12 / 23) < Number.EPSILON);
// start before repeated hour, end >1 day after
assert.sameValue(hours25.total({
unit: "days",
relativeTo: repeatedHourDay
}), 1);
assert.sameValue(oneDay.total({
unit: "hours",
relativeTo: repeatedHourDay
}), 25);
// start after repeated hour, end >1 day before (negative)
var relativeTo = Temporal.PlainDateTime.from("2000-10-30T00:00").toZonedDateTime(timeZone);
assert.sameValue(hours25.negated().total({
unit: "days",
relativeTo
}), -1);
assert.sameValue(oneDay.negated().total({
unit: "hours",
relativeTo
}), -25);
// start before repeated hour, end <1 day after
var totalDays = hours12.total({
unit: "days",
relativeTo: repeatedHourDay
});
assert(Math.abs(totalDays - 12 / 25) < Number.EPSILON);
// start after repeated hour, end <1 day before (negative)
var relativeTo = Temporal.PlainDateTime.from("2000-10-29T12:00").toZonedDateTime(timeZone);
var totalDays = hours12.negated().total({
unit: "days",
relativeTo
});
assert(Math.abs(totalDays - -12 / 25) < Number.EPSILON);
// Samoa skipped 24 hours
var fakeSamoa = TemporalHelpers.crossDateLineTimeZone();
var relativeTo = Temporal.PlainDateTime.from("2011-12-29T12:00").toZonedDateTime(fakeSamoa);
@ -387,15 +220,6 @@ assert.sameValue(Temporal.Duration.from({ days: 3 }).total({
relativeTo
}), 48);
// totaling back up to days
var relativeTo = Temporal.PlainDateTime.from("2000-10-28T00:00").toZonedDateTime(timeZone);
assert.sameValue(Temporal.Duration.from({ hours: 48 }).total({ unit: "days" }), 2);
var totalDays = Temporal.Duration.from({ hours: 48 }).total({
unit: "days",
relativeTo
});
assert(Math.abs(totalDays - (1 + 24 / 25)) < Number.EPSILON);
// casts relativeTo to ZonedDateTime if possible
assert.sameValue(oneDay.total({
unit: "hours",