Quellcode durchsuchen

LibJS: Implement Date.prototype.setUTCFullYear

Timothy Flynn vor 3 Jahren
Ursprung
Commit
0d73da0328

+ 37 - 2
Userland/Libraries/LibJS/Runtime/DatePrototype.cpp

@@ -72,8 +72,8 @@ void DatePrototype::initialize(GlobalObject& global_object)
     define_native_function(vm.names.setMonth, set_month, 2, attr);
     define_native_function(vm.names.setSeconds, set_seconds, 2, attr);
     define_native_function(vm.names.setTime, set_time, 1, attr);
-    define_native_function(vm.names.setUTCDate, set_date, 1, attr);          // FIXME: This is a hack, Serenity doesn't currently support timezones other than UTC.
-    define_native_function(vm.names.setUTCFullYear, set_full_year, 3, attr); // FIXME: see above
+    define_native_function(vm.names.setUTCDate, set_date, 1, attr); // FIXME: This is a hack, Serenity doesn't currently support timezones other than UTC.
+    define_native_function(vm.names.setUTCFullYear, set_utc_full_year, 3, attr);
     define_native_function(vm.names.setUTCHours, set_utc_hours, 4, attr);
     define_native_function(vm.names.setUTCMilliseconds, set_utc_milliseconds, 1, attr);
     define_native_function(vm.names.setUTCMinutes, set_utc_minutes, 3, attr);
@@ -619,6 +619,41 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::set_time)
     return time;
 }
 
+// 21.4.4.29 Date.prototype.setUTCFullYear ( year [ , month [ , date ] ] ), https://tc39.es/ecma262/#sec-date.prototype.setutcfullyear
+JS_DEFINE_NATIVE_FUNCTION(DatePrototype::set_utc_full_year)
+{
+    // 1. Let t be ? thisTimeValue(this value).
+    auto this_time = TRY(this_time_value(global_object, vm.this_value(global_object)));
+
+    // 2. If t is NaN, set t to +0𝔽.
+    double time = 0;
+    if (!this_time.is_nan())
+        time = this_time.as_double();
+
+    // 3. Let y be ? ToNumber(year).
+    auto year = TRY(vm.argument(0).to_number(global_object));
+
+    // 4. If month is not present, let m be MonthFromTime(t); otherwise, let m be ? ToNumber(month).
+    auto month = TRY(argument_or_value(global_object, 1, month_from_time(time)));
+
+    // 5. If date is not present, let dt be DateFromTime(t); otherwise, let dt be ? ToNumber(date).
+    auto date = TRY(argument_or_value(global_object, 2, date_from_time(time)));
+
+    // 6. Let newDate be MakeDate(MakeDay(y, m, dt), TimeWithinDay(t)).
+    auto day = make_day(global_object, year, month, date);
+    auto new_date = make_date(day, Value(time_within_day(time)));
+
+    // 7. Let v be TimeClip(newDate).
+    new_date = time_clip(global_object, new_date);
+
+    // 8. Set the [[DateValue]] internal slot of this Date object to v.
+    auto* this_object = MUST(typed_this_object(global_object));
+    this_object->set_date_value(new_date.as_double());
+
+    // 9. Return v.
+    return new_date;
+}
+
 // 21.4.4.30 Date.prototype.setUTCHours ( hour [ , min [ , sec [ , ms ] ] ] ), https://tc39.es/ecma262/#sec-date.prototype.setutchours
 JS_DEFINE_NATIVE_FUNCTION(DatePrototype::set_utc_hours)
 {

+ 1 - 0
Userland/Libraries/LibJS/Runtime/DatePrototype.h

@@ -46,6 +46,7 @@ private:
     JS_DECLARE_NATIVE_FUNCTION(set_month);
     JS_DECLARE_NATIVE_FUNCTION(set_seconds);
     JS_DECLARE_NATIVE_FUNCTION(set_time);
+    JS_DECLARE_NATIVE_FUNCTION(set_utc_full_year);
     JS_DECLARE_NATIVE_FUNCTION(set_utc_hours);
     JS_DECLARE_NATIVE_FUNCTION(set_utc_milliseconds);
     JS_DECLARE_NATIVE_FUNCTION(set_utc_minutes);

+ 55 - 0
Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.setUTCFullYear.js

@@ -0,0 +1,55 @@
+describe("errors", () => {
+    test("called on non-Date object", () => {
+        expect(() => {
+            Date.prototype.setUTCFullYear();
+        }).toThrowWithMessage(TypeError, "Not an object of type Date");
+    });
+
+    test("called with non-numeric parameters", () => {
+        expect(() => {
+            new Date().setUTCFullYear(Symbol.hasInstance);
+        }).toThrowWithMessage(TypeError, "Cannot convert symbol to number");
+
+        expect(() => {
+            new Date().setUTCFullYear(1989, Symbol.hasInstance);
+        }).toThrowWithMessage(TypeError, "Cannot convert symbol to number");
+
+        expect(() => {
+            new Date().setUTCFullYear(1989, 0, Symbol.hasInstance);
+        }).toThrowWithMessage(TypeError, "Cannot convert symbol to number");
+    });
+});
+
+describe("correct behavior", () => {
+    const d = new Date(2000, 2, 1);
+
+    test("basic functionality", () => {
+        d.setUTCFullYear(1989);
+        expect(d.getUTCFullYear()).toBe(1989);
+
+        d.setUTCFullYear(1990, 1);
+        expect(d.getUTCFullYear()).toBe(1990);
+        expect(d.getUTCMonth()).toBe(1);
+
+        d.setUTCFullYear(1991, 2, 15);
+        expect(d.getUTCFullYear()).toBe(1991);
+        expect(d.getUTCMonth()).toBe(2);
+        expect(d.getUTCDate()).toBe(15);
+
+        d.setUTCFullYear("");
+        expect(d.getUTCFullYear()).toBe(0);
+
+        d.setUTCFullYear("a");
+        expect(d.getUTCFullYear()).toBe(NaN);
+    });
+
+    test("NaN", () => {
+        d.setUTCFullYear(NaN);
+        expect(d.getUTCFullYear()).toBeNaN();
+    });
+
+    test("time clip", () => {
+        d.setUTCFullYear(8.65e15);
+        expect(d.getUTCFullYear()).toBeNaN();
+    });
+});