Use JSValue::toWTFString instead of calling toString(exec) and value(exec)
[WebKit-https.git] / Source / JavaScriptCore / runtime / DatePrototype.cpp
1 /*
2  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2004-2008, 2016 Apple Inc. All rights reserved.
4  *  Copyright (C) 2008, 2009 Torch Mobile, Inc. All rights reserved.
5  *  Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved.
6  *
7  *  This library is free software; you can redistribute it and/or
8  *  modify it under the terms of the GNU Lesser General Public
9  *  License as published by the Free Software Foundation; either
10  *  version 2 of the License, or (at your option) any later version.
11  *
12  *  This library is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  *  Lesser General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Lesser General Public
18  *  License along with this library; if not, write to the Free Software
19  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
20  *  USA
21  *
22  */
23
24 #include "config.h"
25 #include "DatePrototype.h"
26
27 #include "DateConversion.h"
28 #include "DateInstance.h"
29 #include "Error.h"
30 #include "JSCBuiltins.h"
31 #include "JSDateMath.h"
32 #include "JSGlobalObject.h"
33 #include "JSObject.h"
34 #include "JSString.h"
35 #include "Lookup.h"
36 #include "ObjectPrototype.h"
37 #include "JSCInlines.h"
38 #include <limits.h>
39 #include <locale.h>
40 #include <math.h>
41 #include <stdlib.h>
42 #include <time.h>
43 #include <wtf/Assertions.h>
44 #include <wtf/MathExtras.h>
45 #include <wtf/StringExtras.h>
46
47 #if HAVE(LANGINFO_H)
48 #include <langinfo.h>
49 #endif
50
51 #if HAVE(SYS_PARAM_H)
52 #include <sys/param.h>
53 #endif
54
55 #if HAVE(SYS_TIME_H)
56 #include <sys/time.h>
57 #endif
58
59 #if HAVE(SYS_TIMEB_H)
60 #include <sys/timeb.h>
61 #endif
62
63 #if !(OS(DARWIN) && USE(CF))
64 #include <unicode/udat.h>
65 #endif
66
67 #if USE(CF)
68 #include <CoreFoundation/CoreFoundation.h>
69 #endif
70
71 using namespace WTF;
72
73 namespace JSC {
74
75 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState*);
76 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState*);
77 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState*);
78 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState*);
79 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState*);
80 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState*);
81 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState*);
82 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetSeconds(ExecState*);
83 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState*);
84 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState*);
85 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState*);
86 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState*);
87 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState*);
88 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState*);
89 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(ExecState*);
90 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState*);
91 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState*);
92 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState*);
93 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetDate(ExecState*);
94 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetFullYear(ExecState*);
95 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetHours(ExecState*);
96 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMilliSeconds(ExecState*);
97 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMinutes(ExecState*);
98 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMonth(ExecState*);
99 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetSeconds(ExecState*);
100 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState*);
101 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCDate(ExecState*);
102 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCFullYear(ExecState*);
103 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCHours(ExecState*);
104 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMilliseconds(ExecState*);
105 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMinutes(ExecState*);
106 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMonth(ExecState*);
107 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCSeconds(ExecState*);
108 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState*);
109 EncodedJSValue JSC_HOST_CALL dateProtoFuncToDateString(ExecState*);
110 EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState*);
111 EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState*);
112 EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState*);
113 EncodedJSValue JSC_HOST_CALL dateProtoFuncToPrimitiveSymbol(ExecState*);
114 EncodedJSValue JSC_HOST_CALL dateProtoFuncToString(ExecState*);
115 EncodedJSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState*);
116 EncodedJSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState*);
117 EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState*);
118 EncodedJSValue JSC_HOST_CALL dateProtoFuncToJSON(ExecState*);
119
120 }
121
122 #include "DatePrototype.lut.h"
123
124 namespace JSC {
125
126 enum LocaleDateTimeFormat { LocaleDateAndTime, LocaleDate, LocaleTime };
127  
128 #if OS(DARWIN) && USE(CF)
129
130 // FIXME: Since this is superior to the strftime-based version, why limit this to OS(DARWIN)?
131 // Instead we should consider using this whenever USE(CF) is true.
132
133 static CFDateFormatterStyle styleFromArgString(const String& string, CFDateFormatterStyle defaultStyle)
134 {
135     if (string == "short")
136         return kCFDateFormatterShortStyle;
137     if (string == "medium")
138         return kCFDateFormatterMediumStyle;
139     if (string == "long")
140         return kCFDateFormatterLongStyle;
141     if (string == "full")
142         return kCFDateFormatterFullStyle;
143     return defaultStyle;
144 }
145
146 static JSCell* formatLocaleDate(ExecState* exec, DateInstance*, double timeInMilliseconds, LocaleDateTimeFormat format)
147 {
148     CFDateFormatterStyle dateStyle = (format != LocaleTime ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle);
149     CFDateFormatterStyle timeStyle = (format != LocaleDate ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle);
150
151     bool useCustomFormat = false;
152     String customFormatString;
153
154     String arg0String = exec->argument(0).toWTFString(exec);
155     if (arg0String == "custom" && !exec->argument(1).isUndefined()) {
156         useCustomFormat = true;
157         customFormatString = exec->argument(1).toWTFString(exec);
158     } else if (format == LocaleDateAndTime && !exec->argument(1).isUndefined()) {
159         dateStyle = styleFromArgString(arg0String, dateStyle);
160         timeStyle = styleFromArgString(exec->argument(1).toWTFString(exec), timeStyle);
161     } else if (format != LocaleTime && !exec->argument(0).isUndefined())
162         dateStyle = styleFromArgString(arg0String, dateStyle);
163     else if (format != LocaleDate && !exec->argument(0).isUndefined())
164         timeStyle = styleFromArgString(arg0String, timeStyle);
165
166     CFAbsoluteTime absoluteTime = floor(timeInMilliseconds / msPerSecond) - kCFAbsoluteTimeIntervalSince1970;
167
168     auto formatter = adoptCF(CFDateFormatterCreate(kCFAllocatorDefault, adoptCF(CFLocaleCopyCurrent()).get(), dateStyle, timeStyle));
169     if (useCustomFormat)
170         CFDateFormatterSetFormat(formatter.get(), customFormatString.createCFString().get());
171     return jsNontrivialString(exec, adoptCF(CFDateFormatterCreateStringWithAbsoluteTime(kCFAllocatorDefault, formatter.get(), absoluteTime)).get());
172 }
173
174 #elif !UCONFIG_NO_FORMATTING
175
176 static JSCell* formatLocaleDate(ExecState* exec, DateInstance*, double timeInMilliseconds, LocaleDateTimeFormat format)
177 {
178     UDateFormatStyle timeStyle = (format != LocaleDate ? UDAT_LONG : UDAT_NONE);
179     UDateFormatStyle dateStyle = (format != LocaleTime ? UDAT_LONG : UDAT_NONE);
180
181     UErrorCode status = U_ZERO_ERROR;
182     UDateFormat* df = udat_open(timeStyle, dateStyle, 0, 0, -1, 0, 0, &status);
183     if (!df)
184         return jsEmptyString(exec);
185
186     UChar buffer[128];
187     int32_t length;
188     length = udat_format(df, timeInMilliseconds, buffer, 128, 0, &status);
189     udat_close(df);
190     if (status != U_ZERO_ERROR)
191         return jsEmptyString(exec);
192
193     return jsNontrivialString(exec, String(buffer, length));
194 }
195
196 #else
197
198 static JSCell* formatLocaleDate(ExecState* exec, const GregorianDateTime& gdt, LocaleDateTimeFormat format)
199 {
200 #if OS(WINDOWS)
201     SYSTEMTIME systemTime;
202     memset(&systemTime, 0, sizeof(systemTime));
203     systemTime.wYear = gdt.year();
204     systemTime.wMonth = gdt.month() + 1;
205     systemTime.wDay = gdt.monthDay();
206     systemTime.wDayOfWeek = gdt.weekDay();
207     systemTime.wHour = gdt.hour();
208     systemTime.wMinute = gdt.minute();
209     systemTime.wSecond = gdt.second();
210
211     Vector<UChar, 128> buffer;
212     size_t length = 0;
213
214     if (format == LocaleDate) {
215         buffer.resize(GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &systemTime, 0, 0, 0));
216         length = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &systemTime, 0, buffer.data(), buffer.size());
217     } else if (format == LocaleTime) {
218         buffer.resize(GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &systemTime, 0, 0, 0));
219         length = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &systemTime, 0, buffer.data(), buffer.size());
220     } else if (format == LocaleDateAndTime) {
221         buffer.resize(GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &systemTime, 0, 0, 0) + GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &systemTime, 0, 0, 0));
222         length = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &systemTime, 0, buffer.data(), buffer.size());
223         if (length) {
224             buffer[length - 1] = ' ';
225             length += GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &systemTime, 0, buffer.data() + length, buffer.size() - length);
226         }
227     } else
228         RELEASE_ASSERT_NOT_REACHED();
229
230     //  Remove terminating null character.
231     if (length)
232         length--;
233
234     return jsNontrivialString(exec, String(buffer.data(), length));
235
236 #else // OS(WINDOWS)
237
238 #if HAVE(LANGINFO_H)
239     static const nl_item formats[] = { D_T_FMT, D_FMT, T_FMT };
240 #else
241     static const char* const formatStrings[] = { "%#c", "%#x", "%X" };
242 #endif
243
244     // Offset year if needed
245     struct tm localTM = gdt;
246     int year = gdt.year();
247     bool yearNeedsOffset = year < 1900 || year > 2038;
248     if (yearNeedsOffset)
249         localTM.tm_year = equivalentYearForDST(year) - 1900;
250
251 #if HAVE(LANGINFO_H)
252     // We do not allow strftime to generate dates with 2-digits years,
253     // both to avoid ambiguity, and a crash in strncpy, for years that
254     // need offset.
255     char* formatString = strdup(nl_langinfo(formats[format]));
256     char* yPos = strchr(formatString, 'y');
257     if (yPos)
258         *yPos = 'Y';
259 #endif
260
261     // Do the formatting
262     const int bufsize = 128;
263     char timebuffer[bufsize];
264
265 #if HAVE(LANGINFO_H)
266     size_t ret = strftime(timebuffer, bufsize, formatString, &localTM);
267     free(formatString);
268 #else
269     size_t ret = strftime(timebuffer, bufsize, formatStrings[format], &localTM);
270 #endif
271
272     if (ret == 0)
273         return jsEmptyString(exec);
274
275     // Copy original into the buffer
276     if (yearNeedsOffset && format != LocaleTime) {
277         static const int yearLen = 5;   // FIXME will be a problem in the year 10,000
278         char yearString[yearLen];
279
280         snprintf(yearString, yearLen, "%d", localTM.tm_year + 1900);
281         char* yearLocation = strstr(timebuffer, yearString);
282         snprintf(yearString, yearLen, "%d", year);
283
284         strncpy(yearLocation, yearString, yearLen - 1);
285     }
286
287     // Convert multi-byte result to UNICODE.
288     // If __STDC_ISO_10646__ is defined, wide character represents
289     // UTF-16 (or UTF-32) code point. In most modern Unix like system
290     // (e.g. Linux with glibc 2.2 and above) the macro is defined,
291     // and wide character represents UTF-32 code point.
292     // Here we static_cast potential UTF-32 to UTF-16, it should be
293     // safe because date and (or) time related characters in different languages
294     // should be in UNICODE BMP. If mbstowcs fails, we just fall
295     // back on using multi-byte result as-is.
296 #ifdef __STDC_ISO_10646__
297     UChar buffer[bufsize];
298     wchar_t tempbuffer[bufsize];
299     size_t length = mbstowcs(tempbuffer, timebuffer, bufsize - 1);
300     if (length != static_cast<size_t>(-1)) {
301         for (size_t i = 0; i < length; ++i)
302             buffer[i] = static_cast<UChar>(tempbuffer[i]);
303         return jsNontrivialString(exec, String(buffer, length));
304     }
305 #endif
306
307     return jsNontrivialString(exec, timebuffer);
308 #endif // OS(WINDOWS)
309 }
310
311 static JSCell* formatLocaleDate(ExecState* exec, DateInstance* dateObject, double, LocaleDateTimeFormat format)
312 {
313     const GregorianDateTime* gregorianDateTime = dateObject->gregorianDateTime(exec);
314     if (!gregorianDateTime)
315         return jsNontrivialString(exec, ASCIILiteral("Invalid Date"));
316     return formatLocaleDate(exec, *gregorianDateTime, format);
317 }
318
319 #endif // OS(DARWIN) && USE(CF)
320
321 static EncodedJSValue formateDateInstance(ExecState* exec, DateTimeFormat format, bool asUTCVariant)
322 {
323     auto scope = DECLARE_THROW_SCOPE(exec->vm());
324     JSValue thisValue = exec->thisValue();
325     if (!thisValue.inherits(DateInstance::info()))
326         return throwVMTypeError(exec, scope);
327
328     DateInstance* thisDateObj = asDateInstance(thisValue);
329
330     const GregorianDateTime* gregorianDateTime = asUTCVariant
331         ? thisDateObj->gregorianDateTimeUTC(exec)
332         : thisDateObj->gregorianDateTime(exec);
333     if (!gregorianDateTime)
334         return JSValue::encode(jsNontrivialString(exec, String(ASCIILiteral("Invalid Date"))));
335
336     return JSValue::encode(jsNontrivialString(exec, formatDateTime(*gregorianDateTime, format, asUTCVariant)));
337 }
338
339 // Converts a list of arguments sent to a Date member function into milliseconds, updating
340 // ms (representing milliseconds) and t (representing the rest of the date structure) appropriately.
341 //
342 // Format of member function: f([hour,] [min,] [sec,] [ms])
343 static bool fillStructuresUsingTimeArgs(ExecState* exec, int maxArgs, double* ms, GregorianDateTime* t)
344 {
345     double milliseconds = 0;
346     bool ok = true;
347     int idx = 0;
348     int numArgs = exec->argumentCount();
349     
350     // JS allows extra trailing arguments -- ignore them
351     if (numArgs > maxArgs)
352         numArgs = maxArgs;
353
354     // hours
355     if (maxArgs >= 4 && idx < numArgs) {
356         t->setHour(0);
357         double hours = exec->uncheckedArgument(idx++).toIntegerPreserveNaN(exec);
358         ok = std::isfinite(hours);
359         milliseconds += hours * msPerHour;
360     }
361
362     // minutes
363     if (maxArgs >= 3 && idx < numArgs && ok) {
364         t->setMinute(0);
365         double minutes = exec->uncheckedArgument(idx++).toIntegerPreserveNaN(exec);
366         ok = std::isfinite(minutes);
367         milliseconds += minutes * msPerMinute;
368     }
369     
370     // seconds
371     if (maxArgs >= 2 && idx < numArgs && ok) {
372         t->setSecond(0);
373         double seconds = exec->uncheckedArgument(idx++).toIntegerPreserveNaN(exec);
374         ok = std::isfinite(seconds);
375         milliseconds += seconds * msPerSecond;
376     }
377     
378     if (!ok)
379         return false;
380         
381     // milliseconds
382     if (idx < numArgs) {
383         double millis = exec->uncheckedArgument(idx).toIntegerPreserveNaN(exec);
384         ok = std::isfinite(millis);
385         milliseconds += millis;
386     } else
387         milliseconds += *ms;
388     
389     *ms = milliseconds;
390     return ok;
391 }
392
393 // Converts a list of arguments sent to a Date member function into years, months, and milliseconds, updating
394 // ms (representing milliseconds) and t (representing the rest of the date structure) appropriately.
395 //
396 // Format of member function: f([years,] [months,] [days])
397 static bool fillStructuresUsingDateArgs(ExecState *exec, int maxArgs, double *ms, GregorianDateTime *t)
398 {
399     int idx = 0;
400     bool ok = true;
401     int numArgs = exec->argumentCount();
402   
403     // JS allows extra trailing arguments -- ignore them
404     if (numArgs > maxArgs)
405         numArgs = maxArgs;
406   
407     // years
408     if (maxArgs >= 3 && idx < numArgs) {
409         double years = exec->uncheckedArgument(idx++).toIntegerPreserveNaN(exec);
410         ok = std::isfinite(years);
411         t->setYear(toInt32(years));
412     }
413     // months
414     if (maxArgs >= 2 && idx < numArgs && ok) {
415         double months = exec->uncheckedArgument(idx++).toIntegerPreserveNaN(exec);
416         ok = std::isfinite(months);
417         t->setMonth(toInt32(months));
418     }
419     // days
420     if (idx < numArgs && ok) {
421         double days = exec->uncheckedArgument(idx++).toIntegerPreserveNaN(exec);
422         ok = std::isfinite(days);
423         t->setMonthDay(0);
424         *ms += days * msPerDay;
425     }
426     
427     return ok;
428 }
429
430 const ClassInfo DatePrototype::s_info = {"Object", &JSNonFinalObject::s_info, &dateTable, CREATE_METHOD_TABLE(DatePrototype)};
431
432 /* Source for DatePrototype.lut.h
433 @begin dateTable
434   toString              dateProtoFuncToString                DontEnum|Function       0
435   toISOString           dateProtoFuncToISOString             DontEnum|Function       0
436   toDateString          dateProtoFuncToDateString            DontEnum|Function       0
437   toTimeString          dateProtoFuncToTimeString            DontEnum|Function       0
438   toLocaleString        dateProtoFuncToLocaleString          DontEnum|Function       0
439   toLocaleDateString    dateProtoFuncToLocaleDateString      DontEnum|Function       0
440   toLocaleTimeString    dateProtoFuncToLocaleTimeString      DontEnum|Function       0
441   valueOf               dateProtoFuncGetTime                 DontEnum|Function       0
442   getTime               dateProtoFuncGetTime                 DontEnum|Function       0
443   getFullYear           dateProtoFuncGetFullYear             DontEnum|Function       0
444   getUTCFullYear        dateProtoFuncGetUTCFullYear          DontEnum|Function       0
445   getMonth              dateProtoFuncGetMonth                DontEnum|Function       0
446   getUTCMonth           dateProtoFuncGetUTCMonth             DontEnum|Function       0
447   getDate               dateProtoFuncGetDate                 DontEnum|Function       0
448   getUTCDate            dateProtoFuncGetUTCDate              DontEnum|Function       0
449   getDay                dateProtoFuncGetDay                  DontEnum|Function       0
450   getUTCDay             dateProtoFuncGetUTCDay               DontEnum|Function       0
451   getHours              dateProtoFuncGetHours                DontEnum|Function       0
452   getUTCHours           dateProtoFuncGetUTCHours             DontEnum|Function       0
453   getMinutes            dateProtoFuncGetMinutes              DontEnum|Function       0
454   getUTCMinutes         dateProtoFuncGetUTCMinutes           DontEnum|Function       0
455   getSeconds            dateProtoFuncGetSeconds              DontEnum|Function       0
456   getUTCSeconds         dateProtoFuncGetUTCSeconds           DontEnum|Function       0
457   getMilliseconds       dateProtoFuncGetMilliSeconds         DontEnum|Function       0
458   getUTCMilliseconds    dateProtoFuncGetUTCMilliseconds      DontEnum|Function       0
459   getTimezoneOffset     dateProtoFuncGetTimezoneOffset       DontEnum|Function       0
460   setTime               dateProtoFuncSetTime                 DontEnum|Function       1
461   setMilliseconds       dateProtoFuncSetMilliSeconds         DontEnum|Function       1
462   setUTCMilliseconds    dateProtoFuncSetUTCMilliseconds      DontEnum|Function       1
463   setSeconds            dateProtoFuncSetSeconds              DontEnum|Function       2
464   setUTCSeconds         dateProtoFuncSetUTCSeconds           DontEnum|Function       2
465   setMinutes            dateProtoFuncSetMinutes              DontEnum|Function       3
466   setUTCMinutes         dateProtoFuncSetUTCMinutes           DontEnum|Function       3
467   setHours              dateProtoFuncSetHours                DontEnum|Function       4
468   setUTCHours           dateProtoFuncSetUTCHours             DontEnum|Function       4
469   setDate               dateProtoFuncSetDate                 DontEnum|Function       1
470   setUTCDate            dateProtoFuncSetUTCDate              DontEnum|Function       1
471   setMonth              dateProtoFuncSetMonth                DontEnum|Function       2
472   setUTCMonth           dateProtoFuncSetUTCMonth             DontEnum|Function       2
473   setFullYear           dateProtoFuncSetFullYear             DontEnum|Function       3
474   setUTCFullYear        dateProtoFuncSetUTCFullYear          DontEnum|Function       3
475   setYear               dateProtoFuncSetYear                 DontEnum|Function       1
476   getYear               dateProtoFuncGetYear                 DontEnum|Function       0
477   toJSON                dateProtoFuncToJSON                  DontEnum|Function       1
478 @end
479 */
480
481 // ECMA 15.9.4
482
483 DatePrototype::DatePrototype(VM& vm, Structure* structure)
484     : Base(vm, structure)
485 {
486 }
487
488 void DatePrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
489 {
490     Base::finishCreation(vm);
491     ASSERT(inherits(info()));
492
493     Identifier toUTCStringName = Identifier::fromString(&vm, ASCIILiteral("toUTCString"));
494     JSFunction* toUTCStringFunction = JSFunction::create(vm, globalObject, 0, toUTCStringName.string(), dateProtoFuncToUTCString);
495     putDirectWithoutTransition(vm, toUTCStringName, toUTCStringFunction, DontEnum);
496     putDirectWithoutTransition(vm, Identifier::fromString(&vm, ASCIILiteral("toGMTString")), toUTCStringFunction, DontEnum);
497
498 #if ENABLE(INTL)
499     JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("toLocaleString", datePrototypeToLocaleStringCodeGenerator, DontEnum);
500     JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("toLocaleDateString", datePrototypeToLocaleDateStringCodeGenerator, DontEnum);
501     JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("toLocaleTimeString", datePrototypeToLocaleTimeStringCodeGenerator, DontEnum);
502 #else
503     UNUSED_PARAM(globalObject);
504 #endif // ENABLE(INTL)
505
506     JSC_NATIVE_FUNCTION(vm.propertyNames->toPrimitiveSymbol, dateProtoFuncToPrimitiveSymbol, DontEnum | ReadOnly, 1);
507     // The constructor will be added later, after DateConstructor has been built.
508 }
509
510 // Functions
511
512 EncodedJSValue JSC_HOST_CALL dateProtoFuncToString(ExecState* exec)
513 {
514     const bool asUTCVariant = false;
515     return formateDateInstance(exec, DateTimeFormatDateAndTime, asUTCVariant);
516 }
517
518 EncodedJSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState* exec)
519 {
520     const bool asUTCVariant = true;
521     return formateDateInstance(exec, DateTimeFormatDateAndTime, asUTCVariant);
522 }
523
524 EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState* exec)
525 {
526     auto scope = DECLARE_THROW_SCOPE(exec->vm());
527     JSValue thisValue = exec->thisValue();
528     if (!thisValue.inherits(DateInstance::info()))
529         return throwVMTypeError(exec, scope);
530     
531     DateInstance* thisDateObj = asDateInstance(thisValue); 
532     if (!std::isfinite(thisDateObj->internalNumber()))
533         return throwVMError(exec, scope, createRangeError(exec, ASCIILiteral("Invalid Date")));
534
535     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
536     if (!gregorianDateTime)
537         return JSValue::encode(jsNontrivialString(exec, String(ASCIILiteral("Invalid Date"))));
538     // Maximum amount of space we need in buffer: 7 (max. digits in year) + 2 * 5 (2 characters each for month, day, hour, minute, second) + 4 (. + 3 digits for milliseconds)
539     // 6 for formatting and one for null termination = 28. We add one extra character to allow us to force null termination.
540     char buffer[28];
541     // If the year is outside the bounds of 0 and 9999 inclusive we want to use the extended year format (ES 15.9.1.15.1).
542     int ms = static_cast<int>(fmod(thisDateObj->internalNumber(), msPerSecond));
543     if (ms < 0)
544         ms += msPerSecond;
545
546     int charactersWritten;
547     if (gregorianDateTime->year() > 9999 || gregorianDateTime->year() < 0)
548         charactersWritten = snprintf(buffer, sizeof(buffer), "%+07d-%02d-%02dT%02d:%02d:%02d.%03dZ", gregorianDateTime->year(), gregorianDateTime->month() + 1, gregorianDateTime->monthDay(), gregorianDateTime->hour(), gregorianDateTime->minute(), gregorianDateTime->second(), ms);
549     else
550         charactersWritten = snprintf(buffer, sizeof(buffer), "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", gregorianDateTime->year(), gregorianDateTime->month() + 1, gregorianDateTime->monthDay(), gregorianDateTime->hour(), gregorianDateTime->minute(), gregorianDateTime->second(), ms);
551
552     ASSERT(charactersWritten > 0 && static_cast<unsigned>(charactersWritten) < sizeof(buffer));
553     if (static_cast<unsigned>(charactersWritten) >= sizeof(buffer))
554         return JSValue::encode(jsEmptyString(exec));
555
556     return JSValue::encode(jsNontrivialString(exec, String(buffer, charactersWritten)));
557 }
558
559 EncodedJSValue JSC_HOST_CALL dateProtoFuncToDateString(ExecState* exec)
560 {
561     const bool asUTCVariant = false;
562     return formateDateInstance(exec, DateTimeFormatDate, asUTCVariant);
563 }
564
565 EncodedJSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState* exec)
566 {
567     const bool asUTCVariant = false;
568     return formateDateInstance(exec, DateTimeFormatTime, asUTCVariant);
569 }
570
571 EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState* exec)
572 {
573     auto scope = DECLARE_THROW_SCOPE(exec->vm());
574     JSValue thisValue = exec->thisValue();
575     if (!thisValue.inherits(DateInstance::info()))
576         return throwVMTypeError(exec, scope);
577
578     DateInstance* thisDateObj = asDateInstance(thisValue); 
579     return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleDateAndTime));
580 }
581
582 EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState* exec)
583 {
584     auto scope = DECLARE_THROW_SCOPE(exec->vm());
585     JSValue thisValue = exec->thisValue();
586     if (!thisValue.inherits(DateInstance::info()))
587         return throwVMTypeError(exec, scope);
588
589     DateInstance* thisDateObj = asDateInstance(thisValue); 
590     return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleDate));
591 }
592
593 EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState* exec)
594 {
595     auto scope = DECLARE_THROW_SCOPE(exec->vm());
596     JSValue thisValue = exec->thisValue();
597     if (!thisValue.inherits(DateInstance::info()))
598         return throwVMTypeError(exec, scope);
599
600     DateInstance* thisDateObj = asDateInstance(thisValue); 
601     return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleTime));
602 }
603
604 EncodedJSValue JSC_HOST_CALL dateProtoFuncToPrimitiveSymbol(ExecState* exec)
605 {
606     VM& vm = exec->vm();
607     auto scope = DECLARE_THROW_SCOPE(vm);
608     JSValue thisValue = exec->thisValue();
609     if (!thisValue.isObject())
610         return throwVMTypeError(exec, scope, "Date.prototype[Symbol.toPrimitive] expected |this| to be an object.");
611     JSObject* thisObject = jsCast<JSObject*>(thisValue);
612
613     if (!exec->argumentCount())
614         return throwVMTypeError(exec, scope, "Date.prototype[Symbol.toPrimitive] expected a first argument.");
615
616     JSValue hintValue = exec->uncheckedArgument(0);
617     PreferredPrimitiveType type = toPreferredPrimitiveType(exec, hintValue);
618     RETURN_IF_EXCEPTION(scope, encodedJSValue());
619
620     if (type == NoPreference)
621         type = PreferString;
622
623     scope.release();
624     return JSValue::encode(thisObject->ordinaryToPrimitive(exec, type));
625 }
626
627 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState* exec)
628 {
629     auto scope = DECLARE_THROW_SCOPE(exec->vm());
630     JSValue thisValue = exec->thisValue();
631     if (!thisValue.inherits(DateInstance::info()))
632         return throwVMTypeError(exec, scope);
633
634     return JSValue::encode(asDateInstance(thisValue)->internalValue());
635 }
636
637 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState* exec)
638 {
639     auto scope = DECLARE_THROW_SCOPE(exec->vm());
640     JSValue thisValue = exec->thisValue();
641     if (!thisValue.inherits(DateInstance::info()))
642         return throwVMTypeError(exec, scope);
643
644     DateInstance* thisDateObj = asDateInstance(thisValue); 
645
646     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
647     if (!gregorianDateTime)
648         return JSValue::encode(jsNaN());
649     return JSValue::encode(jsNumber(gregorianDateTime->year()));
650 }
651
652 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState* exec)
653 {
654     auto scope = DECLARE_THROW_SCOPE(exec->vm());
655     JSValue thisValue = exec->thisValue();
656     if (!thisValue.inherits(DateInstance::info()))
657         return throwVMTypeError(exec, scope);
658
659     DateInstance* thisDateObj = asDateInstance(thisValue); 
660
661     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
662     if (!gregorianDateTime)
663         return JSValue::encode(jsNaN());
664     return JSValue::encode(jsNumber(gregorianDateTime->year()));
665 }
666
667 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState* exec)
668 {
669     auto scope = DECLARE_THROW_SCOPE(exec->vm());
670     JSValue thisValue = exec->thisValue();
671     if (!thisValue.inherits(DateInstance::info()))
672         return throwVMTypeError(exec, scope);
673
674     DateInstance* thisDateObj = asDateInstance(thisValue); 
675
676     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
677     if (!gregorianDateTime)
678         return JSValue::encode(jsNaN());
679     return JSValue::encode(jsNumber(gregorianDateTime->month()));
680 }
681
682 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState* exec)
683 {
684     auto scope = DECLARE_THROW_SCOPE(exec->vm());
685     JSValue thisValue = exec->thisValue();
686     if (!thisValue.inherits(DateInstance::info()))
687         return throwVMTypeError(exec, scope);
688
689     DateInstance* thisDateObj = asDateInstance(thisValue); 
690
691     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
692     if (!gregorianDateTime)
693         return JSValue::encode(jsNaN());
694     return JSValue::encode(jsNumber(gregorianDateTime->month()));
695 }
696
697 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState* exec)
698 {
699     auto scope = DECLARE_THROW_SCOPE(exec->vm());
700     JSValue thisValue = exec->thisValue();
701     if (!thisValue.inherits(DateInstance::info()))
702         return throwVMTypeError(exec, scope);
703
704     DateInstance* thisDateObj = asDateInstance(thisValue); 
705
706     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
707     if (!gregorianDateTime)
708         return JSValue::encode(jsNaN());
709     return JSValue::encode(jsNumber(gregorianDateTime->monthDay()));
710 }
711
712 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState* exec)
713 {
714     auto scope = DECLARE_THROW_SCOPE(exec->vm());
715     JSValue thisValue = exec->thisValue();
716     if (!thisValue.inherits(DateInstance::info()))
717         return throwVMTypeError(exec, scope);
718
719     DateInstance* thisDateObj = asDateInstance(thisValue); 
720
721     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
722     if (!gregorianDateTime)
723         return JSValue::encode(jsNaN());
724     return JSValue::encode(jsNumber(gregorianDateTime->monthDay()));
725 }
726
727 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState* exec)
728 {
729     auto scope = DECLARE_THROW_SCOPE(exec->vm());
730     JSValue thisValue = exec->thisValue();
731     if (!thisValue.inherits(DateInstance::info()))
732         return throwVMTypeError(exec, scope);
733
734     DateInstance* thisDateObj = asDateInstance(thisValue); 
735
736     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
737     if (!gregorianDateTime)
738         return JSValue::encode(jsNaN());
739     return JSValue::encode(jsNumber(gregorianDateTime->weekDay()));
740 }
741
742 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState* exec)
743 {
744     auto scope = DECLARE_THROW_SCOPE(exec->vm());
745     JSValue thisValue = exec->thisValue();
746     if (!thisValue.inherits(DateInstance::info()))
747         return throwVMTypeError(exec, scope);
748
749     DateInstance* thisDateObj = asDateInstance(thisValue); 
750
751     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
752     if (!gregorianDateTime)
753         return JSValue::encode(jsNaN());
754     return JSValue::encode(jsNumber(gregorianDateTime->weekDay()));
755 }
756
757 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState* exec)
758 {
759     auto scope = DECLARE_THROW_SCOPE(exec->vm());
760     JSValue thisValue = exec->thisValue();
761     if (!thisValue.inherits(DateInstance::info()))
762         return throwVMTypeError(exec, scope);
763
764     DateInstance* thisDateObj = asDateInstance(thisValue); 
765
766     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
767     if (!gregorianDateTime)
768         return JSValue::encode(jsNaN());
769     return JSValue::encode(jsNumber(gregorianDateTime->hour()));
770 }
771
772 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState* exec)
773 {
774     auto scope = DECLARE_THROW_SCOPE(exec->vm());
775     JSValue thisValue = exec->thisValue();
776     if (!thisValue.inherits(DateInstance::info()))
777         return throwVMTypeError(exec, scope);
778
779     DateInstance* thisDateObj = asDateInstance(thisValue); 
780
781     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
782     if (!gregorianDateTime)
783         return JSValue::encode(jsNaN());
784     return JSValue::encode(jsNumber(gregorianDateTime->hour()));
785 }
786
787 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState* exec)
788 {
789     auto scope = DECLARE_THROW_SCOPE(exec->vm());
790     JSValue thisValue = exec->thisValue();
791     if (!thisValue.inherits(DateInstance::info()))
792         return throwVMTypeError(exec, scope);
793
794     DateInstance* thisDateObj = asDateInstance(thisValue); 
795
796     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
797     if (!gregorianDateTime)
798         return JSValue::encode(jsNaN());
799     return JSValue::encode(jsNumber(gregorianDateTime->minute()));
800 }
801
802 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(ExecState* exec)
803 {
804     auto scope = DECLARE_THROW_SCOPE(exec->vm());
805     JSValue thisValue = exec->thisValue();
806     if (!thisValue.inherits(DateInstance::info()))
807         return throwVMTypeError(exec, scope);
808
809     DateInstance* thisDateObj = asDateInstance(thisValue); 
810
811     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
812     if (!gregorianDateTime)
813         return JSValue::encode(jsNaN());
814     return JSValue::encode(jsNumber(gregorianDateTime->minute()));
815 }
816
817 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetSeconds(ExecState* exec)
818 {
819     auto scope = DECLARE_THROW_SCOPE(exec->vm());
820     JSValue thisValue = exec->thisValue();
821     if (!thisValue.inherits(DateInstance::info()))
822         return throwVMTypeError(exec, scope);
823
824     DateInstance* thisDateObj = asDateInstance(thisValue); 
825
826     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
827     if (!gregorianDateTime)
828         return JSValue::encode(jsNaN());
829     return JSValue::encode(jsNumber(gregorianDateTime->second()));
830 }
831
832 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState* exec)
833 {
834     auto scope = DECLARE_THROW_SCOPE(exec->vm());
835     JSValue thisValue = exec->thisValue();
836     if (!thisValue.inherits(DateInstance::info()))
837         return throwVMTypeError(exec, scope);
838
839     DateInstance* thisDateObj = asDateInstance(thisValue); 
840
841     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
842     if (!gregorianDateTime)
843         return JSValue::encode(jsNaN());
844     return JSValue::encode(jsNumber(gregorianDateTime->second()));
845 }
846
847 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState* exec)
848 {
849     auto scope = DECLARE_THROW_SCOPE(exec->vm());
850     JSValue thisValue = exec->thisValue();
851     if (!thisValue.inherits(DateInstance::info()))
852         return throwVMTypeError(exec, scope);
853
854     DateInstance* thisDateObj = asDateInstance(thisValue); 
855     double milli = thisDateObj->internalNumber();
856     if (std::isnan(milli))
857         return JSValue::encode(jsNaN());
858
859     double secs = floor(milli / msPerSecond);
860     double ms = milli - secs * msPerSecond;
861     return JSValue::encode(jsNumber(ms));
862 }
863
864 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState* exec)
865 {
866     auto scope = DECLARE_THROW_SCOPE(exec->vm());
867     JSValue thisValue = exec->thisValue();
868     if (!thisValue.inherits(DateInstance::info()))
869         return throwVMTypeError(exec, scope);
870
871     DateInstance* thisDateObj = asDateInstance(thisValue); 
872     double milli = thisDateObj->internalNumber();
873     if (std::isnan(milli))
874         return JSValue::encode(jsNaN());
875
876     double secs = floor(milli / msPerSecond);
877     double ms = milli - secs * msPerSecond;
878     return JSValue::encode(jsNumber(ms));
879 }
880
881 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState* exec)
882 {
883     auto scope = DECLARE_THROW_SCOPE(exec->vm());
884     JSValue thisValue = exec->thisValue();
885     if (!thisValue.inherits(DateInstance::info()))
886         return throwVMTypeError(exec, scope);
887
888     DateInstance* thisDateObj = asDateInstance(thisValue); 
889
890     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
891     if (!gregorianDateTime)
892         return JSValue::encode(jsNaN());
893     return JSValue::encode(jsNumber(-gregorianDateTime->utcOffset() / minutesPerHour));
894 }
895
896 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState* exec)
897 {
898     auto scope = DECLARE_THROW_SCOPE(exec->vm());
899     JSValue thisValue = exec->thisValue();
900     if (!thisValue.inherits(DateInstance::info()))
901         return throwVMTypeError(exec, scope);
902
903     DateInstance* thisDateObj = asDateInstance(thisValue); 
904
905     double milli = timeClip(exec->argument(0).toNumber(exec));
906     JSValue result = jsNumber(milli);
907     thisDateObj->setInternalValue(exec->vm(), result);
908     return JSValue::encode(result);
909 }
910
911 static EncodedJSValue setNewValueFromTimeArgs(ExecState* exec, int numArgsToUse, WTF::TimeType inputTimeType)
912 {
913     auto scope = DECLARE_THROW_SCOPE(exec->vm());
914     JSValue thisValue = exec->thisValue();
915     if (!thisValue.inherits(DateInstance::info()))
916         return throwVMTypeError(exec, scope);
917
918     DateInstance* thisDateObj = asDateInstance(thisValue);
919     double milli = thisDateObj->internalNumber();
920     VM& vm = exec->vm();
921     
922     if (!exec->argumentCount() || std::isnan(milli)) {
923         JSValue result = jsNaN();
924         thisDateObj->setInternalValue(vm, result);
925         return JSValue::encode(result);
926     }
927      
928     double secs = floor(milli / msPerSecond);
929     double ms = milli - secs * msPerSecond;
930
931     const GregorianDateTime* other = inputTimeType == WTF::UTCTime
932         ? thisDateObj->gregorianDateTimeUTC(exec)
933         : thisDateObj->gregorianDateTime(exec);
934     if (!other)
935         return JSValue::encode(jsNaN());
936
937     GregorianDateTime gregorianDateTime;
938     gregorianDateTime.copyFrom(*other);
939     if (!fillStructuresUsingTimeArgs(exec, numArgsToUse, &ms, &gregorianDateTime)) {
940         JSValue result = jsNaN();
941         thisDateObj->setInternalValue(vm, result);
942         return JSValue::encode(result);
943     } 
944
945     double newUTCDate = gregorianDateTimeToMS(vm, gregorianDateTime, ms, inputTimeType);
946     JSValue result = jsNumber(timeClip(newUTCDate));
947     thisDateObj->setInternalValue(vm, result);
948     return JSValue::encode(result);
949 }
950
951 static EncodedJSValue setNewValueFromDateArgs(ExecState* exec, int numArgsToUse, WTF::TimeType inputTimeType)
952 {
953     auto scope = DECLARE_THROW_SCOPE(exec->vm());
954     JSValue thisValue = exec->thisValue();
955     if (!thisValue.inherits(DateInstance::info()))
956         return throwVMTypeError(exec, scope);
957
958     DateInstance* thisDateObj = asDateInstance(thisValue);
959     if (!exec->argumentCount()) {
960         JSValue result = jsNaN();
961         thisDateObj->setInternalValue(exec->vm(), result);
962         return JSValue::encode(result);
963     }
964
965     VM& vm = exec->vm();
966     double milli = thisDateObj->internalNumber();
967     double ms = 0; 
968
969     GregorianDateTime gregorianDateTime; 
970     if (numArgsToUse == 3 && std::isnan(milli)) 
971         msToGregorianDateTime(vm, 0, WTF::UTCTime, gregorianDateTime);
972     else { 
973         ms = milli - floor(milli / msPerSecond) * msPerSecond; 
974         const GregorianDateTime* other = inputTimeType == WTF::UTCTime
975             ? thisDateObj->gregorianDateTimeUTC(exec)
976             : thisDateObj->gregorianDateTime(exec);
977         if (!other)
978             return JSValue::encode(jsNaN());
979         gregorianDateTime.copyFrom(*other);
980     }
981     
982     if (!fillStructuresUsingDateArgs(exec, numArgsToUse, &ms, &gregorianDateTime)) {
983         JSValue result = jsNaN();
984         thisDateObj->setInternalValue(vm, result);
985         return JSValue::encode(result);
986     } 
987
988     double newUTCDate = gregorianDateTimeToMS(vm, gregorianDateTime, ms, inputTimeType);
989     JSValue result = jsNumber(timeClip(newUTCDate));
990     thisDateObj->setInternalValue(vm, result);
991     return JSValue::encode(result);
992 }
993
994 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMilliSeconds(ExecState* exec)
995 {
996     return setNewValueFromTimeArgs(exec, 1, WTF::LocalTime);
997 }
998
999 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMilliseconds(ExecState* exec)
1000 {
1001     return setNewValueFromTimeArgs(exec, 1, WTF::UTCTime);
1002 }
1003
1004 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetSeconds(ExecState* exec)
1005 {
1006     return setNewValueFromTimeArgs(exec, 2, WTF::LocalTime);
1007 }
1008
1009 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCSeconds(ExecState* exec)
1010 {
1011     return setNewValueFromTimeArgs(exec, 2, WTF::UTCTime);
1012 }
1013
1014 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMinutes(ExecState* exec)
1015 {
1016     return setNewValueFromTimeArgs(exec, 3, WTF::LocalTime);
1017 }
1018
1019 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMinutes(ExecState* exec)
1020 {
1021     return setNewValueFromTimeArgs(exec, 3, WTF::UTCTime);
1022 }
1023
1024 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetHours(ExecState* exec)
1025 {
1026     return setNewValueFromTimeArgs(exec, 4, WTF::LocalTime);
1027 }
1028
1029 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCHours(ExecState* exec)
1030 {
1031     return setNewValueFromTimeArgs(exec, 4, WTF::UTCTime);
1032 }
1033
1034 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetDate(ExecState* exec)
1035 {
1036     return setNewValueFromDateArgs(exec, 1, WTF::LocalTime);
1037 }
1038
1039 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCDate(ExecState* exec)
1040 {
1041     return setNewValueFromDateArgs(exec, 1, WTF::UTCTime);
1042 }
1043
1044 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMonth(ExecState* exec)
1045 {
1046     return setNewValueFromDateArgs(exec, 2, WTF::LocalTime);
1047 }
1048
1049 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMonth(ExecState* exec)
1050 {
1051     return setNewValueFromDateArgs(exec, 2, WTF::UTCTime);
1052 }
1053
1054 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetFullYear(ExecState* exec)
1055 {
1056     return setNewValueFromDateArgs(exec, 3, WTF::LocalTime);
1057 }
1058
1059 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCFullYear(ExecState* exec)
1060 {
1061     return setNewValueFromDateArgs(exec, 3, WTF::UTCTime);
1062 }
1063
1064 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState* exec)
1065 {
1066     auto scope = DECLARE_THROW_SCOPE(exec->vm());
1067     JSValue thisValue = exec->thisValue();
1068     if (!thisValue.inherits(DateInstance::info()))
1069         return throwVMTypeError(exec, scope);
1070
1071     VM& vm = exec->vm();
1072     DateInstance* thisDateObj = asDateInstance(thisValue);
1073     if (!exec->argumentCount()) { 
1074         JSValue result = jsNaN();
1075         thisDateObj->setInternalValue(vm, result);
1076         return JSValue::encode(result);
1077     }
1078
1079     double milli = thisDateObj->internalNumber();
1080     double ms = 0;
1081
1082     GregorianDateTime gregorianDateTime;
1083     if (std::isnan(milli))
1084         // Based on ECMA 262 B.2.5 (setYear)
1085         // the time must be reset to +0 if it is NaN.
1086         msToGregorianDateTime(vm, 0, WTF::UTCTime, gregorianDateTime);
1087     else {
1088         double secs = floor(milli / msPerSecond);
1089         ms = milli - secs * msPerSecond;
1090         if (const GregorianDateTime* other = thisDateObj->gregorianDateTime(exec))
1091             gregorianDateTime.copyFrom(*other);
1092     }
1093
1094     double year = exec->argument(0).toIntegerPreserveNaN(exec);
1095     if (!std::isfinite(year)) {
1096         JSValue result = jsNaN();
1097         thisDateObj->setInternalValue(vm, result);
1098         return JSValue::encode(result);
1099     }
1100
1101     gregorianDateTime.setYear(toInt32((year >= 0 && year <= 99) ? (year + 1900) : year));
1102     double timeInMilliseconds = gregorianDateTimeToMS(vm, gregorianDateTime, ms, WTF::LocalTime);
1103     JSValue result = jsNumber(timeClip(timeInMilliseconds));
1104     thisDateObj->setInternalValue(vm, result);
1105     return JSValue::encode(result);
1106 }
1107
1108 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState* exec)
1109 {
1110     auto scope = DECLARE_THROW_SCOPE(exec->vm());
1111     JSValue thisValue = exec->thisValue();
1112     if (!thisValue.inherits(DateInstance::info()))
1113         return throwVMTypeError(exec, scope);
1114
1115     DateInstance* thisDateObj = asDateInstance(thisValue); 
1116
1117     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
1118     if (!gregorianDateTime)
1119         return JSValue::encode(jsNaN());
1120
1121     // NOTE: IE returns the full year even in getYear.
1122     return JSValue::encode(jsNumber(gregorianDateTime->year() - 1900));
1123 }
1124
1125 EncodedJSValue JSC_HOST_CALL dateProtoFuncToJSON(ExecState* exec)
1126 {
1127     VM& vm = exec->vm();
1128     auto scope = DECLARE_THROW_SCOPE(vm);
1129     JSValue thisValue = exec->thisValue();
1130     JSObject* object = jsCast<JSObject*>(thisValue.toThis(exec, NotStrictMode));
1131     RETURN_IF_EXCEPTION(scope, encodedJSValue());
1132
1133     JSValue timeValue = object->toPrimitive(exec, PreferNumber);
1134     RETURN_IF_EXCEPTION(scope, encodedJSValue());
1135     if (timeValue.isNumber() && !(timeValue.isInt32() || std::isfinite(timeValue.asDouble())))
1136         return JSValue::encode(jsNull());
1137
1138     JSValue toISOValue = object->get(exec, vm.propertyNames->toISOString);
1139     RETURN_IF_EXCEPTION(scope, encodedJSValue());
1140
1141     CallData callData;
1142     CallType callType = getCallData(toISOValue, callData);
1143     if (callType == CallType::None)
1144         return throwVMTypeError(exec, scope, ASCIILiteral("toISOString is not a function"));
1145
1146     JSValue result = call(exec, asObject(toISOValue), callType, callData, object, exec->emptyList());
1147     RETURN_IF_EXCEPTION(scope, encodedJSValue());
1148     if (result.isObject())
1149         return throwVMTypeError(exec, scope, ASCIILiteral("toISOString did not return a primitive value"));
1150     return JSValue::encode(result);
1151 }
1152
1153 } // namespace JSC