Skip to content

Commit d677f36

Browse files
committed
Temporal: Add tests for duration rounding edge case near +24h UTC shift
This edge case was discovered thanks to Firefox fuzzing: https://bugzilla.mozilla.org/show_bug.cgi?id=2029455 See tc39/proposal-temporal#3310 LLM disclosure: I used a bot to make a first draft of these, then hand-edited them until I was satisfied.
1 parent f569285 commit d677f36

4 files changed

Lines changed: 111 additions & 0 deletions

File tree

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright (C) 2026 Igalia, S.L. All rights reserved.
2+
// This code is governed by the BSD license found in the LICENSE file.
3+
4+
/*---
5+
esid: sec-temporal.duration.prototype.round
6+
description: >
7+
Rounding a negative duration where skipped day collapses bounding window
8+
includes: [temporalHelpers.js]
9+
features: [Temporal]
10+
---*/
11+
12+
const relativeTo = Temporal.ZonedDateTime.from("2012-01-01T12:00:00+14:00[Pacific/Apia]");
13+
const d = new Temporal.Duration(0, 0, 0, -1);
14+
TemporalHelpers.assertDuration(
15+
d.round({ smallestUnit: "days", relativeTo }),
16+
0, 0, 0, -1, 0, 0, 0, 0, 0, 0,
17+
"-P1D rounded to days with bounding window spanning a skipped calendar day"
18+
);
19+
20+
const d2 = new Temporal.Duration(0, 0, 0, 0, -25);
21+
TemporalHelpers.assertDuration(
22+
d2.round({ smallestUnit: "days", relativeTo }),
23+
0, 0, 0, -1, 0, 0, 0, 0, 0, 0,
24+
"-PT25H rounded to 1 day, bounding window extending into a skipped calendar day"
25+
);
26+
27+
const d3 = new Temporal.Duration(0, 0, 0, 0, -36);
28+
TemporalHelpers.assertDuration(
29+
d3.round({ smallestUnit: "days", relativeTo }),
30+
0, 0, 0, -2, 0, 0, 0, 0, 0, 0,
31+
"-PT36H rounded to 2 days, bounding window extending into a skipped calendar day"
32+
);
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright (C) 2026 Igalia, S.L. All rights reserved.
2+
// This code is governed by the BSD license found in the LICENSE file.
3+
4+
/*---
5+
esid: sec-temporal.duration.prototype.total
6+
description: >
7+
Totalling a negative duration where skipped day collapses bounding window
8+
features: [Temporal]
9+
---*/
10+
11+
const relativeTo = Temporal.ZonedDateTime.from("2012-01-01T12:00:00+14:00[Pacific/Apia]");
12+
const d = new Temporal.Duration(0, 0, 0, -1);
13+
assert.sameValue(
14+
d.total({ unit: "days", relativeTo }),
15+
-1,
16+
"-1 day total in days with bounding window spanning a skipped calendar day"
17+
);
18+
19+
const d2 = new Temporal.Duration(0, 0, 0, 0, -25);
20+
assert.sameValue(
21+
d2.total({ unit: "days", relativeTo }),
22+
-25 / 24,
23+
"-25 hours total in days, bounding window extending into a skipped calendar day"
24+
);
25+
26+
const d3 = new Temporal.Duration(0, 0, 0, 0, -36);
27+
assert.sameValue(
28+
d3.total({ unit: "days", relativeTo }),
29+
-1.5,
30+
"-36 hours total in days, bounding window extending into a skipped calendar day"
31+
);
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright (C) 2026 Igalia, S.L. All rights reserved.
2+
// This code is governed by the BSD license found in the LICENSE file.
3+
4+
/*---
5+
esid: sec-temporal.zoneddatetime.prototype.since
6+
description: since() result where skipped day collapses bounding window
7+
includes: [temporalHelpers.js]
8+
features: [Temporal]
9+
---*/
10+
11+
const start = Temporal.ZonedDateTime.from("2012-01-01T12:00:00+14:00[Pacific/Apia]");
12+
const end = Temporal.ZonedDateTime.from("2011-12-31T12:00:00+14:00[Pacific/Apia]");
13+
TemporalHelpers.assertDuration(
14+
start.since(end, { smallestUnit: "days" }),
15+
0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
16+
"since spanning a skipped calendar day"
17+
);
18+
19+
const end2 = Temporal.ZonedDateTime.from("2011-12-31T11:00:00+14:00[Pacific/Apia]");
20+
TemporalHelpers.assertDuration(
21+
start.since(end2, { smallestUnit: "days" }),
22+
0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
23+
"bounding window extending into a skipped calendar day"
24+
);
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright (C) 2026 Igalia, S.L. All rights reserved.
2+
// This code is governed by the BSD license found in the LICENSE file.
3+
4+
/*---
5+
esid: sec-temporal.zoneddatetime.prototype.until
6+
description: until() result where skipped day collapses bounding window
7+
includes: [temporalHelpers.js]
8+
features: [Temporal]
9+
---*/
10+
11+
const start = Temporal.ZonedDateTime.from("2012-01-01T12:00:00+14:00[Pacific/Apia]");
12+
const end = Temporal.ZonedDateTime.from("2011-12-31T12:00:00+14:00[Pacific/Apia]");
13+
TemporalHelpers.assertDuration(
14+
start.until(end, { smallestUnit: "days" }),
15+
0, 0, 0, -1, 0, 0, 0, 0, 0, 0,
16+
"until spanning a skipped calendar day"
17+
);
18+
19+
const end2 = Temporal.ZonedDateTime.from("2011-12-31T11:00:00+14:00[Pacific/Apia]");
20+
TemporalHelpers.assertDuration(
21+
start.until(end2, { smallestUnit: "days" }),
22+
0, 0, 0, -1, 0, 0, 0, 0, 0, 0,
23+
"bounding window extending into a skipped calendar day"
24+
);

0 commit comments

Comments
 (0)