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