[INTL] Implement Date.prototype.toLocaleDateString in ECMA-402
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 20 Jan 2016 01:07:34 +0000 (01:07 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 20 Jan 2016 01:07:34 +0000 (01:07 +0000)
https://bugs.webkit.org/show_bug.cgi?id=147612

Patch by Andy VanWagoner <thetalecrafter@gmail.com> on 2016-01-19
Reviewed by Benjamin Poulain.

Source/JavaScriptCore:

Implement toLocaleDateString in builtin JavaScript. Remove comments with
spec steps, and instead link to the new HTML version of the spec.

Avoids creating an extra empty object in the prototype chain of the options
object in ToDateTimeOptions. The version used in toLocaleString was updated
to match as well.

* builtins/DatePrototype.js:
(toLocaleString.toDateTimeOptionsAnyAll):
(toLocaleString):
(toLocaleDateString.toDateTimeOptionsDateDate):
(toLocaleDateString):
* runtime/DatePrototype.cpp:
(JSC::DatePrototype::finishCreation):

LayoutTests:

Added tests for toLocaleDateString.

* js/date-toLocaleString-expected.txt:
* js/script-tests/date-toLocaleString.js:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@195330 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/js/date-toLocaleString-expected.txt
LayoutTests/js/script-tests/date-toLocaleString.js
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/builtins/DatePrototype.js
Source/JavaScriptCore/runtime/DatePrototype.cpp

index dee362f83c5e7d18242187984d5fecc2e52b2025..e7f71e18341a18a03ac174f75be6f6e9fbf54891 100644 (file)
@@ -1,3 +1,15 @@
+2016-01-19  Andy VanWagoner  <thetalecrafter@gmail.com>
+
+        [INTL] Implement Date.prototype.toLocaleDateString in ECMA-402
+        https://bugs.webkit.org/show_bug.cgi?id=147612
+
+        Reviewed by Benjamin Poulain.
+
+        Added tests for toLocaleDateString.
+
+        * js/date-toLocaleString-expected.txt:
+        * js/script-tests/date-toLocaleString.js:
+
 2016-01-19  Brady Eidson  <beidson@apple.com>
 
         Modern IDB: Split all storage/indexeddb/modern tests into separate HTML + JS format.
index 02ccf803fd9cc6523fc663ed7d419afcc5fa5108..a471c61f62e943856c477604c778334b481969d8 100644 (file)
@@ -26,6 +26,29 @@ PASS new Date(0).toLocaleString('en', { timeZone: 'UTC' }) is "1/1/1970, 12:00:0
 PASS new Date(0).toLocaleString('en', null) threw exception TypeError: null is not an object.
 PASS new Date(0).toLocaleString('en', { timeZone: 'UTC', hour:'numeric', minute:'2-digit' }) is "12:00 AM"
 PASS new Date(0).toLocaleString('en', { timeZone: 'UTC', year:'numeric', month:'long' }) is "January 1970"
+PASS Date.prototype.toLocaleDateString.length is 0
+PASS Object.getOwnPropertyDescriptor(Date.prototype, 'toLocaleDateString').enumerable is false
+PASS Object.getOwnPropertyDescriptor(Date.prototype, 'toLocaleDateString').configurable is true
+PASS Object.getOwnPropertyDescriptor(Date.prototype, 'toLocaleDateString').writable is true
+PASS Date.prototype.toLocaleDateString.call(new Date) did not throw exception.
+PASS Date.prototype.toLocaleDateString.call() threw exception TypeError: Type error.
+PASS Date.prototype.toLocaleDateString.call(undefined) threw exception TypeError: Type error.
+PASS Date.prototype.toLocaleDateString.call(null) threw exception TypeError: Type error.
+PASS Date.prototype.toLocaleDateString.call(0) threw exception TypeError: Type error.
+PASS Date.prototype.toLocaleDateString.call(NaN) threw exception TypeError: Type error.
+PASS Date.prototype.toLocaleDateString.call(Infinity) threw exception TypeError: Type error.
+PASS Date.prototype.toLocaleDateString.call('1') threw exception TypeError: Type error.
+PASS Date.prototype.toLocaleDateString.call({}) threw exception TypeError: Type error.
+PASS Date.prototype.toLocaleDateString.call([]) threw exception TypeError: Type error.
+PASS Date.prototype.toLocaleDateString.call(Symbol()) threw exception TypeError: Type error.
+PASS typeof new Date().toLocaleDateString() === 'string' is true
+PASS new Date(NaN).toLocaleDateString() is "Invalid Date"
+PASS new Date().toLocaleDateString('i') threw exception RangeError: invalid language tag: i.
+PASS new Date(0).toLocaleDateString('zh-Hans-CN-u-nu-hanidec', { timeZone: 'UTC' }) is "一九七〇/一/一"
+PASS new Date(0).toLocaleDateString('en', { timeZone: 'UTC' }) is "1/1/1970"
+PASS new Date(0).toLocaleDateString('en', null) threw exception TypeError: null is not an object.
+PASS new Date(0).toLocaleDateString('en', { timeZone: 'UTC', hour:'numeric', minute:'2-digit' }) is "1/1/1970, 12:00 AM"
+PASS new Date(0).toLocaleDateString('en', { timeZone: 'UTC', year:'numeric', month:'long' }) is "January 1970"
 PASS successfullyParsed is true
 
 TEST COMPLETE
index bc4f1e7af20d196fb409234b88c2ac138237a380..77113f5f8aa8823b7d2e467b45f16a8191be7ae2 100644 (file)
@@ -35,3 +35,40 @@ shouldThrow("new Date(0).toLocaleString('en', null)", "'TypeError: null is not a
 shouldBeEqualToString("new Date(0).toLocaleString('en', { timeZone: 'UTC', hour:'numeric', minute:'2-digit' })", "12:00 AM");
 shouldBeEqualToString("new Date(0).toLocaleString('en', { timeZone: 'UTC', year:'numeric', month:'long' })", "January 1970");
 
+// Test toLocaleDateString ()
+shouldBe("Date.prototype.toLocaleDateString.length", "0");
+shouldBeFalse("Object.getOwnPropertyDescriptor(Date.prototype, 'toLocaleDateString').enumerable");
+shouldBeTrue("Object.getOwnPropertyDescriptor(Date.prototype, 'toLocaleDateString').configurable");
+shouldBeTrue("Object.getOwnPropertyDescriptor(Date.prototype, 'toLocaleDateString').writable");
+
+// Test thisTimeValue abrupt completion.
+shouldNotThrow("Date.prototype.toLocaleDateString.call(new Date)");
+shouldThrow("Date.prototype.toLocaleDateString.call()");
+shouldThrow("Date.prototype.toLocaleDateString.call(undefined)");
+shouldThrow("Date.prototype.toLocaleDateString.call(null)");
+shouldThrow("Date.prototype.toLocaleDateString.call(0)");
+shouldThrow("Date.prototype.toLocaleDateString.call(NaN)");
+shouldThrow("Date.prototype.toLocaleDateString.call(Infinity)");
+shouldThrow("Date.prototype.toLocaleDateString.call('1')");
+shouldThrow("Date.prototype.toLocaleDateString.call({})");
+shouldThrow("Date.prototype.toLocaleDateString.call([])");
+shouldThrow("Date.prototype.toLocaleDateString.call(Symbol())");
+
+shouldBeTrue("typeof new Date().toLocaleDateString() === 'string'");
+
+shouldBeEqualToString("new Date(NaN).toLocaleDateString()", "Invalid Date");
+
+// Test for DateTimeFormat behavior.
+// Test that locale parameter is passed through properly.
+shouldThrow("new Date().toLocaleDateString('i')");
+shouldBeEqualToString("new Date(0).toLocaleDateString('zh-Hans-CN-u-nu-hanidec', { timeZone: 'UTC' })", "一九七〇/一/一");
+
+// Defaults to mdy
+shouldBeEqualToString("new Date(0).toLocaleDateString('en', { timeZone: 'UTC' })", "1/1/1970");
+
+// Test that options parameter is passed through properly.
+shouldThrow("new Date(0).toLocaleDateString('en', null)", "'TypeError: null is not an object'");
+// Adds mdy if no date formats specified.
+shouldBeEqualToString("new Date(0).toLocaleDateString('en', { timeZone: 'UTC', hour:'numeric', minute:'2-digit' })", "1/1/1970, 12:00 AM");
+// If any date formats specified, just use them.
+shouldBeEqualToString("new Date(0).toLocaleDateString('en', { timeZone: 'UTC', year:'numeric', month:'long' })", "January 1970");
index 24013b2ea2992dd263de5546f2ce80619b71e38b..24496fc169d450ac02906424eafcca70eba98b1e 100644 (file)
@@ -1,3 +1,25 @@
+2016-01-19  Andy VanWagoner  <thetalecrafter@gmail.com>
+
+        [INTL] Implement Date.prototype.toLocaleDateString in ECMA-402
+        https://bugs.webkit.org/show_bug.cgi?id=147612
+
+        Reviewed by Benjamin Poulain.
+
+        Implement toLocaleDateString in builtin JavaScript. Remove comments with
+        spec steps, and instead link to the new HTML version of the spec.
+
+        Avoids creating an extra empty object in the prototype chain of the options
+        object in ToDateTimeOptions. The version used in toLocaleString was updated
+        to match as well.
+
+        * builtins/DatePrototype.js:
+        (toLocaleString.toDateTimeOptionsAnyAll):
+        (toLocaleString):
+        (toLocaleDateString.toDateTimeOptionsDateDate):
+        (toLocaleDateString):
+        * runtime/DatePrototype.cpp:
+        (JSC::DatePrototype::finishCreation):
+
 2016-01-19  Benjamin Poulain  <bpoulain@apple.com>
 
         [JSC] fixSpillSlotZDef() crashes on ARM64
index 6601a23b00893f453de7e60687654bf5461f9784..683c1d37bba41095ec278bb7515121a7179a1dde 100644 (file)
@@ -31,54 +31,31 @@ function toLocaleString(/* locales, options */)
 
     function toDateTimeOptionsAnyAll(opts)
     {
-        // ToDateTimeOptions abstract operation (ECMA-402 2.0)
-        // http://ecma-international.org/publications/standards/Ecma-402.htm
+        // ToDateTimeOptions(options, "any", "all")
+        // http://www.ecma-international.org/ecma-402/2.0/#sec-InitializeDateTimeFormat
 
-        // 1. If options is undefined, then let options be null, else let options be ToObject(options).
-        // 2. ReturnIfAbrupt(options).
-        var optObj;
+        var options;
         if (opts === undefined)
-            optObj = null;
+            options = null;
         else if (opts === null)
             throw new @TypeError("null is not an object");
         else
-            optObj = @Object(opts);
-
-        // 3. Let options be ObjectCreate(options).
-        var options = @Object.create(optObj);
-
-        // 4. Let needDefaults be true.
-        // 5. If required is "date" or "any",
-        // a. For each of the property names "weekday", "year", "month", "day":
-        // i. Let prop be the property name.
-        // ii. Let value be Get(options, prop).
-        // iii. ReturnIfAbrupt(value).
-        // iv. If value is not undefined, then let needDefaults be false.
-        // 6. If required is "time" or "any",
-        // a. For each of the property names "hour", "minute", "second":
-        // i. Let prop be the property name.
-        // ii. Let value be Get(options, prop).
-        // iii. ReturnIfAbrupt(value).
-        // iv. If value is not undefined, then let needDefaults be false.
-        // Check optObj instead of options to reduce lookups up the prototype chain.
-        var needsDefaults = !optObj || (
-            optObj.weekday === undefined &&
-            optObj.year === undefined &&
-            optObj.month === undefined &&
-            optObj.day === undefined &&
-            optObj.hour === undefined &&
-            optObj.minute === undefined &&
-            optObj.second === undefined
+            options = @Object(opts);
+
+        // Check original instead of descendant to reduce lookups up the prototype chain.
+        var needsDefaults = !options || (
+            options.weekday === undefined &&
+            options.year === undefined &&
+            options.month === undefined &&
+            options.day === undefined &&
+            options.hour === undefined &&
+            options.minute === undefined &&
+            options.second === undefined
         );
 
-        // 7. If needDefaults is true and defaults is either "date" or "all", then a. For each of the property names "year", "month", "day":
-        // i. Let status be CreateDatePropertyOrThrow(options, prop, "numeric").
-        // ii. ReturnIfAbrupt(status).
-        // 8. If needDefaults is true and defaults is either "time" or "all", then
-        // a. For each of the property names "hour", "minute", "second":
-        // i. Let status be CreateDatePropertyOrThrow(options, prop, "numeric").
-        // ii. ReturnIfAbrupt(status).
+        // Only create descendant if it will have own properties.
         if (needsDefaults) {
+            options = @Object.create(options)
             options.year = "numeric";
             options.month = "numeric";
             options.day = "numeric";
@@ -92,25 +69,65 @@ function toLocaleString(/* locales, options */)
     }
 
     // 13.3.1 Date.prototype.toLocaleString ([locales [, options ]]) (ECMA-402 2.0)
-    // http://ecma-international.org/publications/standards/Ecma-402.htm
+    // http://www.ecma-international.org/ecma-402/2.0/#sec-Date.prototype.toLocaleString
 
-    // 1. Let x be thisTimeValue(this value).
-    // 2. ReturnIfAbrupt(x).
     var value = @thisTimeValue.@call(this);
-
-    // 3. If x is NaN, return "Invalid Date".
     if (@isNaN(value))
         return "Invalid Date";
 
-    // 4. Let options be ToDateTimeOptions(options, "any", "all").
-    // 5. ReturnIfAbrupt(options).
     var options = toDateTimeOptionsAnyAll(arguments[1]);
-
-    // 6. Let dateFormat be Construct(%DateTimeFormat%, «locales, options»).
-    // 7. ReturnIfAbrupt(dateFormat).
     var locales = arguments[0];
+
     var dateFormat = new @DateTimeFormat(locales, options);
+    return dateFormat.format(value);
+}
+
+function toLocaleDateString(/* locales, options */)
+{
+    "use strict";
+
+    function toDateTimeOptionsDateDate(opts)
+    {
+        // ToDateTimeOptions(options, "date", "date")
+        // http://www.ecma-international.org/ecma-402/2.0/#sec-InitializeDateTimeFormat
+
+        var options;
+        if (opts === undefined)
+            options = null;
+        else if (opts === null)
+            throw new @TypeError("null is not an object");
+        else
+            options = @Object(opts);
+
+        // Check original instead of descendant to reduce lookups up the prototype chain.
+        var needsDefaults = !options || (
+            options.weekday === undefined &&
+            options.year === undefined &&
+            options.month === undefined &&
+            options.day === undefined
+        );
 
-    // 8. Return FormatDateTime(dateFormat, x).
+        // Only create descendant if it will have own properties.
+        if (needsDefaults) {
+            options = @Object.create(options)
+            options.year = "numeric";
+            options.month = "numeric";
+            options.day = "numeric";
+        }
+
+        return options;
+    }
+
+    // 13.3.2 Date.prototype.toLocaleDateString ([locales [, options ]]) (ECMA-402 2.0)
+    // http://www.ecma-international.org/ecma-402/2.0/#sec-Date.prototype.toLocaleDateString
+
+    var value = @thisTimeValue.@call(this);
+    if (@isNaN(value))
+        return "Invalid Date";
+
+    var options = toDateTimeOptionsDateDate(arguments[1]);
+    var locales = arguments[0];
+
+    var dateFormat = new @DateTimeFormat(locales, options);
     return dateFormat.format(value);
 }
index f5e86843f6d5d8b9b371fe3f55e430152e5d7833..45af7e0efffc630650bc71d17b43a89fd39ce773 100644 (file)
@@ -493,6 +493,7 @@ void DatePrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
 
 #if ENABLE(INTL)
     JSC_BUILTIN_FUNCTION("toLocaleString", datePrototypeToLocaleStringCodeGenerator, DontEnum);
+    JSC_BUILTIN_FUNCTION("toLocaleDateString", datePrototypeToLocaleDateStringCodeGenerator, DontEnum);
 #else
     UNUSED_PARAM(globalObject);
 #endif // ENABLE(INTL)