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