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)); +});