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