From 2086b8df9c06fbd0ae1738bd188d183270667d2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20=28gsus=29=20Lapastora?= Date: Sun, 22 Oct 2023 22:01:38 +0200 Subject: [PATCH] LibJS/Date: Ensure `YearFromTime(t)` holds invariant after approximation As of https://tc39.es/ecma262/#sec-yearfromtime, YearFromTime(t) should return `y` such that `TimeFromYear(YearFromTime(t)) <= t`. This wasn't held, since the approximation contained decimal digits that would nudge the final value in the wrong direction. Adapted from Kiesel: https://codeberg.org/kiesel-js/kiesel/commit/6548a857439ca175d4254c880442bb5267e92a04 Co-authored-by: Linus Groh --- Userland/Libraries/LibJS/Runtime/Date.cpp | 2 +- Userland/Libraries/LibJS/Tests/builtins/Date/Date.UTC.js | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Userland/Libraries/LibJS/Runtime/Date.cpp b/Userland/Libraries/LibJS/Runtime/Date.cpp index d8e5552923..8d8ddc8824 100644 --- a/Userland/Libraries/LibJS/Runtime/Date.cpp +++ b/Userland/Libraries/LibJS/Runtime/Date.cpp @@ -138,7 +138,7 @@ i32 year_from_time(double t) return NumericLimits::max(); // Approximation using average number of milliseconds per year. We might have to adjust this guess afterwards. - auto year = static_cast(t / (365.2425 * ms_per_day) + 1970); + auto year = static_cast(floor(t / (365.2425 * ms_per_day) + 1970)); auto year_t = time_from_year(year); if (year_t > t) diff --git a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.UTC.js b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.UTC.js index 4dca450c19..1054e2a8f6 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.UTC.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.UTC.js @@ -70,3 +70,12 @@ test("time clip", () => { expect(Date.UTC(275760, 8, 13, 0, 0, 0, 0)).toBe(8.64e15); expect(Date.UTC(275760, 8, 13, 0, 0, 0, 1)).toBeNaN(); }); + +test("YearFromTime invariant holds with negative times", () => { + // https://tc39.es/ecma262/#sec-yearfromtime: YearFromTime(t) should return + // a value such that TimeFromYear(YearFromTime(t)) <= t. + // + // If this doesn't hold, then the following Date constructor will result in + // a crash from an assertion (#21548). + new Date(Date.UTC(-1112, 11, 31)); +});