diff options
author | Nico Weber <thakis@chromium.org> | 2020-08-20 10:41:10 -0400 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-08-20 20:53:43 +0200 |
commit | d4d9222eea2dff296c841504b4f3f9769b86a49f (patch) | |
tree | ef670facac10481e2fa66404b7cc803a83d132a4 /Libraries | |
parent | 45827cace92f749d7a729f7fc535e66bacc97a4b (diff) | |
download | serenity-d4d9222eea2dff296c841504b4f3f9769b86a49f.zip |
LibJS: Basic implementation of most of Date's constructor arguments
The constructor with a string argument isn't implemented yet, but
this implements the other variants.
The timestamp constructor doens't handle negative timestamps correctly.
Out-of-bound and invalid arguments aren't handled correctly.
Diffstat (limited to 'Libraries')
-rw-r--r-- | Libraries/LibJS/Runtime/DateConstructor.cpp | 47 | ||||
-rw-r--r-- | Libraries/LibJS/Tests/builtins/Date/Date.js | 42 |
2 files changed, 83 insertions, 6 deletions
diff --git a/Libraries/LibJS/Runtime/DateConstructor.cpp b/Libraries/LibJS/Runtime/DateConstructor.cpp index a0783b0eb7..d66c0fa93b 100644 --- a/Libraries/LibJS/Runtime/DateConstructor.cpp +++ b/Libraries/LibJS/Runtime/DateConstructor.cpp @@ -60,13 +60,48 @@ Value DateConstructor::call(Interpreter& interpreter) return js_string(interpreter, static_cast<Date&>(date.as_object()).string()); } -Value DateConstructor::construct(Interpreter&, Function&) +Value DateConstructor::construct(Interpreter& interpreter, Function&) { - // TODO: Support args - struct timeval tv; - gettimeofday(&tv, nullptr); - auto datetime = Core::DateTime::now(); - auto milliseconds = static_cast<u16>(tv.tv_usec / 1000); + if (interpreter.argument_count() == 0) { + struct timeval tv; + gettimeofday(&tv, nullptr); + auto datetime = Core::DateTime::now(); + auto milliseconds = static_cast<u16>(tv.tv_usec / 1000); + return Date::create(global_object(), datetime, milliseconds); + } + if (interpreter.argument_count() == 1 && interpreter.argument(0).is_string()) { + // FIXME: Parse simplified ISO8601-like string, like Date.parse() will do. + struct timeval tv; + gettimeofday(&tv, nullptr); + auto datetime = Core::DateTime::now(); + auto milliseconds = static_cast<u16>(tv.tv_usec / 1000); + return Date::create(global_object(), datetime, milliseconds); + } + if (interpreter.argument_count() == 1) { + // A timestamp since the epoch, in UTC. + // FIXME: Date() probably should use a double as internal representation, so that NaN arguments and larger offsets are handled correctly. + // FIXME: DateTime::from_timestamp() seems to not support negative offsets. + double value = interpreter.argument(0).to_double(interpreter); + auto datetime = Core::DateTime::from_timestamp(static_cast<time_t>(value / 1000)); + auto milliseconds = static_cast<u16>(fmod(value, 1000)); + return Date::create(global_object(), datetime, milliseconds); + } + // A date/time in components, in local time. + // FIXME: This doesn't construct an "Invalid Date" object if one of the parameters is NaN. + // FIXME: This doesn't range-check args and convert months > 12 to year increments etc. + auto arg_or = [&interpreter](size_t i, i32 fallback) { return interpreter.argument_count() > i ? interpreter.argument(i).to_i32(interpreter) : fallback; }; + int year = interpreter.argument(0).to_i32(interpreter); + int month_index = interpreter.argument(1).to_i32(interpreter); + int day = arg_or(2, 1); + int hours = arg_or(3, 0); + int minutes = arg_or(4, 0); + int seconds = arg_or(5, 0); + int milliseconds = arg_or(6, 0); + + if (year >= 0 && year <= 99) + year += 1900; + int month = month_index + 1; + auto datetime = Core::DateTime::create(year, month, day, hours, minutes, seconds); return Date::create(global_object(), datetime, milliseconds); } diff --git a/Libraries/LibJS/Tests/builtins/Date/Date.js b/Libraries/LibJS/Tests/builtins/Date/Date.js index 3934fb5142..c7a2669675 100644 --- a/Libraries/LibJS/Tests/builtins/Date/Date.js +++ b/Libraries/LibJS/Tests/builtins/Date/Date.js @@ -3,3 +3,45 @@ test("basic functionality", () => { expect(Date.name === "Date"); expect(Date.prototype).not.toHaveProperty("length"); }); + +test("timestamp constructor", () => { + // The timestamp constructor takes a timestamp in milliseconds since the start of the epoch, in UTC. + + // 50 days and 1234 milliseconds after the start of the epoch. + // Most Date methods return values in local time, but since timezone offsets are less than 17 days, + // these checks will pass in all timezones. + let timestamp = 50 * 24 * 60 * 60 * 1000 + 1234; + + let date = new Date(timestamp); + expect(date.getTime()).toBe(timestamp); // getTime() returns the timestamp in UTC. + expect(date.getMilliseconds()).toBe(234); + expect(date.getSeconds()).toBe(1); + expect(date.getFullYear()).toBe(1970); + expect(date.getMonth()).toBe(1); // Feb +}); + +test("tuple constructor", () => { + // The tuple constructor takes a date in local time. + expect(new Date(2019, 11).getFullYear()).toBe(2019); + expect(new Date(2019, 11).getMonth()).toBe(11); + expect(new Date(2019, 11).getDate()).toBe(1); // getDay() returns day of week, getDate() returnsn day in month + expect(new Date(2019, 11).getHours()).toBe(0); + expect(new Date(2019, 11).getMinutes()).toBe(0); + expect(new Date(2019, 11).getSeconds()).toBe(0); + expect(new Date(2019, 11).getMilliseconds()).toBe(0); + + let date = new Date(2019, 11, 15, 9, 16, 14, 123); // Note: Month is 0-based. + expect(date.getFullYear()).toBe(2019); + expect(date.getMonth()).toBe(11); + expect(date.getDate()).toBe(15); + expect(date.getHours()).toBe(9); + expect(date.getMinutes()).toBe(16); + expect(date.getSeconds()).toBe(14); + expect(date.getMilliseconds()).toBe(123); + + // getTime() returns a time stamp in UTC, but we can at least check it's in the right interval, which will be true independent of the local timezone if the range is big enough. + let timestamp_lower_bound = 1575072000000; // 2019-12-01T00:00:00Z + let timestamp_upper_bound = 1577750400000; // 2019-12-31T00:00:00Z + expect(date.getTime()).toBeGreaterThan(timestamp_lower_bound); + expect(date.getTime()).toBeLessThan(timestamp_upper_bound); +}); |