Skip to content

Commit

Permalink
Tests for Duration rounding bug when rounding crosses a unit boundary
Browse files Browse the repository at this point in the history
See tc39/proposal-temporal#2563

The old behaviour was encoded in one test in staging, but the behaviour of
largestUnit in duration rounding has changed since that test was written.
Therefore I'm assuming that toString() should've been updated when that
happened.
  • Loading branch information
ptomato committed Sep 28, 2023
1 parent aea7013 commit d402459
Show file tree
Hide file tree
Showing 15 changed files with 331 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright (C) 2023 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: Rounding can cross unit boundaries up to the implicit largestUnit
includes: [temporalHelpers.js]
features: [Temporal]
---*/

const relativeTo = new Temporal.PlainDate(2022, 1, 1);
const roundingMode = "expand";

// Positive, date units
{
const duration = new Temporal.Duration(1, 11, 0, 24);
const result = duration.round({ smallestUnit: "months", roundingMode, relativeTo });
TemporalHelpers.assertDuration(result, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, "1 year 12 months balances to 2 years");
}

// Negative, date units
{
const duration = new Temporal.Duration(-1, -11, 0, -24);
const result = duration.round({ smallestUnit: "months", roundingMode, relativeTo });
TemporalHelpers.assertDuration(result, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, "-1 year -12 months balances to -2 years");
}

// Positive, time units
{
const duration = new Temporal.Duration(0, 0, 0, 0, 1, 59, 59, 900);
const result = duration.round({ smallestUnit: "seconds", roundingMode });
TemporalHelpers.assertDuration(result, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, "1:59:60 balances to 2 hours");
}

// Negative, time units
{
const duration = new Temporal.Duration(0, 0, 0, 0, -1, -59, -59, -900);
const result = duration.round({ smallestUnit: "seconds", roundingMode });
TemporalHelpers.assertDuration(result, 0, 0, 0, 0, -2, 0, 0, 0, 0, 0, "-1:59:60 balances to -2 hours");
}

