[ES6] Add support for Symbol.toPrimitive
[WebKit-https.git] / Source / JavaScriptCore / runtime / DatePrototype.cpp
1 /*
2  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2004, 2005, 2006, 2007, 2008 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 dateProtoFuncToGMTString(ExecState*);
111 EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState*);
112 EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState*);
113 EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState*);
114 EncodedJSValue JSC_HOST_CALL dateProtoFuncToPrimitiveSymbol(ExecState*);
115 EncodedJSValue JSC_HOST_CALL dateProtoFuncToString(ExecState*);
116 EncodedJSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState*);
117 EncodedJSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState*);
118 EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState*);
119 EncodedJSValue JSC_HOST_CALL dateProtoFuncToJSON(ExecState*);
120
121 }
122
123 #include "DatePrototype.lut.h"
124
125 namespace JSC {
126
127 enum LocaleDateTimeFormat { LocaleDateAndTime, LocaleDate, LocaleTime };
128  
129 #if OS(DARWIN) && USE(CF)
130
131 // FIXME: Since this is superior to the strftime-based version, why limit this to OS(DARWIN)?
132 // Instead we should consider using this whenever USE(CF) is true.
133
134 static CFDateFormatterStyle styleFromArgString(const String& string, CFDateFormatterStyle defaultStyle)
135 {
136     if (string == "short")
137         return kCFDateFormatterShortStyle;
138     if (string == "medium")
139         return kCFDateFormatterMediumStyle;
140     if (string == "long")
141         return kCFDateFormatterLongStyle;
142     if (string == "full")
143         return kCFDateFormatterFullStyle;
144     return defaultStyle;
145 }
146
147 static JSCell* formatLocaleDate(ExecState* exec, DateInstance*, double timeInMilliseconds, LocaleDateTimeFormat format)
148 {
149     CFDateFormatterStyle dateStyle = (format != LocaleTime ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle);
150     CFDateFormatterStyle timeStyle = (format != LocaleDate ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle);
151
152     bool useCustomFormat = false;
153     String customFormatString;
154
155     String arg0String = exec->argument(0).toString(exec)->value(exec);
156     if (arg0String == "custom" && !exec->argument(1).isUndefined()) {
157         useCustomFormat = true;
158         customFormatString = exec->argument(1).toString(exec)->value(exec);
159     } else if (format == LocaleDateAndTime && !exec->argument(1).isUndefined()) {
160         dateStyle = styleFromArgString(arg0String, dateStyle);
161         timeStyle = styleFromArgString(exec->argument(1).toString(exec)->value(exec), timeStyle);
162     } else if (format != LocaleTime && !exec->argument(0).isUndefined())
163         dateStyle = styleFromArgString(arg0String, dateStyle);
164     else if (format != LocaleDate && !exec->argument(0).isUndefined())
165         timeStyle = styleFromArgString(arg0String, timeStyle);
166
167     CFAbsoluteTime absoluteTime = floor(timeInMilliseconds / msPerSecond) - kCFAbsoluteTimeIntervalSince1970;
168
169     auto formatter = adoptCF(CFDateFormatterCreate(kCFAllocatorDefault, adoptCF(CFLocaleCopyCurrent()).get(), dateStyle, timeStyle));
170     if (useCustomFormat)
171         CFDateFormatterSetFormat(formatter.get(), customFormatString.createCFString().get());
172     return jsNontrivialString(exec, adoptCF(CFDateFormatterCreateStringWithAbsoluteTime(kCFAllocatorDefault, formatter.get(), absoluteTime)).get());
173 }
174
175 #elif !UCONFIG_NO_FORMATTING
176
177 static JSCell* formatLocaleDate(ExecState* exec, DateInstance*, double timeInMilliseconds, LocaleDateTimeFormat format)
178 {
179     UDateFormatStyle timeStyle = (format != LocaleDate ? UDAT_LONG : UDAT_NONE);
180     UDateFormatStyle dateStyle = (format != LocaleTime ? UDAT_LONG : UDAT_NONE);
181
182     UErrorCode status = U_ZERO_ERROR;
183     UDateFormat* df = udat_open(timeStyle, dateStyle, 0, 0, -1, 0, 0, &status);
184     if (!df)
185         return jsEmptyString(exec);
186
187     UChar buffer[128];
188     int32_t length;
189     length = udat_format(df, timeInMilliseconds, buffer, 128, 0, &status);
190     udat_close(df);
191     if (status != U_ZERO_ERROR)
192         return jsEmptyString(exec);
193
194     return jsNontrivialString(exec, String(buffer, length));
195 }
196
197 #else
198
199 static JSCell* formatLocaleDate(ExecState* exec, const GregorianDateTime& gdt, LocaleDateTimeFormat format)
200 {
201 #if OS(WINDOWS)
202     SYSTEMTIME systemTime;
203     memset(&systemTime, 0, sizeof(systemTime));
204     systemTime.wYear = gdt.year();
205     systemTime.wMonth = gdt.month() + 1;
206     systemTime.wDay = gdt.monthDay();
207     systemTime.wDayOfWeek = gdt.weekDay();
208     systemTime.wHour = gdt.hour();
209     systemTime.wMinute = gdt.minute();
210     systemTime.wSecond = gdt.second();
211
212     Vector<UChar, 128> buffer;
213     size_t length = 0;
214
215     if (format == LocaleDate) {
216         buffer.resize(GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &systemTime, 0, 0, 0));
217         length = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &systemTime, 0, buffer.data(), buffer.size());
218     } else if (format == LocaleTime) {
219         buffer.resize(GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &systemTime, 0, 0, 0));
220         length = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &systemTime, 0, buffer.data(), buffer.size());
221     } else if (format == LocaleDateAndTime) {
222         buffer.resize(GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &systemTime, 0, 0, 0) + GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &systemTime, 0, 0, 0));
223         length = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &systemTime, 0, buffer.data(), buffer.size());
224         if (length) {
225             buffer[length - 1] = ' ';
226             length += GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &systemTime, 0, buffer.data() + length, buffer.size() - length);
227         }
228     } else
229         RELEASE_ASSERT_NOT_REACHED();
230
231     //  Remove terminating null character.
232     if (length)
233         length--;
234
235     return jsNontrivialString(exec, String(buffer.data(), length));
236
237 #else // OS(WINDOWS)
238
239 #if HAVE(LANGINFO_H)
240     static const nl_item formats[] = { D_T_FMT, D_FMT, T_FMT };
241 #else
242     static const char* const formatStrings[] = { "%#c", "%#x", "%X" };
243 #endif
244
245     // Offset year if needed
246     struct tm localTM = gdt;
247     int year = gdt.year();
248     bool yearNeedsOffset = year < 1900 || year > 2038;
249     if (yearNeedsOffset)
250         localTM.tm_year = equivalentYearForDST(year) - 1900;
251
252 #if HAVE(LANGINFO_H)
253     // We do not allow strftime to generate dates with 2-digits years,
254     // both to avoid ambiguity, and a crash in strncpy, for years that
255     // need offset.
256     char* formatString = strdup(nl_langinfo(formats[format]));
257     char* yPos = strchr(formatString, 'y');
258     if (yPos)
259         *yPos = 'Y';
260 #endif
261
262     // Do the formatting
263     const int bufsize = 128;
264     char timebuffer[bufsize];
265
266 #if HAVE(LANGINFO_H)
267     size_t ret = strftime(timebuffer, bufsize, formatString, &localTM);
268     free(formatString);
269 #else
270     size_t ret = strftime(timebuffer, bufsize, formatStrings[format], &localTM);
271 #endif
272
273     if (ret == 0)
274         return jsEmptyString(exec);
275
276     // Copy original into the buffer
277     if (yearNeedsOffset && format != LocaleTime) {
278         static const int yearLen = 5;   // FIXME will be a problem in the year 10,000
279         char yearString[yearLen];
280
281         snprintf(yearString, yearLen, "%d", localTM.tm_year + 1900);
282         char* yearLocation = strstr(timebuffer, yearString);
283         snprintf(yearString, yearLen, "%d", year);
284
285         strncpy(yearLocation, yearString, yearLen - 1);
286     }
287
288     // Convert multi-byte result to UNICODE.
289     // If __STDC_ISO_10646__ is defined, wide character represents
290     // UTF-16 (or UTF-32) code point. In most modern Unix like system
291     // (e.g. Linux with glibc 2.2 and above) the macro is defined,
292     // and wide character represents UTF-32 code point.
293     // Here we static_cast potential UTF-32 to UTF-16, it should be
294     // safe because date and (or) time related characters in different languages
295     // should be in UNICODE BMP. If mbstowcs fails, we just fall
296     // back on using multi-byte result as-is.
297 #ifdef __STDC_ISO_10646__
298     UChar buffer[bufsize];
299     wchar_t tempbuffer[bufsize];
300     size_t length = mbstowcs(tempbuffer, timebuffer, bufsize - 1);
301     if (length != static_cast<size_t>(-1)) {
302         for (size_t i = 0; i < length; ++i)
303             buffer[i] = static_cast<UChar>(tempbuffer[i]);
304         return jsNontrivialString(exec, String(buffer, length));
305     }
306 #endif
307
308     return jsNontrivialString(exec, timebuffer);
309 #endif // OS(WINDOWS)
310 }
311
312 static JSCell* formatLocaleDate(ExecState* exec, DateInstance* dateObject, double, LocaleDateTimeFormat format)
313 {
314     const GregorianDateTime* gregorianDateTime = dateObject->gregorianDateTime(exec);
315     if (!gregorianDateTime)
316         return jsNontrivialString(exec, ASCIILiteral("Invalid Date"));
317     return formatLocaleDate(exec, *gregorianDateTime, format);
318 }
319
320 #endif // OS(DARWIN) && USE(CF)
321
322 static EncodedJSValue formateDateInstance(ExecState* exec, DateTimeFormat format, bool asUTCVariant)
323 {
324     JSValue thisValue = exec->thisValue();
325     if (!thisValue.inherits(DateInstance::info()))
326         return throwVMTypeError(exec);
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   toUTCString           dateProtoFuncToUTCString             DontEnum|Function       0
437   toDateString          dateProtoFuncToDateString            DontEnum|Function       0
438   toTimeString          dateProtoFuncToTimeString            DontEnum|Function       0
439   toLocaleString        dateProtoFuncToLocaleString          DontEnum|Function       0
440   toLocaleDateString    dateProtoFuncToLocaleDateString      DontEnum|Function       0
441   toLocaleTimeString    dateProtoFuncToLocaleTimeString      DontEnum|Function       0
442   valueOf               dateProtoFuncGetTime                 DontEnum|Function       0
443   getTime               dateProtoFuncGetTime                 DontEnum|Function       0
444   getFullYear           dateProtoFuncGetFullYear             DontEnum|Function       0
445   getUTCFullYear        dateProtoFuncGetUTCFullYear          DontEnum|Function       0
446   toGMTString           dateProtoFuncToGMTString             DontEnum|Function       0
447   getMonth              dateProtoFuncGetMonth                DontEnum|Function       0
448   getUTCMonth           dateProtoFuncGetUTCMonth             DontEnum|Function       0
449   getDate               dateProtoFuncGetDate                 DontEnum|Function       0
450   getUTCDate            dateProtoFuncGetUTCDate              DontEnum|Function       0
451   getDay                dateProtoFuncGetDay                  DontEnum|Function       0
452   getUTCDay             dateProtoFuncGetUTCDay               DontEnum|Function       0
453   getHours              dateProtoFuncGetHours                DontEnum|Function       0
454   getUTCHours           dateProtoFuncGetUTCHours             DontEnum|Function       0
455   getMinutes            dateProtoFuncGetMinutes              DontEnum|Function       0
456   getUTCMinutes         dateProtoFuncGetUTCMinutes           DontEnum|Function       0
457   getSeconds            dateProtoFuncGetSeconds              DontEnum|Function       0
458   getUTCSeconds         dateProtoFuncGetUTCSeconds           DontEnum|Function       0
459   getMilliseconds       dateProtoFuncGetMilliSeconds         DontEnum|Function       0
460   getUTCMilliseconds    dateProtoFuncGetUTCMilliseconds      DontEnum|Function       0
461   getTimezoneOffset     dateProtoFuncGetTimezoneOffset       DontEnum|Function       0
462   setTime               dateProtoFuncSetTime                 DontEnum|Function       1
463   setMilliseconds       dateProtoFuncSetMilliSeconds         DontEnum|Function       1
464   setUTCMilliseconds    dateProtoFuncSetUTCMilliseconds      DontEnum|Function       1
465   setSeconds            dateProtoFuncSetSeconds              DontEnum|Function       2
466   setUTCSeconds         dateProtoFuncSetUTCSeconds           DontEnum|Function       2
467   setMinutes            dateProtoFuncSetMinutes              DontEnum|Function       3
468   setUTCMinutes         dateProtoFuncSetUTCMinutes           DontEnum|Function       3
469   setHours              dateProtoFuncSetHours                DontEnum|Function       4
470   setUTCHours           dateProtoFuncSetUTCHours             DontEnum|Function       4
471   setDate               dateProtoFuncSetDate                 DontEnum|Function       1
472   setUTCDate            dateProtoFuncSetUTCDate              DontEnum|Function       1
473   setMonth              dateProtoFuncSetMonth                DontEnum|Function       2
474   setUTCMonth           dateProtoFuncSetUTCMonth             DontEnum|Function       2
475   setFullYear           dateProtoFuncSetFullYear             DontEnum|Function       3
476   setUTCFullYear        dateProtoFuncSetUTCFullYear          DontEnum|Function       3
477   setYear               dateProtoFuncSetYear                 DontEnum|Function       1
478   getYear               dateProtoFuncGetYear                 DontEnum|Function       0
479   toJSON                dateProtoFuncToJSON                  DontEnum|Function       1
480 @end
481 */
482
483 // ECMA 15.9.4
484
485 DatePrototype::DatePrototype(VM& vm, Structure* structure)
486     : Base(vm, structure)
487 {
488 }
489
490 void DatePrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
491 {
492     Base::finishCreation(vm);
493     ASSERT(inherits(info()));
494
495 #if ENABLE(INTL)
496     JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("toLocaleString", datePrototypeToLocaleStringCodeGenerator, DontEnum);
497     JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("toLocaleDateString", datePrototypeToLocaleDateStringCodeGenerator, DontEnum);
498     JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("toLocaleTimeString", datePrototypeToLocaleTimeStringCodeGenerator, DontEnum);
499 #else
500     UNUSED_PARAM(globalObject);
501 #endif // ENABLE(INTL)
502
503     JSC_NATIVE_FUNCTION(vm.propertyNames->toPrimitiveSymbol, dateProtoFuncToPrimitiveSymbol, DontEnum | ReadOnly, 1);
504     // The constructor will be added later, after DateConstructor has been built.
505 }
506
507 bool DatePrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
508 {
509     return getStaticFunctionSlot<JSObject>(exec, dateTable, jsCast<DatePrototype*>(object), propertyName, slot);
510 }
511
512 // Functions
513
514 EncodedJSValue JSC_HOST_CALL dateProtoFuncToString(ExecState* exec)
515 {
516     const bool asUTCVariant = false;
517     return formateDateInstance(exec, DateTimeFormatDateAndTime, asUTCVariant);
518 }
519
520 EncodedJSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState* exec)
521 {
522     const bool asUTCVariant = true;
523     return formateDateInstance(exec, DateTimeFormatDateAndTime, asUTCVariant);
524 }
525
526 EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState* exec)
527 {
528     JSValue thisValue = exec->thisValue();
529     if (!thisValue.inherits(DateInstance::info()))
530         return throwVMTypeError(exec);
531     
532     DateInstance* thisDateObj = asDateInstance(thisValue); 
533     if (!std::isfinite(thisDateObj->internalNumber()))
534         return throwVMError(exec, createRangeError(exec, ASCIILiteral("Invalid Date")));
535
536     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
537     if (!gregorianDateTime)
538         return JSValue::encode(jsNontrivialString(exec, String(ASCIILiteral("Invalid Date"))));
539     // 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)
540     // 6 for formatting and one for null termination = 28. We add one extra character to allow us to force null termination.
541     char buffer[28];
542     // 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).
543     int ms = static_cast<int>(fmod(thisDateObj->internalNumber(), msPerSecond));
544     if (ms < 0)
545         ms += msPerSecond;
546
547     int charactersWritten;
548     if (gregorianDateTime->year() > 9999 || gregorianDateTime->year() < 0)
549         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);
550     else
551         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);
552
553     ASSERT(charactersWritten > 0 && static_cast<unsigned>(charactersWritten) < sizeof(buffer));
554     if (static_cast<unsigned>(charactersWritten) >= sizeof(buffer))
555         return JSValue::encode(jsEmptyString(exec));
556
557     return JSValue::encode(jsNontrivialString(exec, String(buffer, charactersWritten)));
558 }
559
560 EncodedJSValue JSC_HOST_CALL dateProtoFuncToDateString(ExecState* exec)
561 {
562     const bool asUTCVariant = false;
563     return formateDateInstance(exec, DateTimeFormatDate, asUTCVariant);
564 }
565
566 EncodedJSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState* exec)
567 {
568     const bool asUTCVariant = false;
569     return formateDateInstance(exec, DateTimeFormatTime, asUTCVariant);
570 }
571
572 EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState* exec)
573 {
574     JSValue thisValue = exec->thisValue();
575     if (!thisValue.inherits(DateInstance::info()))
576         return throwVMTypeError(exec);
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     JSValue thisValue = exec->thisValue();
585     if (!thisValue.inherits(DateInstance::info()))
586         return throwVMTypeError(exec);
587
588     DateInstance* thisDateObj = asDateInstance(thisValue); 
589     return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleDate));
590 }
591
592 EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState* exec)
593 {
594     JSValue thisValue = exec->thisValue();
595     if (!thisValue.inherits(DateInstance::info()))
596         return throwVMTypeError(exec);
597
598     DateInstance* thisDateObj = asDateInstance(thisValue); 
599     return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleTime));
600 }
601
602 EncodedJSValue JSC_HOST_CALL dateProtoFuncToPrimitiveSymbol(ExecState* exec)
603 {
604     JSValue thisValue = exec->thisValue();
605     if (!thisValue.isObject())
606         return throwVMTypeError(exec, "Date.prototype[Symbol.toPrimitive] expected |this| to be an object.");
607     JSObject* thisObject = jsCast<JSObject*>(thisValue);
608
609     if (!exec->argumentCount())
610         return throwVMTypeError(exec, "Date.prototype[Symbol.toPrimitive] expected a first argument.");
611
612     JSValue hintValue = exec->uncheckedArgument(0);
613     PreferredPrimitiveType type = toPreferredPrimitiveType(exec, hintValue);
614     if (exec->hadException())
615         return JSValue::encode(JSValue());
616
617     if (type == NoPreference)
618         type = PreferString;
619
620     return JSValue::encode(thisObject->ordinaryToPrimitive(exec, type));
621 }
622
623 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState* exec)
624 {
625     JSValue thisValue = exec->thisValue();
626     if (!thisValue.inherits(DateInstance::info()))
627         return throwVMTypeError(exec);
628
629     return JSValue::encode(asDateInstance(thisValue)->internalValue());
630 }
631
632 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState* exec)
633 {
634     JSValue thisValue = exec->thisValue();
635     if (!thisValue.inherits(DateInstance::info()))
636         return throwVMTypeError(exec);
637
638     DateInstance* thisDateObj = asDateInstance(thisValue); 
639
640     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
641     if (!gregorianDateTime)
642         return JSValue::encode(jsNaN());
643     return JSValue::encode(jsNumber(gregorianDateTime->year()));
644 }
645
646 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState* exec)
647 {
648     JSValue thisValue = exec->thisValue();
649     if (!thisValue.inherits(DateInstance::info()))
650         return throwVMTypeError(exec);
651
652     DateInstance* thisDateObj = asDateInstance(thisValue); 
653
654     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
655     if (!gregorianDateTime)
656         return JSValue::encode(jsNaN());
657     return JSValue::encode(jsNumber(gregorianDateTime->year()));
658 }
659
660 EncodedJSValue JSC_HOST_CALL dateProtoFuncToGMTString(ExecState* exec)
661 {
662     const bool asUTCVariant = true;
663     return formateDateInstance(exec, DateTimeFormatDateAndTime, asUTCVariant);
664 }
665
666 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState* exec)
667 {
668     JSValue thisValue = exec->thisValue();
669     if (!thisValue.inherits(DateInstance::info()))
670         return throwVMTypeError(exec);
671
672     DateInstance* thisDateObj = asDateInstance(thisValue); 
673
674     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
675     if (!gregorianDateTime)
676         return JSValue::encode(jsNaN());
677     return JSValue::encode(jsNumber(gregorianDateTime->month()));
678 }
679
680 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState* exec)
681 {
682     JSValue thisValue = exec->thisValue();
683     if (!thisValue.inherits(DateInstance::info()))
684         return throwVMTypeError(exec);
685
686     DateInstance* thisDateObj = asDateInstance(thisValue); 
687
688     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
689     if (!gregorianDateTime)
690         return JSValue::encode(jsNaN());
691     return JSValue::encode(jsNumber(gregorianDateTime->month()));
692 }
693
694 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState* exec)
695 {
696     JSValue thisValue = exec->thisValue();
697     if (!thisValue.inherits(DateInstance::info()))
698         return throwVMTypeError(exec);
699
700     DateInstance* thisDateObj = asDateInstance(thisValue); 
701
702     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
703     if (!gregorianDateTime)
704         return JSValue::encode(jsNaN());
705     return JSValue::encode(jsNumber(gregorianDateTime->monthDay()));
706 }
707
708 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState* exec)
709 {
710     JSValue thisValue = exec->thisValue();
711     if (!thisValue.inherits(DateInstance::info()))
712         return throwVMTypeError(exec);
713
714     DateInstance* thisDateObj = asDateInstance(thisValue); 
715
716     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
717     if (!gregorianDateTime)
718         return JSValue::encode(jsNaN());
719     return JSValue::encode(jsNumber(gregorianDateTime->monthDay()));
720 }
721
722 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState* exec)
723 {
724     JSValue thisValue = exec->thisValue();
725     if (!thisValue.inherits(DateInstance::info()))
726         return throwVMTypeError(exec);
727
728     DateInstance* thisDateObj = asDateInstance(thisValue); 
729
730     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
731     if (!gregorianDateTime)
732         return JSValue::encode(jsNaN());
733     return JSValue::encode(jsNumber(gregorianDateTime->weekDay()));
734 }
735
736 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState* exec)
737 {
738     JSValue thisValue = exec->thisValue();
739     if (!thisValue.inherits(DateInstance::info()))
740         return throwVMTypeError(exec);
741
742     DateInstance* thisDateObj = asDateInstance(thisValue); 
743
744     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
745     if (!gregorianDateTime)
746         return JSValue::encode(jsNaN());
747     return JSValue::encode(jsNumber(gregorianDateTime->weekDay()));
748 }
749
750 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState* exec)
751 {
752     JSValue thisValue = exec->thisValue();
753     if (!thisValue.inherits(DateInstance::info()))
754         return throwVMTypeError(exec);
755
756     DateInstance* thisDateObj = asDateInstance(thisValue); 
757
758     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
759     if (!gregorianDateTime)
760         return JSValue::encode(jsNaN());
761     return JSValue::encode(jsNumber(gregorianDateTime->hour()));
762 }
763
764 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState* exec)
765 {
766     JSValue thisValue = exec->thisValue();
767     if (!thisValue.inherits(DateInstance::info()))
768         return throwVMTypeError(exec);
769
770     DateInstance* thisDateObj = asDateInstance(thisValue); 
771
772     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
773     if (!gregorianDateTime)
774         return JSValue::encode(jsNaN());
775     return JSValue::encode(jsNumber(gregorianDateTime->hour()));
776 }
777
778 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState* exec)
779 {
780     JSValue thisValue = exec->thisValue();
781     if (!thisValue.inherits(DateInstance::info()))
782         return throwVMTypeError(exec);
783
784     DateInstance* thisDateObj = asDateInstance(thisValue); 
785
786     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
787     if (!gregorianDateTime)
788         return JSValue::encode(jsNaN());
789     return JSValue::encode(jsNumber(gregorianDateTime->minute()));
790 }
791
792 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(ExecState* exec)
793 {
794     JSValue thisValue = exec->thisValue();
795     if (!thisValue.inherits(DateInstance::info()))
796         return throwVMTypeError(exec);
797
798     DateInstance* thisDateObj = asDateInstance(thisValue); 
799
800     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
801     if (!gregorianDateTime)
802         return JSValue::encode(jsNaN());
803     return JSValue::encode(jsNumber(gregorianDateTime->minute()));
804 }
805
806 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetSeconds(ExecState* exec)
807 {
808     JSValue thisValue = exec->thisValue();
809     if (!thisValue.inherits(DateInstance::info()))
810         return throwVMTypeError(exec);
811
812     DateInstance* thisDateObj = asDateInstance(thisValue); 
813
814     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
815     if (!gregorianDateTime)
816         return JSValue::encode(jsNaN());
817     return JSValue::encode(jsNumber(gregorianDateTime->second()));
818 }
819
820 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState* exec)
821 {
822     JSValue thisValue = exec->thisValue();
823     if (!thisValue.inherits(DateInstance::info()))
824         return throwVMTypeError(exec);
825
826     DateInstance* thisDateObj = asDateInstance(thisValue); 
827
828     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
829     if (!gregorianDateTime)
830         return JSValue::encode(jsNaN());
831     return JSValue::encode(jsNumber(gregorianDateTime->second()));
832 }
833
834 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState* exec)
835 {
836     JSValue thisValue = exec->thisValue();
837     if (!thisValue.inherits(DateInstance::info()))
838         return throwVMTypeError(exec);
839
840     DateInstance* thisDateObj = asDateInstance(thisValue); 
841     double milli = thisDateObj->internalNumber();
842     if (std::isnan(milli))
843         return JSValue::encode(jsNaN());
844
845     double secs = floor(milli / msPerSecond);
846     double ms = milli - secs * msPerSecond;
847     return JSValue::encode(jsNumber(ms));
848 }
849
850 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState* exec)
851 {
852     JSValue thisValue = exec->thisValue();
853     if (!thisValue.inherits(DateInstance::info()))
854         return throwVMTypeError(exec);
855
856     DateInstance* thisDateObj = asDateInstance(thisValue); 
857     double milli = thisDateObj->internalNumber();
858     if (std::isnan(milli))
859         return JSValue::encode(jsNaN());
860
861     double secs = floor(milli / msPerSecond);
862     double ms = milli - secs * msPerSecond;
863     return JSValue::encode(jsNumber(ms));
864 }
865
866 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState* exec)
867 {
868     JSValue thisValue = exec->thisValue();
869     if (!thisValue.inherits(DateInstance::info()))
870         return throwVMTypeError(exec);
871
872     DateInstance* thisDateObj = asDateInstance(thisValue); 
873
874     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
875     if (!gregorianDateTime)
876         return JSValue::encode(jsNaN());
877     return JSValue::encode(jsNumber(-gregorianDateTime->utcOffset() / minutesPerHour));
878 }
879
880 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState* exec)
881 {
882     JSValue thisValue = exec->thisValue();
883     if (!thisValue.inherits(DateInstance::info()))
884         return throwVMTypeError(exec);
885
886     DateInstance* thisDateObj = asDateInstance(thisValue); 
887
888     double milli = timeClip(exec->argument(0).toNumber(exec));
889     JSValue result = jsNumber(milli);
890     thisDateObj->setInternalValue(exec->vm(), result);
891     return JSValue::encode(result);
892 }
893
894 static EncodedJSValue setNewValueFromTimeArgs(ExecState* exec, int numArgsToUse, WTF::TimeType inputTimeType)
895 {
896     JSValue thisValue = exec->thisValue();
897     if (!thisValue.inherits(DateInstance::info()))
898         return throwVMTypeError(exec);
899
900     DateInstance* thisDateObj = asDateInstance(thisValue);
901     double milli = thisDateObj->internalNumber();
902     VM& vm = exec->vm();
903     
904     if (!exec->argumentCount() || std::isnan(milli)) {
905         JSValue result = jsNaN();
906         thisDateObj->setInternalValue(vm, result);
907         return JSValue::encode(result);
908     }
909      
910     double secs = floor(milli / msPerSecond);
911     double ms = milli - secs * msPerSecond;
912
913     const GregorianDateTime* other = inputTimeType == WTF::UTCTime
914         ? thisDateObj->gregorianDateTimeUTC(exec)
915         : thisDateObj->gregorianDateTime(exec);
916     if (!other)
917         return JSValue::encode(jsNaN());
918
919     GregorianDateTime gregorianDateTime;
920     gregorianDateTime.copyFrom(*other);
921     if (!fillStructuresUsingTimeArgs(exec, numArgsToUse, &ms, &gregorianDateTime)) {
922         JSValue result = jsNaN();
923         thisDateObj->setInternalValue(vm, result);
924         return JSValue::encode(result);
925     } 
926     
927     JSValue result = jsNumber(gregorianDateTimeToMS(vm, gregorianDateTime, ms, inputTimeType));
928     thisDateObj->setInternalValue(vm, result);
929     return JSValue::encode(result);
930 }
931
932 static EncodedJSValue setNewValueFromDateArgs(ExecState* exec, int numArgsToUse, WTF::TimeType inputTimeType)
933 {
934     JSValue thisValue = exec->thisValue();
935     if (!thisValue.inherits(DateInstance::info()))
936         return throwVMTypeError(exec);
937
938     DateInstance* thisDateObj = asDateInstance(thisValue);
939     if (!exec->argumentCount()) {
940         JSValue result = jsNaN();
941         thisDateObj->setInternalValue(exec->vm(), result);
942         return JSValue::encode(result);
943     }
944
945     VM& vm = exec->vm();
946     double milli = thisDateObj->internalNumber();
947     double ms = 0; 
948
949     GregorianDateTime gregorianDateTime; 
950     if (numArgsToUse == 3 && std::isnan(milli)) 
951         msToGregorianDateTime(vm, 0, WTF::UTCTime, gregorianDateTime);
952     else { 
953         ms = milli - floor(milli / msPerSecond) * msPerSecond; 
954         const GregorianDateTime* other = inputTimeType == WTF::UTCTime
955             ? thisDateObj->gregorianDateTimeUTC(exec)
956             : thisDateObj->gregorianDateTime(exec);
957         if (!other)
958             return JSValue::encode(jsNaN());
959         gregorianDateTime.copyFrom(*other);
960     }
961     
962     if (!fillStructuresUsingDateArgs(exec, numArgsToUse, &ms, &gregorianDateTime)) {
963         JSValue result = jsNaN();
964         thisDateObj->setInternalValue(vm, result);
965         return JSValue::encode(result);
966     } 
967            
968     JSValue result = jsNumber(gregorianDateTimeToMS(vm, gregorianDateTime, ms, inputTimeType));
969     thisDateObj->setInternalValue(vm, result);
970     return JSValue::encode(result);
971 }
972
973 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMilliSeconds(ExecState* exec)
974 {
975     return setNewValueFromTimeArgs(exec, 1, WTF::LocalTime);
976 }
977
978 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMilliseconds(ExecState* exec)
979 {
980     return setNewValueFromTimeArgs(exec, 1, WTF::UTCTime);
981 }
982
983 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetSeconds(ExecState* exec)
984 {
985     return setNewValueFromTimeArgs(exec, 2, WTF::LocalTime);
986 }
987
988 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCSeconds(ExecState* exec)
989 {
990     return setNewValueFromTimeArgs(exec, 2, WTF::UTCTime);
991 }
992
993 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMinutes(ExecState* exec)
994 {
995     return setNewValueFromTimeArgs(exec, 3, WTF::LocalTime);
996 }
997
998 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMinutes(ExecState* exec)
999 {
1000     return setNewValueFromTimeArgs(exec, 3, WTF::UTCTime);
1001 }
1002
1003 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetHours(ExecState* exec)
1004 {
1005     return setNewValueFromTimeArgs(exec, 4, WTF::LocalTime);
1006 }
1007
1008 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCHours(ExecState* exec)
1009 {
1010     return setNewValueFromTimeArgs(exec, 4, WTF::UTCTime);
1011 }
1012
1013 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetDate(ExecState* exec)
1014 {
1015     return setNewValueFromDateArgs(exec, 1, WTF::LocalTime);
1016 }
1017
1018 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCDate(ExecState* exec)
1019 {
1020     return setNewValueFromDateArgs(exec, 1, WTF::UTCTime);
1021 }
1022
1023 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMonth(ExecState* exec)
1024 {
1025     return setNewValueFromDateArgs(exec, 2, WTF::LocalTime);
1026 }
1027
1028 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMonth(ExecState* exec)
1029 {
1030     return setNewValueFromDateArgs(exec, 2, WTF::UTCTime);
1031 }
1032
1033 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetFullYear(ExecState* exec)
1034 {
1035     return setNewValueFromDateArgs(exec, 3, WTF::LocalTime);
1036 }
1037
1038 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCFullYear(ExecState* exec)
1039 {
1040     return setNewValueFromDateArgs(exec, 3, WTF::UTCTime);
1041 }
1042
1043 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState* exec)
1044 {
1045     JSValue thisValue = exec->thisValue();
1046     if (!thisValue.inherits(DateInstance::info()))
1047         return throwVMTypeError(exec);
1048
1049     VM& vm = exec->vm();
1050     DateInstance* thisDateObj = asDateInstance(thisValue);
1051     if (!exec->argumentCount()) { 
1052         JSValue result = jsNaN();
1053         thisDateObj->setInternalValue(vm, result);
1054         return JSValue::encode(result);
1055     }
1056
1057     double milli = thisDateObj->internalNumber();
1058     double ms = 0;
1059
1060     GregorianDateTime gregorianDateTime;
1061     if (std::isnan(milli))
1062         // Based on ECMA 262 B.2.5 (setYear)
1063         // the time must be reset to +0 if it is NaN.
1064         msToGregorianDateTime(vm, 0, WTF::UTCTime, gregorianDateTime);
1065     else {
1066         double secs = floor(milli / msPerSecond);
1067         ms = milli - secs * msPerSecond;
1068         if (const GregorianDateTime* other = thisDateObj->gregorianDateTime(exec))
1069             gregorianDateTime.copyFrom(*other);
1070     }
1071
1072     double year = exec->argument(0).toIntegerPreserveNaN(exec);
1073     if (!std::isfinite(year)) {
1074         JSValue result = jsNaN();
1075         thisDateObj->setInternalValue(vm, result);
1076         return JSValue::encode(result);
1077     }
1078
1079     gregorianDateTime.setYear(toInt32((year >= 0 && year <= 99) ? (year + 1900) : year));
1080     JSValue result = jsNumber(gregorianDateTimeToMS(vm, gregorianDateTime, ms, WTF::LocalTime));
1081     thisDateObj->setInternalValue(vm, result);
1082     return JSValue::encode(result);
1083 }
1084
1085 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState* exec)
1086 {
1087     JSValue thisValue = exec->thisValue();
1088     if (!thisValue.inherits(DateInstance::info()))
1089         return throwVMTypeError(exec);
1090
1091     DateInstance* thisDateObj = asDateInstance(thisValue); 
1092
1093     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
1094     if (!gregorianDateTime)
1095         return JSValue::encode(jsNaN());
1096
1097     // NOTE: IE returns the full year even in getYear.
1098     return JSValue::encode(jsNumber(gregorianDateTime->year() - 1900));
1099 }
1100
1101 EncodedJSValue JSC_HOST_CALL dateProtoFuncToJSON(ExecState* exec)
1102 {
1103     JSValue thisValue = exec->thisValue();
1104     JSObject* object = jsCast<JSObject*>(thisValue.toThis(exec, NotStrictMode));
1105     if (exec->hadException())
1106         return JSValue::encode(jsNull());
1107
1108     JSValue timeValue = object->toPrimitive(exec, PreferNumber);
1109     if (exec->hadException())
1110         return JSValue::encode(jsNull());
1111     if (timeValue.isNumber() && !(timeValue.isInt32() || std::isfinite(timeValue.asDouble())))
1112         return JSValue::encode(jsNull());
1113
1114     JSValue toISOValue = object->get(exec, exec->vm().propertyNames->toISOString);
1115     if (exec->hadException())
1116         return JSValue::encode(jsNull());
1117
1118     CallData callData;
1119     CallType callType = getCallData(toISOValue, callData);
1120     if (callType == CallTypeNone)
1121         return throwVMError(exec, createTypeError(exec, ASCIILiteral("toISOString is not a function")));
1122
1123     JSValue result = call(exec, asObject(toISOValue), callType, callData, object, exec->emptyList());
1124     if (exec->hadException())
1125         return JSValue::encode(jsNull());
1126     if (result.isObject())
1127         return throwVMError(exec, createTypeError(exec, ASCIILiteral("toISOString did not return a primitive value")));
1128     return JSValue::encode(result);
1129 }
1130
1131 } // namespace JSC