[INTL] Implement Date.prototype.toLocaleDateString in ECMA-402
[WebKit-https.git] / Source / JavaScriptCore / builtins / DatePrototype.js
1 /*
2  * Copyright (C) 2015 Andy VanWagoner <thetalecrafter@gmail.com>.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 // @conditional=ENABLE(INTL)
27
28 function toLocaleString(/* locales, options */)
29 {
30     "use strict";
31
32     function toDateTimeOptionsAnyAll(opts)
33     {
34         // ToDateTimeOptions(options, "any", "all")
35         // http://www.ecma-international.org/ecma-402/2.0/#sec-InitializeDateTimeFormat
36
37         var options;
38         if (opts === undefined)
39             options = null;
40         else if (opts === null)
41             throw new @TypeError("null is not an object");
42         else
43             options = @Object(opts);
44
45         // Check original instead of descendant to reduce lookups up the prototype chain.
46         var needsDefaults = !options || (
47             options.weekday === undefined &&
48             options.year === undefined &&
49             options.month === undefined &&
50             options.day === undefined &&
51             options.hour === undefined &&
52             options.minute === undefined &&
53             options.second === undefined
54         );
55
56         // Only create descendant if it will have own properties.
57         if (needsDefaults) {
58             options = @Object.create(options)
59             options.year = "numeric";
60             options.month = "numeric";
61             options.day = "numeric";
62             options.hour = "numeric";
63             options.minute = "numeric";
64             options.second = "numeric";
65         }
66
67         // 9. Return options.
68         return options;
69     }
70
71     // 13.3.1 Date.prototype.toLocaleString ([locales [, options ]]) (ECMA-402 2.0)
72     // http://www.ecma-international.org/ecma-402/2.0/#sec-Date.prototype.toLocaleString
73
74     var value = @thisTimeValue.@call(this);
75     if (@isNaN(value))
76         return "Invalid Date";
77
78     var options = toDateTimeOptionsAnyAll(arguments[1]);
79     var locales = arguments[0];
80
81     var dateFormat = new @DateTimeFormat(locales, options);
82     return dateFormat.format(value);
83 }
84
85 function toLocaleDateString(/* locales, options */)
86 {
87     "use strict";
88
89     function toDateTimeOptionsDateDate(opts)
90     {
91         // ToDateTimeOptions(options, "date", "date")
92         // http://www.ecma-international.org/ecma-402/2.0/#sec-InitializeDateTimeFormat
93
94         var options;
95         if (opts === undefined)
96             options = null;
97         else if (opts === null)
98             throw new @TypeError("null is not an object");
99         else
100             options = @Object(opts);
101
102         // Check original instead of descendant to reduce lookups up the prototype chain.
103         var needsDefaults = !options || (
104             options.weekday === undefined &&
105             options.year === undefined &&
106             options.month === undefined &&
107             options.day === undefined
108         );
109
110         // Only create descendant if it will have own properties.
111         if (needsDefaults) {
112             options = @Object.create(options)
113             options.year = "numeric";
114             options.month = "numeric";
115             options.day = "numeric";
116         }
117
118         return options;
119     }
120
121     // 13.3.2 Date.prototype.toLocaleDateString ([locales [, options ]]) (ECMA-402 2.0)
122     // http://www.ecma-international.org/ecma-402/2.0/#sec-Date.prototype.toLocaleDateString
123
124     var value = @thisTimeValue.@call(this);
125     if (@isNaN(value))
126         return "Invalid Date";
127
128     var options = toDateTimeOptionsDateDate(arguments[1]);
129     var locales = arguments[0];
130
131     var dateFormat = new @DateTimeFormat(locales, options);
132     return dateFormat.format(value);
133 }