// No balancing if smallest unit is largest unit
{
const duration = new Temporal.Duration(0, 11, 0, 24);
const result = duration.round({ smallestUnit: "months", roundingMode, relativeTo });
TemporalHelpers.assertDuration(result, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, "12 months stays as is");
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright (C) 2023 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-temporal.duration.prototype.tostring
description: Rounding can cross unit boundaries up to days
features: [Temporal]
---*/

const roundingMode = "expand";

// Positive, time units
{
const duration = new Temporal.Duration(0, 0, 0, 0, 1, 59, 59, 900);
assert.sameValue(duration.toString({ fractionalSecondDigits: 0, roundingMode }), "PT2H0S", "1:59:60 balances to 2 hours");
}

// Negative, time units
{
const duration = new Temporal.Duration(0, 0, 0, 0, -1, -59, -59, -900);
assert.sameValue(duration.toString({ fractionalSecondDigits: 0, roundingMode }), "-PT2H0S", "-1:59:60 balances to -2 hours");
}

// Positive, date and time units
{
const duration = new Temporal.Duration(1, 11, 0, 30, 23, 59, 59, 999, 999, 999);
assert.sameValue(duration.toString({ fractionalSecondDigits: 8, roundingMode }), "P1Y11M31DT0.00000000S", "units balance only up to days (positive)");
}

// Negative, date and time units
{
const duration = new Temporal.Duration(-1, -11, 0, -30, -23, -59, -59, -999, -999, -999);
assert.sameValue(duration.toString({ fractionalSecondDigits: 8, roundingMode }), "-P1Y11M31DT0.00000000S", "units balance only up to days (negative)");
}

// No balancing if smallest unit is largest unit
{
const duration = new Temporal.Duration(0, 0, 0, 0, 0, 0, 59, 900);
assert.sameValue(duration.toString({ fractionalSecondDigits: 0, roundingMode }), "PT60S", "60 seconds stays as is");
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright (C) 2023 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-temporal.instant.prototype.since
description: Rounding can cross unit boundaries up to largestUnit
includes: [temporalHelpers.js]
features: [Temporal]
---*/

const earlier = new Temporal.Instant(0n);
const later = new Temporal.Instant(7199_000_000_000n);
const duration = earlier.since(later, { largestUnit: "hours", smallestUnit: "minutes", roundingMode: "expand" });
TemporalHelpers.assertDuration(duration, 0, 0, 0, 0, -2, 0, 0, 0, 0, 0, "-1:59 balances to -2 hours");
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright (C) 2023 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-temporal.instant.prototype.until
description: Rounding can cross unit boundaries up to largestUnit
includes: [temporalHelpers.js]
features: [Temporal]
---*/

const earlier = new Temporal.Instant(0n);
const later = new Temporal.Instant(7199_000_000_000n);
const duration = earlier.until(later, { largestUnit: "hours", smallestUnit: "minutes", roundingMode: "expand" });
TemporalHelpers.assertDuration(duration, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, "1:59 balances to 2 hours");
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright (C) 2023 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-temporal.plaindate.prototype.since
description: Rounding can cross unit boundaries up to largestUnit
includes: [temporalHelpers.js]
features: [Temporal]
---*/

const earlier = new Temporal.PlainDate(2022, 1, 1);
const later = new Temporal.PlainDate(2023, 12, 25);
const duration = earlier.since(later, { largestUnit: "years", smallestUnit: "months", roundingMode: "expand" });
TemporalHelpers.assertDuration(duration, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, "-1 year -11 months balances to -2 years");
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright (C) 2023 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-temporal.plaindate.prototype.until
description: Rounding can cross unit boundaries up to largestUnit
includes: [temporalHelpers.js]
features: [Temporal]
---*/

const earlier = new Temporal.PlainDate(2022, 1, 1);
const later = new Temporal.PlainDate(2023, 12, 25);
const duration = earlier.until(later, { largestUnit: "years", smallestUnit: "months", roundingMode: "expand" });
TemporalHelpers.assertDuration(duration, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, "1 year 11 months balances to 2 years");
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright (C) 2023 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-temporal.plaindatetime.prototype.since
description: Rounding can cross unit boundaries up to largestUnit
includes: [temporalHelpers.js]
features: [Temporal]
---*/

// Date units
{
const earlier = new Temporal.PlainDateTime(2022, 1, 1);
const later = new Temporal.PlainDateTime(2023, 12, 25);
const duration = earlier.since(later, { largestUnit: "years", smallestUnit: "months", roundingMode: "expand" });
TemporalHelpers.assertDuration(duration, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, "-1 year -11 months balances to -2 years");
}

// Time units
{
const earlier = new Temporal.PlainDateTime(2000, 5, 2);
const later = new Temporal.PlainDateTime(2000, 5, 2, 1, 59, 59);
const duration = earlier.since(later, { largestUnit: "hours", smallestUnit: "minutes", roundingMode: "expand" });
TemporalHelpers.assertDuration(duration, 0, 0, 0, 0, -2, 0, 0, 0, 0, 0, "-1:59 balances to -2 hours");
}

// Both
{
const earlier = new Temporal.PlainDateTime(1970, 1, 1);
const later = new Temporal.PlainDateTime(1971, 12, 31, 23, 59, 59, 999, 999, 999);
const duration = earlier.since(later, { largestUnit: "years", smallestUnit: "microseconds", roundingMode: "expand" });
TemporalHelpers.assertDuration(duration, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, "rounding down 1 ns balances to -2 years");
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright (C) 2023 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-temporal.plaindatetime.prototype.until
description: Rounding can cross unit boundaries up to largestUnit
includes: [temporalHelpers.js]
features: [Temporal]
---*/

// Date units
{
const earlier = new Temporal.PlainDateTime(2022, 1, 1);
const later = new Temporal.PlainDateTime(2023, 12, 25);
const duration = earlier.until(later, { largestUnit: "years", smallestUnit: "months", roundingMode: "expand" });
TemporalHelpers.assertDuration(duration, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, "1 year 11 months balances to 2 years");
}

// Time units
{
const earlier = new Temporal.PlainDateTime(2000, 5, 2);
const later = new Temporal.PlainDateTime(2000, 5, 2, 1, 59, 59);
const duration = earlier.until(later, { largestUnit: "hours", smallestUnit: "minutes", roundingMode: "expand" });
TemporalHelpers.assertDuration(duration, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, "1:59 balances to 2 hours");
}

// Both
{
const earlier = new Temporal.PlainDateTime(1970, 1, 1);
const later = new Temporal.PlainDateTime(1971, 12, 31, 23, 59, 59, 999, 999, 999);
const duration = earlier.until(later, { largestUnit: "years", smallestUnit: "microseconds", roundingMode: "expand" });
TemporalHelpers.assertDuration(duration, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, "rounding up 1 ns balances to 2 years");
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright (C) 2023 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-temporal.plaintime.prototype.since
description: Rounding can cross unit boundaries up to largestUnit
includes: [temporalHelpers.js]
features: [Temporal]
---*/

const earlier = new Temporal.PlainTime();
const later = new Temporal.PlainTime(1, 59, 59);
const duration = earlier.since(later, { largestUnit: "hours", smallestUnit: "minutes", roundingMode: "expand" });
TemporalHelpers.assertDuration(duration, 0, 0, 0, 0, -2, 0, 0, 0, 0, 0, "-1:60 balances to -2 hours");
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright (C) 2023 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-temporal.plaintime.prototype.until
description: Rounding can cross unit boundaries up to largestUnit
includes: [temporalHelpers.js]
features: [Temporal]
---*/

const earlier = new Temporal.PlainTime();
const later = new Temporal.PlainTime(1, 59, 59);
const duration = earlier.until(later, { largestUnit: "hours", smallestUnit: "minutes", roundingMode: "expand" });
TemporalHelpers.assertDuration(duration, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, "1:60 balances to 2 hours");
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright (C) 2023 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-temporal.plainyearmonth.prototype.since
description: Rounding can cross unit boundaries up to largestUnit
includes: [temporalHelpers.js]
features: [Temporal]
---*/

const earlier = new Temporal.PlainYearMonth(2022, 1);
const later = new Temporal.PlainYearMonth(2023, 12);
const duration = earlier.since(later, { largestUnit: "years", smallestUnit: "months", roundingIncrement: 3, roundingMode: "expand" });
TemporalHelpers.assertDuration(duration, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, "-1 year -12 months balances to -2 years");
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright (C) 2023 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-temporal.plainyearmonth.prototype.until
description: Rounding can cross unit boundaries up to largestUnit
includes: [temporalHelpers.js]
features: [Temporal]
---*/

const earlier = new Temporal.PlainYearMonth(2022, 1);
const later = new Temporal.PlainYearMonth(2023, 12);
const duration = earlier.until(later, { largestUnit: "years", smallestUnit: "months", roundingIncrement: 3, roundingMode: "expand" });
TemporalHelpers.assertDuration(duration, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, "1 year 12 months balances to 2 years");
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright (C) 2023 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-temporal.zoneddatetime.prototype.since
description: Rounding can cross unit boundaries up to largestUnit
includes: [temporalHelpers.js]
features: [Temporal]
---*/

// Date units
{
const earlier = new Temporal.ZonedDateTime(1640995200_000_000_000n /* = 2022-01-01T00 */, "UTC");
const later = new Temporal.ZonedDateTime(1703462400_000_000_000n /* = 2023-12-25T00 */, "UTC");
const duration = earlier.since(later, { largestUnit: "years", smallestUnit: "months", roundingMode: "expand" });
TemporalHelpers.assertDuration(duration, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, "-1 year -11 months balances to -2 years");
}

// Time units
{
const earlier = new Temporal.ZonedDateTime(0n, "UTC");
const later = new Temporal.ZonedDateTime(7199_000_000_000n, "UTC");
const duration = earlier.since(later, { largestUnit: "hours", smallestUnit: "minutes", roundingMode: "expand" });
TemporalHelpers.assertDuration(duration, 0, 0, 0, 0, -2, 0, 0, 0, 0, 0, "-1:59 balances to -2 hours");
}

// Both
{
const earlier = new Temporal.ZonedDateTime(0n, "UTC");
const later = new Temporal.ZonedDateTime(63071999_999_999_999n /* = 1971-12-31T23:59:59.999999999 */, "UTC");
const duration = earlier.since(later, { largestUnit: "years", smallestUnit: "microseconds", roundingMode: "expand" });
TemporalHelpers.assertDuration(duration, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, "rounding down 1 ns balances to -2 years");
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright (C) 2023 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-temporal.zoneddatetime.prototype.until
description: Rounding can cross unit boundaries up to largestUnit
includes: [temporalHelpers.js]
features: [Temporal]
---*/

// Date units
{
const earlier = new Temporal.ZonedDateTime(1640995200_000_000_000n /* = 2022-01-01T00 */, "UTC");
const later = new Temporal.ZonedDateTime(1703462400_000_000_000n /* = 2023-12-25T00 */, "UTC");
const duration = earlier.until(later, { largestUnit: "years", smallestUnit: "months", roundingMode: "expand" });
TemporalHelpers.assertDuration(duration, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, "1 year 11 months balances to 2 years");
}

// Time units
{
const earlier = new Temporal.ZonedDateTime(0n, "UTC");
const later = new Temporal.ZonedDateTime(7199_000_000_000n, "UTC");
const duration = earlier.until(later, { largestUnit: "hours", smallestUnit: "minutes", roundingMode: "expand" });
TemporalHelpers.assertDuration(duration, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, "1:59 balances to 2 hours");
}

// Both
{
const earlier = new Temporal.ZonedDateTime(0n, "UTC");
const later = new Temporal.ZonedDateTime(63071999_999_999_999n /* = 1971-12-31T23:59:59.999999999 */, "UTC");
const duration = earlier.until(later, { largestUnit: "years", smallestUnit: "microseconds", roundingMode: "expand" });
TemporalHelpers.assertDuration(duration, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, "rounding up 1 ns balances to 2 years");
}
7 changes: 0 additions & 7 deletions test/staging/Temporal/Duration/old/toString.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,3 @@ var d = Temporal.Duration.from({
microseconds: Number.MAX_SAFE_INTEGER
});
assert.sameValue(`${ d }`, "PT9016206453995.731991S");

// rounding can affect units up to seconds
var d4 = Temporal.Duration.from("P1Y1M1W1DT23H59M59.999999999S");
assert.sameValue(d4.toString({
fractionalSecondDigits: 8,
roundingMode: "halfExpand"
}), "P1Y1M1W1DT23H59M60.00000000S");

0 comments on commit d402459

Please sign in to comment.