Skip to content

Commit c7e4a99

Browse files
committed
LibJS: Handle negativity in Temporal's ApplyUnsignedRoundingMode
I don't fully understand the BigInt math here, as the computation for d1 and d2 don't align with the spec due to BigInt logic. This was discussed a bit in SerenityOS's Discord some years ago: https://discord.com/channels/830522505605283862/851522357734408232/978786665306918932 But some new tests in test262 indicate that we need to handle negative values here, instead of just throwing away the sign.
1 parent 48854a8 commit c7e4a99

File tree

2 files changed

+19
-2
lines changed

2 files changed

+19
-2
lines changed

Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -947,10 +947,11 @@ Crypto::SignedBigInteger apply_unsigned_rounding_mode(Crypto::SignedDivisionResu
947947
return r2;
948948

949949
// 6. Let d1 be x – r1.
950-
auto d1 = x.remainder.unsigned_value();
950+
auto const& d1 = x.remainder;
951951

952952
// 7. Let d2 be r2 – x.
953-
auto d2 = MUST(increment.minus(x.remainder.unsigned_value()));
953+
auto d2 = x.remainder.is_negative() ? x.remainder.plus(increment) : x.remainder.minus(increment);
954+
d2.negate();
954955

955956
// 8. If d1 < d2, return r1.
956957
if (d1 < d2)

Libraries/LibJS/Tests/builtins/Temporal/Instant/Instant.prototype.toString.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,22 @@ describe("correct behavior", () => {
5252
expect(instant.toString(options)).toBe(expected);
5353
}
5454
});
55+
56+
test("rounding", () => {
57+
const instant = new Temporal.Instant(-999999999999999990n);
58+
const roundedDown = "1938-04-24T22:13:20.000Z";
59+
const roundedUp = "1938-04-24T22:13:20.001Z";
60+
61+
for (const roundingMode of ["halfCeil", "halfFloor", "halfExpand", "halfTrunc", "halfEven", "floor", "trunc"]) {
62+
const options = { smallestUnit: "millisecond", roundingMode };
63+
expect(instant.toString(options)).toBe(roundedDown);
64+
}
65+
66+
for (const roundingMode of ["ceil", "expand"]) {
67+
const options = { smallestUnit: "millisecond", roundingMode };
68+
expect(instant.toString(options)).toBe(roundedUp);
69+
}
70+
});
5571
});
5672

5773
describe("errors", () => {

0 commit comments

Comments
 (0)