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