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