Add static version of JSCell::getOwnPropertySlot
[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)) || OS(SYMBIAN)
205      // strftime() does not support '#' on WinCE or Symbian
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(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
447 {
448     return getOwnPropertySlot(this, exec, propertyName, slot);
449 }
450
451 bool DatePrototype::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
452 {
453     return getStaticFunctionSlot<JSObject>(exec, ExecState::dateTable(exec), static_cast<DatePrototype*>(cell), propertyName, slot);
454 }
455
456 bool DatePrototype::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
457 {
458     return getStaticFunctionDescriptor<JSObject>(exec, ExecState::dateTable(exec), this, propertyName, descriptor);
459 }
460
461 // Functions
462
463 EncodedJSValue JSC_HOST_CALL dateProtoFuncToString(ExecState* exec)
464 {
465     JSValue thisValue = exec->hostThisValue();
466     if (!thisValue.inherits(&DateInstance::s_info))
467         return throwVMTypeError(exec);
468
469     DateInstance* thisDateObj = asDateInstance(thisValue); 
470
471     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
472     if (!gregorianDateTime)
473         return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
474     DateConversionBuffer date;
475     DateConversionBuffer time;
476     formatDate(*gregorianDateTime, date);
477     formatTime(*gregorianDateTime, time);
478     return JSValue::encode(jsMakeNontrivialString(exec, date, " ", time));
479 }
480
481 EncodedJSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState* exec)
482 {
483     JSValue thisValue = exec->hostThisValue();
484     if (!thisValue.inherits(&DateInstance::s_info))
485         return throwVMTypeError(exec);
486
487     DateInstance* thisDateObj = asDateInstance(thisValue); 
488
489     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
490     if (!gregorianDateTime)
491         return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
492     DateConversionBuffer date;
493     DateConversionBuffer time;
494     formatDateUTCVariant(*gregorianDateTime, date);
495     formatTimeUTC(*gregorianDateTime, time);
496     return JSValue::encode(jsMakeNontrivialString(exec, date, " ", time));
497 }
498
499 EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState* exec)
500 {
501     JSValue thisValue = exec->hostThisValue();
502     if (!thisValue.inherits(&DateInstance::s_info))
503         return throwVMTypeError(exec);
504     
505     DateInstance* thisDateObj = asDateInstance(thisValue); 
506     
507     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
508     if (!gregorianDateTime)
509         return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
510     // 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)
511     // 6 for formatting and one for null termination = 28. We add one extra character to allow us to force null termination.
512     char buffer[29];
513     // 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).
514     if (gregorianDateTime->year > 8099 || gregorianDateTime->year < -1900)
515         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)));
516     else
517         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)));
518     buffer[sizeof(buffer) - 1] = 0;
519     return JSValue::encode(jsNontrivialString(exec, buffer));
520 }
521
522 EncodedJSValue JSC_HOST_CALL dateProtoFuncToDateString(ExecState* exec)
523 {
524     JSValue thisValue = exec->hostThisValue();
525     if (!thisValue.inherits(&DateInstance::s_info))
526         return throwVMTypeError(exec);
527
528     DateInstance* thisDateObj = asDateInstance(thisValue); 
529
530     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
531     if (!gregorianDateTime)
532         return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
533     DateConversionBuffer date;
534     formatDate(*gregorianDateTime, date);
535     return JSValue::encode(jsNontrivialString(exec, date));
536 }
537
538 EncodedJSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState* exec)
539 {
540     JSValue thisValue = exec->hostThisValue();
541     if (!thisValue.inherits(&DateInstance::s_info))
542         return throwVMTypeError(exec);
543
544     DateInstance* thisDateObj = asDateInstance(thisValue); 
545
546     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
547     if (!gregorianDateTime)
548         return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
549     DateConversionBuffer time;
550     formatTime(*gregorianDateTime, time);
551     return JSValue::encode(jsNontrivialString(exec, time));
552 }
553
554 EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState* exec)
555 {
556     JSValue thisValue = exec->hostThisValue();
557     if (!thisValue.inherits(&DateInstance::s_info))
558         return throwVMTypeError(exec);
559
560     DateInstance* thisDateObj = asDateInstance(thisValue); 
561     return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleDateAndTime));
562 }
563
564 EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState* exec)
565 {
566     JSValue thisValue = exec->hostThisValue();
567     if (!thisValue.inherits(&DateInstance::s_info))
568         return throwVMTypeError(exec);
569
570     DateInstance* thisDateObj = asDateInstance(thisValue); 
571     return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleDate));
572 }
573
574 EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState* exec)
575 {
576     JSValue thisValue = exec->hostThisValue();
577     if (!thisValue.inherits(&DateInstance::s_info))
578         return throwVMTypeError(exec);
579
580     DateInstance* thisDateObj = asDateInstance(thisValue); 
581     return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleTime));
582 }
583
584 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState* exec)
585 {
586     JSValue thisValue = exec->hostThisValue();
587     if (!thisValue.inherits(&DateInstance::s_info))
588         return throwVMTypeError(exec);
589
590     return JSValue::encode(asDateInstance(thisValue)->internalValue());
591 }
592
593 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState* exec)
594 {
595     JSValue thisValue = exec->hostThisValue();
596     if (!thisValue.inherits(&DateInstance::s_info))
597         return throwVMTypeError(exec);
598
599     DateInstance* thisDateObj = asDateInstance(thisValue); 
600
601     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
602     if (!gregorianDateTime)
603         return JSValue::encode(jsNaN());
604     return JSValue::encode(jsNumber(1900 + gregorianDateTime->year));
605 }
606
607 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState* exec)
608 {
609     JSValue thisValue = exec->hostThisValue();
610     if (!thisValue.inherits(&DateInstance::s_info))
611         return throwVMTypeError(exec);
612
613     DateInstance* thisDateObj = asDateInstance(thisValue); 
614
615     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
616     if (!gregorianDateTime)
617         return JSValue::encode(jsNaN());
618     return JSValue::encode(jsNumber(1900 + gregorianDateTime->year));
619 }
620
621 EncodedJSValue JSC_HOST_CALL dateProtoFuncToGMTString(ExecState* exec)
622 {
623     JSValue thisValue = exec->hostThisValue();
624     if (!thisValue.inherits(&DateInstance::s_info))
625         return throwVMTypeError(exec);
626
627     DateInstance* thisDateObj = asDateInstance(thisValue); 
628
629     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
630     if (!gregorianDateTime)
631         return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
632     DateConversionBuffer date;
633     DateConversionBuffer time;
634     formatDateUTCVariant(*gregorianDateTime, date);
635     formatTimeUTC(*gregorianDateTime, time);
636     return JSValue::encode(jsMakeNontrivialString(exec, date, " ", time));
637 }
638
639 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState* exec)
640 {
641     JSValue thisValue = exec->hostThisValue();
642     if (!thisValue.inherits(&DateInstance::s_info))
643         return throwVMTypeError(exec);
644
645     DateInstance* thisDateObj = asDateInstance(thisValue); 
646
647     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
648     if (!gregorianDateTime)
649         return JSValue::encode(jsNaN());
650     return JSValue::encode(jsNumber(gregorianDateTime->month));
651 }
652
653 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState* exec)
654 {
655     JSValue thisValue = exec->hostThisValue();
656     if (!thisValue.inherits(&DateInstance::s_info))
657         return throwVMTypeError(exec);
658
659     DateInstance* thisDateObj = asDateInstance(thisValue); 
660
661     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
662     if (!gregorianDateTime)
663         return JSValue::encode(jsNaN());
664     return JSValue::encode(jsNumber(gregorianDateTime->month));
665 }
666
667 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState* exec)
668 {
669     JSValue thisValue = exec->hostThisValue();
670     if (!thisValue.inherits(&DateInstance::s_info))
671         return throwVMTypeError(exec);
672
673     DateInstance* thisDateObj = asDateInstance(thisValue); 
674
675     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
676     if (!gregorianDateTime)
677         return JSValue::encode(jsNaN());
678     return JSValue::encode(jsNumber(gregorianDateTime->monthDay));
679 }
680
681 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState* exec)
682 {
683     JSValue thisValue = exec->hostThisValue();
684     if (!thisValue.inherits(&DateInstance::s_info))
685         return throwVMTypeError(exec);
686
687     DateInstance* thisDateObj = asDateInstance(thisValue); 
688
689     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
690     if (!gregorianDateTime)
691         return JSValue::encode(jsNaN());
692     return JSValue::encode(jsNumber(gregorianDateTime->monthDay));
693 }
694
695 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState* exec)
696 {
697     JSValue thisValue = exec->hostThisValue();
698     if (!thisValue.inherits(&DateInstance::s_info))
699         return throwVMTypeError(exec);
700
701     DateInstance* thisDateObj = asDateInstance(thisValue); 
702
703     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
704     if (!gregorianDateTime)
705         return JSValue::encode(jsNaN());
706     return JSValue::encode(jsNumber(gregorianDateTime->weekDay));
707 }
708
709 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState* exec)
710 {
711     JSValue thisValue = exec->hostThisValue();
712     if (!thisValue.inherits(&DateInstance::s_info))
713         return throwVMTypeError(exec);
714
715     DateInstance* thisDateObj = asDateInstance(thisValue); 
716
717     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
718     if (!gregorianDateTime)
719         return JSValue::encode(jsNaN());
720     return JSValue::encode(jsNumber(gregorianDateTime->weekDay));
721 }
722
723 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState* exec)
724 {
725     JSValue thisValue = exec->hostThisValue();
726     if (!thisValue.inherits(&DateInstance::s_info))
727         return throwVMTypeError(exec);
728
729     DateInstance* thisDateObj = asDateInstance(thisValue); 
730
731     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
732     if (!gregorianDateTime)
733         return JSValue::encode(jsNaN());
734     return JSValue::encode(jsNumber(gregorianDateTime->hour));
735 }
736
737 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState* exec)
738 {
739     JSValue thisValue = exec->hostThisValue();
740     if (!thisValue.inherits(&DateInstance::s_info))
741         return throwVMTypeError(exec);
742
743     DateInstance* thisDateObj = asDateInstance(thisValue); 
744
745     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
746     if (!gregorianDateTime)
747         return JSValue::encode(jsNaN());
748     return JSValue::encode(jsNumber(gregorianDateTime->hour));
749 }
750
751 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState* exec)
752 {
753     JSValue thisValue = exec->hostThisValue();
754     if (!thisValue.inherits(&DateInstance::s_info))
755         return throwVMTypeError(exec);
756
757     DateInstance* thisDateObj = asDateInstance(thisValue); 
758
759     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
760     if (!gregorianDateTime)
761         return JSValue::encode(jsNaN());
762     return JSValue::encode(jsNumber(gregorianDateTime->minute));
763 }
764
765 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(ExecState* exec)
766 {
767     JSValue thisValue = exec->hostThisValue();
768     if (!thisValue.inherits(&DateInstance::s_info))
769         return throwVMTypeError(exec);
770
771     DateInstance* thisDateObj = asDateInstance(thisValue); 
772
773     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
774     if (!gregorianDateTime)
775         return JSValue::encode(jsNaN());
776     return JSValue::encode(jsNumber(gregorianDateTime->minute));
777 }
778
779 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetSeconds(ExecState* exec)
780 {
781     JSValue thisValue = exec->hostThisValue();
782     if (!thisValue.inherits(&DateInstance::s_info))
783         return throwVMTypeError(exec);
784
785     DateInstance* thisDateObj = asDateInstance(thisValue); 
786
787     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
788     if (!gregorianDateTime)
789         return JSValue::encode(jsNaN());
790     return JSValue::encode(jsNumber(gregorianDateTime->second));
791 }
792
793 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState* exec)
794 {
795     JSValue thisValue = exec->hostThisValue();
796     if (!thisValue.inherits(&DateInstance::s_info))
797         return throwVMTypeError(exec);
798
799     DateInstance* thisDateObj = asDateInstance(thisValue); 
800
801     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
802     if (!gregorianDateTime)
803         return JSValue::encode(jsNaN());
804     return JSValue::encode(jsNumber(gregorianDateTime->second));
805 }
806
807 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState* exec)
808 {
809     JSValue thisValue = exec->hostThisValue();
810     if (!thisValue.inherits(&DateInstance::s_info))
811         return throwVMTypeError(exec);
812
813     DateInstance* thisDateObj = asDateInstance(thisValue); 
814     double milli = thisDateObj->internalNumber();
815     if (isnan(milli))
816         return JSValue::encode(jsNaN());
817
818     double secs = floor(milli / msPerSecond);
819     double ms = milli - secs * msPerSecond;
820     return JSValue::encode(jsNumber(ms));
821 }
822
823 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState* exec)
824 {
825     JSValue thisValue = exec->hostThisValue();
826     if (!thisValue.inherits(&DateInstance::s_info))
827         return throwVMTypeError(exec);
828
829     DateInstance* thisDateObj = asDateInstance(thisValue); 
830     double milli = thisDateObj->internalNumber();
831     if (isnan(milli))
832         return JSValue::encode(jsNaN());
833
834     double secs = floor(milli / msPerSecond);
835     double ms = milli - secs * msPerSecond;
836     return JSValue::encode(jsNumber(ms));
837 }
838
839 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState* exec)
840 {
841     JSValue thisValue = exec->hostThisValue();
842     if (!thisValue.inherits(&DateInstance::s_info))
843         return throwVMTypeError(exec);
844
845     DateInstance* thisDateObj = asDateInstance(thisValue); 
846
847     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
848     if (!gregorianDateTime)
849         return JSValue::encode(jsNaN());
850     return JSValue::encode(jsNumber(-gregorianDateTime->utcOffset / minutesPerHour));
851 }
852
853 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState* exec)
854 {
855     JSValue thisValue = exec->hostThisValue();
856     if (!thisValue.inherits(&DateInstance::s_info))
857         return throwVMTypeError(exec);
858
859     DateInstance* thisDateObj = asDateInstance(thisValue); 
860
861     double milli = timeClip(exec->argument(0).toNumber(exec));
862     JSValue result = jsNumber(milli);
863     thisDateObj->setInternalValue(exec->globalData(), result);
864     return JSValue::encode(result);
865 }
866
867 static EncodedJSValue setNewValueFromTimeArgs(ExecState* exec, int numArgsToUse, bool inputIsUTC)
868 {
869     JSValue thisValue = exec->hostThisValue();
870     if (!thisValue.inherits(&DateInstance::s_info))
871         return throwVMTypeError(exec);
872
873     DateInstance* thisDateObj = asDateInstance(thisValue);
874     double milli = thisDateObj->internalNumber();
875     
876     if (!exec->argumentCount() || isnan(milli)) {
877         JSValue result = jsNaN();
878         thisDateObj->setInternalValue(exec->globalData(), result);
879         return JSValue::encode(result);
880     }
881      
882     double secs = floor(milli / msPerSecond);
883     double ms = milli - secs * msPerSecond;
884
885     const GregorianDateTime* other = inputIsUTC 
886         ? thisDateObj->gregorianDateTimeUTC(exec)
887         : thisDateObj->gregorianDateTime(exec);
888     if (!other)
889         return JSValue::encode(jsNaN());
890
891     GregorianDateTime gregorianDateTime;
892     gregorianDateTime.copyFrom(*other);
893     if (!fillStructuresUsingTimeArgs(exec, numArgsToUse, &ms, &gregorianDateTime)) {
894         JSValue result = jsNaN();
895         thisDateObj->setInternalValue(exec->globalData(), result);
896         return JSValue::encode(result);
897     } 
898     
899     JSValue result = jsNumber(gregorianDateTimeToMS(exec, gregorianDateTime, ms, inputIsUTC));
900     thisDateObj->setInternalValue(exec->globalData(), result);
901     return JSValue::encode(result);
902 }
903
904 static EncodedJSValue setNewValueFromDateArgs(ExecState* exec, int numArgsToUse, bool inputIsUTC)
905 {
906     JSValue thisValue = exec->hostThisValue();
907     if (!thisValue.inherits(&DateInstance::s_info))
908         return throwVMTypeError(exec);
909
910     DateInstance* thisDateObj = asDateInstance(thisValue);
911     if (!exec->argumentCount()) {
912         JSValue result = jsNaN();
913         thisDateObj->setInternalValue(exec->globalData(), result);
914         return JSValue::encode(result);
915     }      
916     
917     double milli = thisDateObj->internalNumber();
918     double ms = 0; 
919
920     GregorianDateTime gregorianDateTime; 
921     if (numArgsToUse == 3 && isnan(milli)) 
922         msToGregorianDateTime(exec, 0, true, gregorianDateTime); 
923     else { 
924         ms = milli - floor(milli / msPerSecond) * msPerSecond; 
925         const GregorianDateTime* other = inputIsUTC 
926             ? thisDateObj->gregorianDateTimeUTC(exec)
927             : thisDateObj->gregorianDateTime(exec);
928         if (!other)
929             return JSValue::encode(jsNaN());
930         gregorianDateTime.copyFrom(*other);
931     }
932     
933     if (!fillStructuresUsingDateArgs(exec, numArgsToUse, &ms, &gregorianDateTime)) {
934         JSValue result = jsNaN();
935         thisDateObj->setInternalValue(exec->globalData(), result);
936         return JSValue::encode(result);
937     } 
938            
939     JSValue result = jsNumber(gregorianDateTimeToMS(exec, gregorianDateTime, ms, inputIsUTC));
940     thisDateObj->setInternalValue(exec->globalData(), result);
941     return JSValue::encode(result);
942 }
943
944 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMilliSeconds(ExecState* exec)
945 {
946     const bool inputIsUTC = false;
947     return setNewValueFromTimeArgs(exec, 1, inputIsUTC);
948 }
949
950 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMilliseconds(ExecState* exec)
951 {
952     const bool inputIsUTC = true;
953     return setNewValueFromTimeArgs(exec, 1, inputIsUTC);
954 }
955
956 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetSeconds(ExecState* exec)
957 {
958     const bool inputIsUTC = false;
959     return setNewValueFromTimeArgs(exec, 2, inputIsUTC);
960 }
961
962 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCSeconds(ExecState* exec)
963 {
964     const bool inputIsUTC = true;
965     return setNewValueFromTimeArgs(exec, 2, inputIsUTC);
966 }
967
968 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMinutes(ExecState* exec)
969 {
970     const bool inputIsUTC = false;
971     return setNewValueFromTimeArgs(exec, 3, inputIsUTC);
972 }
973
974 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMinutes(ExecState* exec)
975 {
976     const bool inputIsUTC = true;
977     return setNewValueFromTimeArgs(exec, 3, inputIsUTC);
978 }
979
980 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetHours(ExecState* exec)
981 {
982     const bool inputIsUTC = false;
983     return setNewValueFromTimeArgs(exec, 4, inputIsUTC);
984 }
985
986 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCHours(ExecState* exec)
987 {
988     const bool inputIsUTC = true;
989     return setNewValueFromTimeArgs(exec, 4, inputIsUTC);
990 }
991
992 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetDate(ExecState* exec)
993 {
994     const bool inputIsUTC = false;
995     return setNewValueFromDateArgs(exec, 1, inputIsUTC);
996 }
997
998 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCDate(ExecState* exec)
999 {
1000     const bool inputIsUTC = true;
1001     return setNewValueFromDateArgs(exec, 1, inputIsUTC);
1002 }
1003
1004 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMonth(ExecState* exec)
1005 {
1006     const bool inputIsUTC = false;
1007     return setNewValueFromDateArgs(exec, 2, inputIsUTC);
1008 }
1009
1010 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMonth(ExecState* exec)
1011 {
1012     const bool inputIsUTC = true;
1013     return setNewValueFromDateArgs(exec, 2, inputIsUTC);
1014 }
1015
1016 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetFullYear(ExecState* exec)
1017 {
1018     const bool inputIsUTC = false;
1019     return setNewValueFromDateArgs(exec, 3, inputIsUTC);
1020 }
1021
1022 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCFullYear(ExecState* exec)
1023 {
1024     const bool inputIsUTC = true;
1025     return setNewValueFromDateArgs(exec, 3, inputIsUTC);
1026 }
1027
1028 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState* exec)
1029 {
1030     JSValue thisValue = exec->hostThisValue();
1031     if (!thisValue.inherits(&DateInstance::s_info))
1032         return throwVMTypeError(exec);
1033
1034     DateInstance* thisDateObj = asDateInstance(thisValue);     
1035     if (!exec->argumentCount()) { 
1036         JSValue result = jsNaN();
1037         thisDateObj->setInternalValue(exec->globalData(), result);
1038         return JSValue::encode(result);
1039     }
1040     
1041     double milli = thisDateObj->internalNumber();
1042     double ms = 0;
1043
1044     GregorianDateTime gregorianDateTime;
1045     if (isnan(milli))
1046         // Based on ECMA 262 B.2.5 (setYear)
1047         // the time must be reset to +0 if it is NaN. 
1048         msToGregorianDateTime(exec, 0, true, gregorianDateTime);
1049     else {   
1050         double secs = floor(milli / msPerSecond);
1051         ms = milli - secs * msPerSecond;
1052         if (const GregorianDateTime* other = thisDateObj->gregorianDateTime(exec))
1053             gregorianDateTime.copyFrom(*other);
1054     }
1055     
1056     double year = exec->argument(0).toIntegerPreserveNaN(exec);
1057     if (!isfinite(year)) {
1058         JSValue result = jsNaN();
1059         thisDateObj->setInternalValue(exec->globalData(), result);
1060         return JSValue::encode(result);
1061     }
1062             
1063     gregorianDateTime.year = toInt32((year > 99 || year < 0) ? year - 1900 : year);
1064     JSValue result = jsNumber(gregorianDateTimeToMS(exec, gregorianDateTime, ms, false));
1065     thisDateObj->setInternalValue(exec->globalData(), result);
1066     return JSValue::encode(result);
1067 }
1068
1069 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState* exec)
1070 {
1071     JSValue thisValue = exec->hostThisValue();
1072     if (!thisValue.inherits(&DateInstance::s_info))
1073         return throwVMTypeError(exec);
1074
1075     DateInstance* thisDateObj = asDateInstance(thisValue); 
1076
1077     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
1078     if (!gregorianDateTime)
1079         return JSValue::encode(jsNaN());
1080
1081     // NOTE: IE returns the full year even in getYear.
1082     return JSValue::encode(jsNumber(gregorianDateTime->year));
1083 }
1084
1085 EncodedJSValue JSC_HOST_CALL dateProtoFuncToJSON(ExecState* exec)
1086 {
1087     JSValue thisValue = exec->hostThisValue();
1088     JSObject* object = thisValue.toThisObject(exec);
1089     if (exec->hadException())
1090         return JSValue::encode(jsNull());
1091     
1092     JSValue toISOValue = object->get(exec, exec->globalData().propertyNames->toISOString);
1093     if (exec->hadException())
1094         return JSValue::encode(jsNull());
1095
1096     CallData callData;
1097     CallType callType = getCallData(toISOValue, callData);
1098     if (callType == CallTypeNone)
1099         return throwVMError(exec, createTypeError(exec, "toISOString is not a function"));
1100
1101     JSValue result = call(exec, asObject(toISOValue), callType, callData, object, exec->emptyList());
1102     if (exec->hadException())
1103         return JSValue::encode(jsNull());
1104     if (result.isObject())
1105         return throwVMError(exec, createTypeError(exec, "toISOString did not return a primitive value"));
1106     return JSValue::encode(result);
1107 }
1108
1109 } // namespace JSC