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