Windows build fix.
[WebKit-https.git] / JavaScriptCore / kjs / date_object.cpp
1 /*
2  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2004, 2005, 2006, 2007 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 "date_object.h"
24 #include "date_object.lut.h"
25 #include "internal.h"
26
27 #if HAVE(ERRNO_H)
28 #include <errno.h>
29 #endif
30
31 #if HAVE(SYS_PARAM_H)
32 #include <sys/param.h>
33 #endif
34
35 #if HAVE(SYS_TIME_H)
36 #include <sys/time.h>
37 #endif
38
39 #if HAVE(SYS_TIMEB_H)
40 #include <sys/timeb.h>
41 #endif
42
43 #include <float.h>
44 #include <limits.h>
45 #include <locale.h>
46 #include <math.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <time.h>
51
52 #include "error_object.h"
53 #include "operations.h"
54 #include "DateMath.h"
55
56 #include <wtf/ASCIICType.h>
57 #include <wtf/Assertions.h>
58 #include <wtf/MathExtras.h>
59 #include <wtf/StringExtras.h>
60 #include <wtf/UnusedParam.h>
61
62 #if PLATFORM(MAC)
63     #include <CoreFoundation/CoreFoundation.h>
64 #endif
65
66 using namespace WTF;
67
68 namespace KJS {
69
70 static double parseDate(const UString&);
71 static double timeClip(double);
72
73 inline int gmtoffset(const GregorianDateTime& t)
74 {
75     return t.utcOffset;
76 }
77
78
79 /**
80  * @internal
81  *
82  * Class to implement all methods that are properties of the
83  * Date object
84  */
85 class DateObjectFuncImp : public InternalFunctionImp {
86 public:
87     DateObjectFuncImp(ExecState *, FunctionPrototype *, int i, int len, const Identifier& );
88
89     virtual JSValue *callAsFunction(ExecState *, JSObject *thisObj, const List &args);
90
91     enum { Parse, UTC };
92
93 private:
94     int id;
95 };
96
97 #if PLATFORM(MAC)
98
99 static CFDateFormatterStyle styleFromArgString(const UString& string, CFDateFormatterStyle defaultStyle)
100 {
101     if (string == "short")
102         return kCFDateFormatterShortStyle;
103     if (string == "medium")
104         return kCFDateFormatterMediumStyle;
105     if (string == "long")
106         return kCFDateFormatterLongStyle;
107     if (string == "full")
108         return kCFDateFormatterFullStyle;
109     return defaultStyle;
110 }
111
112 static UString formatLocaleDate(ExecState *exec, double time, bool includeDate, bool includeTime, const List &args)
113 {
114     CFDateFormatterStyle dateStyle = (includeDate ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle);
115     CFDateFormatterStyle timeStyle = (includeTime ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle);
116
117     bool useCustomFormat = false;
118     UString customFormatString;
119
120     UString arg0String = args[0]->toString(exec);
121     if (arg0String == "custom" && !args[1]->isUndefined()) {
122         useCustomFormat = true;
123         customFormatString = args[1]->toString(exec);
124     } else if (includeDate && includeTime && !args[1]->isUndefined()) {
125         dateStyle = styleFromArgString(arg0String, dateStyle);
126         timeStyle = styleFromArgString(args[1]->toString(exec), timeStyle);
127     } else if (includeDate && !args[0]->isUndefined()) {
128         dateStyle = styleFromArgString(arg0String, dateStyle);
129     } else if (includeTime && !args[0]->isUndefined()) {
130         timeStyle = styleFromArgString(arg0String, timeStyle);
131     }
132
133     CFLocaleRef locale = CFLocaleCopyCurrent();
134     CFDateFormatterRef formatter = CFDateFormatterCreate(0, locale, dateStyle, timeStyle);
135     CFRelease(locale);
136
137     if (useCustomFormat) {
138         CFStringRef customFormatCFString = CFStringCreateWithCharacters(0, (UniChar *)customFormatString.data(), customFormatString.size());
139         CFDateFormatterSetFormat(formatter, customFormatCFString);
140         CFRelease(customFormatCFString);
141     }
142
143     CFStringRef string = CFDateFormatterCreateStringWithAbsoluteTime(0, formatter, time - kCFAbsoluteTimeIntervalSince1970);
144
145     CFRelease(formatter);
146
147     // We truncate the string returned from CFDateFormatter if it's absurdly long (> 200 characters).
148     // That's not great error handling, but it just won't happen so it doesn't matter.
149     UChar buffer[200];
150     const size_t bufferLength = sizeof(buffer) / sizeof(buffer[0]);
151     size_t length = CFStringGetLength(string);
152     ASSERT(length <= bufferLength);
153     if (length > bufferLength)
154         length = bufferLength;
155     CFStringGetCharacters(string, CFRangeMake(0, length), reinterpret_cast<UniChar *>(buffer));
156
157     CFRelease(string);
158
159     return UString(buffer, length);
160 }
161
162 #else
163
164 enum LocaleDateTimeFormat { LocaleDateAndTime, LocaleDate, LocaleTime };
165  
166 static JSCell* formatLocaleDate(const GregorianDateTime& gdt, const LocaleDateTimeFormat format)
167 {
168     static const char* formatStrings[] = {"%#c", "%#x", "%X"};
169  
170     // Offset year if needed
171     struct tm localTM = gdt;
172     int year = gdt.year + 1900;
173     bool yearNeedsOffset = year < 1900 || year > 2038;
174     if (yearNeedsOffset) {
175         localTM.tm_year = equivalentYearForDST(year) - 1900;
176      }
177  
178     // Do the formatting
179     const int bufsize=128;
180     char timebuffer[bufsize];
181     size_t ret = strftime(timebuffer, bufsize, formatStrings[format], &localTM);
182  
183     if ( ret == 0 )
184         return jsString("");
185  
186     // Copy original into the buffer
187     if (yearNeedsOffset && format != LocaleTime) {
188         static const int yearLen = 5;   // FIXME will be a problem in the year 10,000
189         char yearString[yearLen];
190  
191         snprintf(yearString, yearLen, "%d", localTM.tm_year + 1900);
192         char* yearLocation = strstr(timebuffer, yearString);
193         snprintf(yearString, yearLen, "%d", year);
194  
195         strncpy(yearLocation, yearString, yearLen - 1);
196     }
197  
198     return jsString(timebuffer);
199 }
200
201 #endif // PLATFORM(WIN_OS)
202
203 static UString formatDate(const GregorianDateTime &t)
204 {
205     char buffer[100];
206     snprintf(buffer, sizeof(buffer), "%s %s %02d %04d",
207         weekdayName[(t.weekDay + 6) % 7],
208         monthName[t.month], t.monthDay, t.year + 1900);
209     return buffer;
210 }
211
212 static UString formatDateUTCVariant(const GregorianDateTime &t)
213 {
214     char buffer[100];
215     snprintf(buffer, sizeof(buffer), "%s, %02d %s %04d",
216         weekdayName[(t.weekDay + 6) % 7],
217         t.monthDay, monthName[t.month], t.year + 1900);
218     return buffer;
219 }
220
221 static UString formatTime(const GregorianDateTime &t, bool utc)
222 {
223     char buffer[100];
224     if (utc) {
225         snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d GMT", t.hour, t.minute, t.second);
226     } else {
227         int offset = abs(gmtoffset(t));
228         char tzname[70];
229         struct tm gtm = t;
230         strftime(tzname, sizeof(tzname), "%Z", &gtm);
231
232         if (tzname) {
233             snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d GMT%c%02d%02d (%s)",
234                 t.hour, t.minute, t.second,
235                 gmtoffset(t) < 0 ? '-' : '+', offset / (60*60), (offset / 60) % 60, tzname);
236         } else {
237             snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d GMT%c%02d%02d",
238                 t.hour, t.minute, t.second,
239                 gmtoffset(t) < 0 ? '-' : '+', offset / (60*60), (offset / 60) % 60);
240         }
241     }
242     return UString(buffer);
243 }
244
245 // Converts a list of arguments sent to a Date member function into milliseconds, updating
246 // ms (representing milliseconds) and t (representing the rest of the date structure) appropriately.
247 //
248 // Format of member function: f([hour,] [min,] [sec,] [ms])
249 static void fillStructuresUsingTimeArgs(ExecState *exec, const List &args, int maxArgs, double *ms, GregorianDateTime *t)
250 {
251     double milliseconds = 0;
252     int idx = 0;
253     int numArgs = args.size();
254     
255     // JS allows extra trailing arguments -- ignore them
256     if (numArgs > maxArgs)
257         numArgs = maxArgs;
258
259     // hours
260     if (maxArgs >= 4 && idx < numArgs) {
261         t->hour = 0;
262         milliseconds += args[idx++]->toInt32(exec) * msPerHour;
263     }
264
265     // minutes
266     if (maxArgs >= 3 && idx < numArgs) {
267         t->minute = 0;
268         milliseconds += args[idx++]->toInt32(exec) * msPerMinute;
269     }
270     
271     // seconds
272     if (maxArgs >= 2 && idx < numArgs) {
273         t->second = 0;
274         milliseconds += args[idx++]->toInt32(exec) * msPerSecond;
275     }
276     
277     // milliseconds
278     if (idx < numArgs) {
279         milliseconds += args[idx]->toNumber(exec);
280     } else {
281         milliseconds += *ms;
282     }
283     
284     *ms = milliseconds;
285 }
286
287 // Converts a list of arguments sent to a Date member function into years, months, and milliseconds, updating
288 // ms (representing milliseconds) and t (representing the rest of the date structure) appropriately.
289 //
290 // Format of member function: f([years,] [months,] [days])
291 static void fillStructuresUsingDateArgs(ExecState *exec, const List &args, int maxArgs, double *ms, GregorianDateTime *t)
292 {
293     int idx = 0;
294     int numArgs = args.size();
295   
296     // JS allows extra trailing arguments -- ignore them
297     if (numArgs > maxArgs)
298         numArgs = maxArgs;
299   
300     // years
301     if (maxArgs >= 3 && idx < numArgs)
302         t->year = args[idx++]->toInt32(exec) - 1900;
303   
304     // months
305     if (maxArgs >= 2 && idx < numArgs)
306         t->month = args[idx++]->toInt32(exec);
307   
308     // days
309     if (idx < numArgs) {
310         t->monthDay = 0;
311         *ms += args[idx]->toInt32(exec) * msPerDay;
312     }
313 }
314
315 // ------------------------------ DateInstance ------------------------------
316
317 const ClassInfo DateInstance::info = {"Date", 0, 0};
318
319 DateInstance::DateInstance(JSObject *proto)
320   : JSWrapperObject(proto)
321 {
322 }
323
324 bool DateInstance::getTime(GregorianDateTime &t, int &offset) const
325 {
326     double milli = internalValue()->getNumber();
327     if (isnan(milli))
328         return false;
329     
330     msToGregorianDateTime(milli, false, t);
331     offset = gmtoffset(t);
332     return true;
333 }
334
335 bool DateInstance::getUTCTime(GregorianDateTime &t) const
336 {
337     double milli = internalValue()->getNumber();
338     if (isnan(milli))
339         return false;
340     
341     msToGregorianDateTime(milli, true, t);
342     return true;
343 }
344
345 bool DateInstance::getTime(double &milli, int &offset) const
346 {
347     milli = internalValue()->getNumber();
348     if (isnan(milli))
349         return false;
350     
351     GregorianDateTime t;
352     msToGregorianDateTime(milli, false, t);
353     offset = gmtoffset(t);
354     return true;
355 }
356
357 bool DateInstance::getUTCTime(double &milli) const
358 {
359     milli = internalValue()->getNumber();
360     if (isnan(milli))
361         return false;
362     
363     return true;
364 }
365
366 static inline bool isTime_tSigned()
367 {
368     time_t minusOne = (time_t)(-1);
369     return minusOne < 0;
370 }
371
372 // ------------------------------ DatePrototype -----------------------------
373
374 const ClassInfo DatePrototype::info = {"Date", &DateInstance::info, &dateTable};
375
376 /* Source for date_object.lut.h
377    FIXMEL We could use templates to simplify the UTC variants.
378 @begin dateTable 61
379   toString              &DateProtoFuncToString::create                DontEnum|Function       0
380   toUTCString           &DateProtoFuncToUTCString::create             DontEnum|Function       0
381   toDateString          &DateProtoFuncToDateString::create            DontEnum|Function       0
382   toTimeString          &DateProtoFuncToTimeString::create            DontEnum|Function       0
383   toLocaleString        &DateProtoFuncToLocaleString::create          DontEnum|Function       0
384   toLocaleDateString    &DateProtoFuncToLocaleDateString::create      DontEnum|Function       0
385   toLocaleTimeString    &DateProtoFuncToLocaleTimeString::create      DontEnum|Function       0
386   valueOf               &DateProtoFuncValueOf::create                 DontEnum|Function       0
387   getTime               &DateProtoFuncGetTime::create                 DontEnum|Function       0
388   getFullYear           &DateProtoFuncGetFullYear::create             DontEnum|Function       0
389   getUTCFullYear        &DateProtoFuncGetUTCFullYear::create          DontEnum|Function       0
390   toGMTString           &DateProtoFuncToGMTString::create             DontEnum|Function       0
391   getMonth              &DateProtoFuncGetMonth::create                DontEnum|Function       0
392   getUTCMonth           &DateProtoFuncGetUTCMonth::create             DontEnum|Function       0
393   getDate               &DateProtoFuncGetDate::create                 DontEnum|Function       0
394   getUTCDate            &DateProtoFuncGetUTCDate::create              DontEnum|Function       0
395   getDay                &DateProtoFuncGetDay::create                  DontEnum|Function       0
396   getUTCDay             &DateProtoFuncGetUTCDay::create               DontEnum|Function       0
397   getHours              &DateProtoFuncGetHours::create                DontEnum|Function       0
398   getUTCHours           &DateProtoFuncGetUTCHours::create             DontEnum|Function       0
399   getMinutes            &DateProtoFuncGetMinutes::create              DontEnum|Function       0
400   getUTCMinutes         &DateProtoFuncGetUTCMinutes::create           DontEnum|Function       0
401   getSeconds            &DateProtoFuncGetSeconds::create              DontEnum|Function       0
402   getUTCSeconds         &DateProtoFuncGetUTCSeconds::create           DontEnum|Function       0
403   getMilliseconds       &DateProtoFuncGetMilliSeconds::create         DontEnum|Function       0
404   getUTCMilliseconds    &DateProtoFuncGetUTCMilliseconds::create      DontEnum|Function       0
405   getTimezoneOffset     &DateProtoFuncGetTimezoneOffset::create       DontEnum|Function       0
406   setTime               &DateProtoFuncSetTime::create                 DontEnum|Function       1
407   setMilliseconds       &DateProtoFuncSetMilliSeconds::create         DontEnum|Function       1
408   setUTCMilliseconds    &DateProtoFuncSetUTCMilliseconds::create      DontEnum|Function       1
409   setSeconds            &DateProtoFuncSetSeconds::create              DontEnum|Function       2
410   setUTCSeconds         &DateProtoFuncSetUTCSeconds::create           DontEnum|Function       2
411   setMinutes            &DateProtoFuncSetMinutes::create              DontEnum|Function       3
412   setUTCMinutes         &DateProtoFuncSetUTCMinutes::create           DontEnum|Function       3
413   setHours              &DateProtoFuncSetHours::create                DontEnum|Function       4
414   setUTCHours           &DateProtoFuncSetUTCHours::create             DontEnum|Function       4
415   setDate               &DateProtoFuncSetDate::create                 DontEnum|Function       1
416   setUTCDate            &DateProtoFuncSetUTCDate::create              DontEnum|Function       1
417   setMonth              &DateProtoFuncSetMonth::create                DontEnum|Function       2
418   setUTCMonth           &DateProtoFuncSetUTCMonth::create             DontEnum|Function       2
419   setFullYear           &DateProtoFuncSetFullYear::create             DontEnum|Function       3
420   setUTCFullYear        &DateProtoFuncSetUTCFullYear::create          DontEnum|Function       3
421   setYear               &DateProtoFuncSetYear::create                 DontEnum|Function       1
422   getYear               &DateProtoFuncGetYear::create                 DontEnum|Function       0
423 @end
424 */
425 // ECMA 15.9.4
426
427 DatePrototype::DatePrototype(ExecState *, ObjectPrototype *objectProto)
428   : DateInstance(objectProto)
429 {
430     setInternalValue(jsNaN());
431     // The constructor will be added later, after DateObjectImp has been built.
432 }
433
434 bool DatePrototype::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
435 {
436     return getStaticFunctionSlot<JSObject>(exec, &dateTable, this, propertyName, slot);
437 }
438
439 // ------------------------------ DateObjectImp --------------------------------
440
441 // TODO: MakeTime (15.9.11.1) etc. ?
442
443 DateObjectImp::DateObjectImp(ExecState *exec,
444                              FunctionPrototype *funcProto,
445                              DatePrototype *dateProto)
446   : InternalFunctionImp(funcProto)
447 {
448   static const Identifier* parsePropertyName = new Identifier("parse");
449   static const Identifier* UTCPropertyName = new Identifier("UTC");
450
451   putDirect(exec->propertyNames().prototype, dateProto, DontEnum|DontDelete|ReadOnly);
452   putDirectFunction(new DateObjectFuncImp(exec, funcProto, DateObjectFuncImp::Parse, 1, *parsePropertyName), DontEnum);
453   putDirectFunction(new DateObjectFuncImp(exec, funcProto, DateObjectFuncImp::UTC, 7, *UTCPropertyName), DontEnum);
454   putDirect(exec->propertyNames().length, 7, ReadOnly|DontDelete|DontEnum);
455 }
456
457 bool DateObjectImp::implementsConstruct() const
458 {
459     return true;
460 }
461
462 // ECMA 15.9.3
463 JSObject *DateObjectImp::construct(ExecState *exec, const List &args)
464 {
465   int numArgs = args.size();
466
467   double value;
468
469   if (numArgs == 0) { // new Date() ECMA 15.9.3.3
470     value = getCurrentUTCTime();
471   } else if (numArgs == 1) {
472     if (args[0]->isObject(&DateInstance::info))
473       value = static_cast<DateInstance*>(args[0])->internalValue()->toNumber(exec);
474     else {
475       JSValue* primitive = args[0]->toPrimitive(exec);
476       if (primitive->isString())
477         value = parseDate(primitive->getString());
478       else
479         value = primitive->toNumber(exec);
480     }
481   } else {
482     if (isnan(args[0]->toNumber(exec))
483         || isnan(args[1]->toNumber(exec))
484         || (numArgs >= 3 && isnan(args[2]->toNumber(exec)))
485         || (numArgs >= 4 && isnan(args[3]->toNumber(exec)))
486         || (numArgs >= 5 && isnan(args[4]->toNumber(exec)))
487         || (numArgs >= 6 && isnan(args[5]->toNumber(exec)))
488         || (numArgs >= 7 && isnan(args[6]->toNumber(exec)))) {
489       value = NaN;
490     } else {
491       GregorianDateTime t;
492       int year = args[0]->toInt32(exec);
493       t.year = (year >= 0 && year <= 99) ? year : year - 1900;
494       t.month = args[1]->toInt32(exec);
495       t.monthDay = (numArgs >= 3) ? args[2]->toInt32(exec) : 1;
496       t.hour = args[3]->toInt32(exec);
497       t.minute = args[4]->toInt32(exec);
498       t.second = args[5]->toInt32(exec);
499       t.isDST = -1;
500       double ms = (numArgs >= 7) ? args[6]->toNumber(exec) : 0;
501       value = gregorianDateTimeToMS(t, ms, false);
502     }
503   }
504   
505   DateInstance *ret = new DateInstance(exec->lexicalInterpreter()->builtinDatePrototype());
506   ret->setInternalValue(jsNumber(timeClip(value)));
507   return ret;
508 }
509
510 // ECMA 15.9.2
511 JSValue *DateObjectImp::callAsFunction(ExecState * /*exec*/, JSObject * /*thisObj*/, const List &/*args*/)
512 {
513     time_t t = time(0);
514     GregorianDateTime ts(*localtime(&t));
515     return jsString(formatDate(ts) + " " + formatTime(ts, false));
516 }
517
518 // ------------------------------ DateObjectFuncImp ----------------------------
519
520 DateObjectFuncImp::DateObjectFuncImp(ExecState* exec, FunctionPrototype* funcProto, int i, int len, const Identifier& name)
521     : InternalFunctionImp(funcProto, name), id(i)
522 {
523     putDirect(exec->propertyNames().length, len, DontDelete|ReadOnly|DontEnum);
524 }
525
526 // ECMA 15.9.4.2 - 3
527 JSValue *DateObjectFuncImp::callAsFunction(ExecState* exec, JSObject*, const List& args)
528 {
529   if (id == Parse) {
530     return jsNumber(parseDate(args[0]->toString(exec)));
531   }
532   else { // UTC
533     int n = args.size();
534     if (isnan(args[0]->toNumber(exec))
535         || isnan(args[1]->toNumber(exec))
536         || (n >= 3 && isnan(args[2]->toNumber(exec)))
537         || (n >= 4 && isnan(args[3]->toNumber(exec)))
538         || (n >= 5 && isnan(args[4]->toNumber(exec)))
539         || (n >= 6 && isnan(args[5]->toNumber(exec)))
540         || (n >= 7 && isnan(args[6]->toNumber(exec)))) {
541       return jsNaN();
542     }
543
544     GregorianDateTime t;
545     memset(&t, 0, sizeof(t));
546     int year = args[0]->toInt32(exec);
547     t.year = (year >= 0 && year <= 99) ? year : year - 1900;
548     t.month = args[1]->toInt32(exec);
549     t.monthDay = (n >= 3) ? args[2]->toInt32(exec) : 1;
550     t.hour = args[3]->toInt32(exec);
551     t.minute = args[4]->toInt32(exec);
552     t.second = args[5]->toInt32(exec);
553     double ms = (n >= 7) ? args[6]->toNumber(exec) : 0;
554     return jsNumber(gregorianDateTimeToMS(t, ms, true));
555   }
556 }
557
558 // -----------------------------------------------------------------------------
559
560 // Code originally from krfcdate.cpp, but we don't want to use kdecore, and we want double range.
561
562 static inline double ymdhmsToSeconds(long year, int mon, int day, int hour, int minute, int second)
563 {
564     double days = (day - 32075)
565         + floor(1461 * (year + 4800.0 + (mon - 14) / 12) / 4)
566         + 367 * (mon - 2 - (mon - 14) / 12 * 12) / 12
567         - floor(3 * ((year + 4900.0 + (mon - 14) / 12) / 100) / 4)
568         - 2440588;
569     return ((days * hoursPerDay + hour) * minutesPerHour + minute) * secondsPerMinute + second;
570 }
571
572 // We follow the recommendation of RFC 2822 to consider all
573 // obsolete time zones not listed here equivalent to "-0000".
574 static const struct KnownZone {
575 #if !PLATFORM(WIN_OS)
576     const
577 #endif
578         char tzName[4];
579     int tzOffset;
580 } known_zones[] = {
581     { "UT", 0 },
582     { "GMT", 0 },
583     { "EST", -300 },
584     { "EDT", -240 },
585     { "CST", -360 },
586     { "CDT", -300 },
587     { "MST", -420 },
588     { "MDT", -360 },
589     { "PST", -480 },
590     { "PDT", -420 }
591 };
592
593 inline static void skipSpacesAndComments(const char*& s)
594 {
595     int nesting = 0;
596     char ch;
597     while ((ch = *s)) {
598         if (!isASCIISpace(ch)) {
599             if (ch == '(')
600                 nesting++;
601             else if (ch == ')' && nesting > 0)
602                 nesting--;
603             else if (nesting == 0)
604                 break;
605         }
606         s++;
607     }
608 }
609
610 // returns 0-11 (Jan-Dec); -1 on failure
611 static int findMonth(const char* monthStr)
612 {
613     ASSERT(monthStr);
614     char needle[4];
615     for (int i = 0; i < 3; ++i) {
616         if (!*monthStr)
617             return -1;
618         needle[i] = static_cast<char>(toASCIILower(*monthStr++));
619     }
620     needle[3] = '\0';
621     const char *haystack = "janfebmaraprmayjunjulaugsepoctnovdec";
622     const char *str = strstr(haystack, needle);
623     if (str) {
624         int position = static_cast<int>(str - haystack);
625         if (position % 3 == 0)
626             return position / 3;
627     }
628     return -1;
629 }
630
631 static double parseDate(const UString &date)
632 {
633     // This parses a date in the form:
634     //     Tuesday, 09-Nov-99 23:12:40 GMT
635     // or
636     //     Sat, 01-Jan-2000 08:00:00 GMT
637     // or
638     //     Sat, 01 Jan 2000 08:00:00 GMT
639     // or
640     //     01 Jan 99 22:00 +0100    (exceptions in rfc822/rfc2822)
641     // ### non RFC formats, added for Javascript:
642     //     [Wednesday] January 09 1999 23:12:40 GMT
643     //     [Wednesday] January 09 23:12:40 GMT 1999
644     //
645     // We ignore the weekday.
646
647     CString dateCString = date.UTF8String();
648     const char *dateString = dateCString.c_str();
649      
650     // Skip leading space
651     skipSpacesAndComments(dateString);
652
653     long month = -1;
654     const char *wordStart = dateString;
655     // Check contents of first words if not number
656     while (*dateString && !isASCIIDigit(*dateString)) {
657         if (isASCIISpace(*dateString) || *dateString == '(') {
658             if (dateString - wordStart >= 3)
659                 month = findMonth(wordStart);
660             skipSpacesAndComments(dateString);
661             wordStart = dateString;
662         } else
663            dateString++;
664     }
665
666     // Missing delimiter between month and day (like "January29")?
667     if (month == -1 && wordStart != dateString)
668         month = findMonth(wordStart);
669
670     skipSpacesAndComments(dateString);
671
672     if (!*dateString)
673         return NaN;
674
675     // ' 09-Nov-99 23:12:40 GMT'
676     char *newPosStr;
677     errno = 0;
678     long day = strtol(dateString, &newPosStr, 10);
679     if (errno)
680         return NaN;
681     dateString = newPosStr;
682
683     if (!*dateString)
684         return NaN;
685
686     if (day < 0)
687         return NaN;
688
689     long year = 0;
690     if (day > 31) {
691         // ### where is the boundary and what happens below?
692         if (*dateString != '/')
693             return NaN;
694         // looks like a YYYY/MM/DD date
695         if (!*++dateString)
696             return NaN;
697         year = day;
698         month = strtol(dateString, &newPosStr, 10) - 1;
699         if (errno)
700             return NaN;
701         dateString = newPosStr;
702         if (*dateString++ != '/' || !*dateString)
703             return NaN;
704         day = strtol(dateString, &newPosStr, 10);
705         if (errno)
706             return NaN;
707         dateString = newPosStr;
708     } else if (*dateString == '/' && month == -1) {
709         dateString++;
710         // This looks like a MM/DD/YYYY date, not an RFC date.
711         month = day - 1; // 0-based
712         day = strtol(dateString, &newPosStr, 10);
713         if (errno)
714             return NaN;
715         if (day < 1 || day > 31)
716             return NaN;
717         dateString = newPosStr;
718         if (*dateString == '/')
719             dateString++;
720         if (!*dateString)
721             return NaN;
722      } else {
723         if (*dateString == '-')
724             dateString++;
725
726         skipSpacesAndComments(dateString);
727
728         if (*dateString == ',')
729             dateString++;
730
731         if (month == -1) { // not found yet
732             month = findMonth(dateString);
733             if (month == -1)
734                 return NaN;
735
736             while (*dateString && *dateString != '-' && *dateString != ',' && !isASCIISpace(*dateString))
737                 dateString++;
738
739             if (!*dateString)
740                 return NaN;
741
742             // '-99 23:12:40 GMT'
743             if (*dateString != '-' && *dateString != '/' && *dateString != ',' && !isASCIISpace(*dateString))
744                 return NaN;
745             dateString++;
746         }
747     }
748
749     if (month < 0 || month > 11)
750         return NaN;
751
752     // '99 23:12:40 GMT'
753     if (year <= 0 && *dateString) {
754         year = strtol(dateString, &newPosStr, 10);
755         if (errno)
756             return NaN;
757     }
758     
759     // Don't fail if the time is missing.
760     long hour = 0;
761     long minute = 0;
762     long second = 0;
763     if (!*newPosStr)
764         dateString = newPosStr;
765     else {
766         // ' 23:12:40 GMT'
767         if (!(isASCIISpace(*newPosStr) || *newPosStr == ',')) {
768             if (*newPosStr != ':')
769                 return NaN;
770             // There was no year; the number was the hour.
771             year = -1;
772         } else {
773             // in the normal case (we parsed the year), advance to the next number
774             dateString = ++newPosStr;
775             skipSpacesAndComments(dateString);
776         }
777
778         hour = strtol(dateString, &newPosStr, 10);
779         // Do not check for errno here since we want to continue
780         // even if errno was set becasue we are still looking
781         // for the timezone!
782
783         // Read a number? If not, this might be a timezone name.
784         if (newPosStr != dateString) {
785             dateString = newPosStr;
786
787             if (hour < 0 || hour > 23)
788                 return NaN;
789
790             if (!*dateString)
791                 return NaN;
792
793             // ':12:40 GMT'
794             if (*dateString++ != ':')
795                 return NaN;
796
797             minute = strtol(dateString, &newPosStr, 10);
798             if (errno)
799                 return NaN;
800             dateString = newPosStr;
801
802             if (minute < 0 || minute > 59)
803                 return NaN;
804
805             // ':40 GMT'
806             if (*dateString && *dateString != ':' && !isASCIISpace(*dateString))
807                 return NaN;
808
809             // seconds are optional in rfc822 + rfc2822
810             if (*dateString ==':') {
811                 dateString++;
812
813                 second = strtol(dateString, &newPosStr, 10);
814                 if (errno)
815                     return NaN;
816                 dateString = newPosStr;
817             
818                 if (second < 0 || second > 59)
819                     return NaN;
820             }
821
822             skipSpacesAndComments(dateString);
823
824             if (strncasecmp(dateString, "AM", 2) == 0) {
825                 if (hour > 12)
826                     return NaN;
827                 if (hour == 12)
828                     hour = 0;
829                 dateString += 2;
830                 skipSpacesAndComments(dateString);
831             } else if (strncasecmp(dateString, "PM", 2) == 0) {
832                 if (hour > 12)
833                     return NaN;
834                 if (hour != 12)
835                     hour += 12;
836                 dateString += 2;
837                 skipSpacesAndComments(dateString);
838             }
839         }
840     }
841
842     bool haveTZ = false;
843     int offset = 0;
844
845     // Don't fail if the time zone is missing. 
846     // Some websites omit the time zone (4275206).
847     if (*dateString) {
848         if (strncasecmp(dateString, "GMT", 3) == 0 || strncasecmp(dateString, "UTC", 3) == 0) {
849             dateString += 3;
850             haveTZ = true;
851         }
852
853         if (*dateString == '+' || *dateString == '-') {
854             long o = strtol(dateString, &newPosStr, 10);
855             if (errno)
856                 return NaN;
857             dateString = newPosStr;
858
859             if (o < -9959 || o > 9959)
860                 return NaN;
861
862             int sgn = (o < 0) ? -1 : 1;
863             o = abs(o);
864             if (*dateString != ':') {
865                 offset = ((o / 100) * 60 + (o % 100)) * sgn;
866             } else { // GMT+05:00
867                 long o2 = strtol(dateString, &newPosStr, 10);
868                 if (errno)
869                     return NaN;
870                 dateString = newPosStr;
871                 offset = (o * 60 + o2) * sgn;
872             }
873             haveTZ = true;
874         } else {
875             for (int i = 0; i < int(sizeof(known_zones) / sizeof(KnownZone)); i++) {
876                 if (0 == strncasecmp(dateString, known_zones[i].tzName, strlen(known_zones[i].tzName))) {
877                     offset = known_zones[i].tzOffset;
878                     dateString += strlen(known_zones[i].tzName);
879                     haveTZ = true;
880                     break;
881                 }
882             }
883         }
884     }
885
886     skipSpacesAndComments(dateString);
887
888     if (*dateString && year == -1) {
889         year = strtol(dateString, &newPosStr, 10);
890         if (errno)
891             return NaN;
892         dateString = newPosStr;
893     }
894      
895     skipSpacesAndComments(dateString);
896      
897     // Trailing garbage
898     if (*dateString)
899         return NaN;
900
901     // Y2K: Handle 2 digit years.
902     if (year >= 0 && year < 100) {
903         if (year < 50)
904             year += 2000;
905         else
906             year += 1900;
907     }
908
909     // fall back to local timezone
910     if (!haveTZ) {
911         GregorianDateTime t;
912         memset(&t, 0, sizeof(tm));
913         t.monthDay = day;
914         t.month = month;
915         t.year = year - 1900;
916         t.isDST = -1;
917         t.second = second;
918         t.minute = minute;
919         t.hour = hour;
920
921         // Use our gregorianDateTimeToMS() rather than mktime() as the latter can't handle the full year range.
922         return gregorianDateTimeToMS(t, 0, false);
923     }
924
925     return (ymdhmsToSeconds(year, month + 1, day, hour, minute, second) - (offset * 60.0)) * msPerSecond;
926 }
927
928 double timeClip(double t)
929 {
930     if (!isfinite(t))
931         return NaN;
932     if (fabs(t) > 8.64E15)
933         return NaN;
934     return trunc(t);
935 }
936
937 // Functions
938
939 JSValue* DateProtoFuncToString::callAsFunction(ExecState* exec, JSObject* thisObj, const List&)
940 {
941     if (!thisObj->inherits(&DateInstance::info))
942         return throwError(exec, TypeError);
943
944     const bool utc = false;
945
946     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
947     JSValue* v = thisDateObj->internalValue();
948     double milli = v->toNumber(exec);
949     if (isnan(milli))
950         return jsString("Invalid Date");
951
952     GregorianDateTime t;
953     msToGregorianDateTime(milli, utc, t);
954     return jsString(formatDate(t) + " " + formatTime(t, utc));
955 }
956
957 JSValue* DateProtoFuncToUTCString::callAsFunction(ExecState* exec, JSObject* thisObj, const List&)
958 {
959     if (!thisObj->inherits(&DateInstance::info))
960         return throwError(exec, TypeError);
961
962     const bool utc = true;
963
964     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
965     JSValue* v = thisDateObj->internalValue();
966     double milli = v->toNumber(exec);
967     if (isnan(milli))
968         return jsString("Invalid Date");
969
970     GregorianDateTime t;
971     msToGregorianDateTime(milli, utc, t);
972     return jsString(formatDateUTCVariant(t) + " " + formatTime(t, utc));
973 }
974
975 JSValue* DateProtoFuncToDateString::callAsFunction(ExecState* exec, JSObject* thisObj, const List&)
976 {
977     if (!thisObj->inherits(&DateInstance::info))
978         return throwError(exec, TypeError);
979
980     const bool utc = false;
981
982     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
983     JSValue* v = thisDateObj->internalValue();
984     double milli = v->toNumber(exec);
985     if (isnan(milli))
986         return jsString("Invalid Date");
987
988     GregorianDateTime t;
989     msToGregorianDateTime(milli, utc, t);
990     return jsString(formatDate(t));
991 }
992
993 JSValue* DateProtoFuncToTimeString::callAsFunction(ExecState* exec, JSObject* thisObj, const List&)
994 {
995     if (!thisObj->inherits(&DateInstance::info))
996         return throwError(exec, TypeError);
997
998     const bool utc = false;
999
1000     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1001     JSValue* v = thisDateObj->internalValue();
1002     double milli = v->toNumber(exec);
1003     if (isnan(milli))
1004         return jsString("Invalid Date");
1005
1006     GregorianDateTime t;
1007     msToGregorianDateTime(milli, utc, t);
1008     return jsString(formatTime(t, utc));
1009 }
1010
1011 JSValue* DateProtoFuncToLocaleString::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1012 {
1013     if (!thisObj->inherits(&DateInstance::info))
1014         return throwError(exec, TypeError);
1015
1016     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1017     JSValue* v = thisDateObj->internalValue();
1018     double milli = v->toNumber(exec);
1019     if (isnan(milli))
1020         return jsString("Invalid Date");
1021
1022 #if PLATFORM(MAC)
1023     double secs = floor(milli / msPerSecond);
1024     return jsString(formatLocaleDate(exec, secs, true, true, args));
1025 #else
1026     UNUSED_PARAM(args);
1027
1028     const bool utc = false;
1029
1030     GregorianDateTime t;
1031     msToGregorianDateTime(milli, utc, t);
1032     return formatLocaleDate(t, LocaleDateAndTime);
1033 #endif
1034 }
1035
1036 JSValue* DateProtoFuncToLocaleDateString::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1037 {
1038     if (!thisObj->inherits(&DateInstance::info))
1039         return throwError(exec, TypeError);
1040
1041     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1042     JSValue* v = thisDateObj->internalValue();
1043     double milli = v->toNumber(exec);
1044     if (isnan(milli))
1045         return jsString("Invalid Date");
1046
1047 #if PLATFORM(MAC)
1048     double secs = floor(milli / msPerSecond);
1049     return jsString(formatLocaleDate(exec, secs, true, false, args));
1050 #else
1051     UNUSED_PARAM(args);
1052
1053     const bool utc = false;
1054
1055     GregorianDateTime t;
1056     msToGregorianDateTime(milli, utc, t);
1057     return formatLocaleDate(t, LocaleDate);
1058 #endif
1059 }
1060
1061 JSValue* DateProtoFuncToLocaleTimeString::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1062 {
1063     if (!thisObj->inherits(&DateInstance::info))
1064         return throwError(exec, TypeError);
1065
1066     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1067     JSValue* v = thisDateObj->internalValue();
1068     double milli = v->toNumber(exec);
1069     if (isnan(milli))
1070         return jsString("Invalid Date");
1071
1072 #if PLATFORM(MAC)
1073     double secs = floor(milli / msPerSecond);
1074     return jsString(formatLocaleDate(exec, secs, false, true, args));
1075 #else
1076     UNUSED_PARAM(args);
1077
1078     const bool utc = false;
1079
1080     GregorianDateTime t;
1081     msToGregorianDateTime(milli, utc, t);
1082     return formatLocaleDate(t, LocaleTime);
1083 #endif
1084 }
1085
1086 JSValue* DateProtoFuncValueOf::callAsFunction(ExecState* exec, JSObject* thisObj, const List&)
1087 {
1088     if (!thisObj->inherits(&DateInstance::info))
1089         return throwError(exec, TypeError);
1090
1091     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1092     JSValue* v = thisDateObj->internalValue();
1093     double milli = v->toNumber(exec);
1094     if (isnan(milli))
1095         return jsNaN();
1096
1097     return jsNumber(milli);
1098 }
1099
1100 JSValue* DateProtoFuncGetTime::callAsFunction(ExecState* exec, JSObject* thisObj, const List&)
1101 {
1102     if (!thisObj->inherits(&DateInstance::info))
1103         return throwError(exec, TypeError);
1104
1105     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1106     JSValue* v = thisDateObj->internalValue();
1107     double milli = v->toNumber(exec);
1108     if (isnan(milli))
1109         return jsNaN();
1110
1111     return jsNumber(milli);
1112 }
1113
1114 JSValue* DateProtoFuncGetFullYear::callAsFunction(ExecState* exec, JSObject* thisObj, const List&)
1115 {
1116     if (!thisObj->inherits(&DateInstance::info))
1117         return throwError(exec, TypeError);
1118
1119     const bool utc = false;
1120
1121     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1122     JSValue* v = thisDateObj->internalValue();
1123     double milli = v->toNumber(exec);
1124     if (isnan(milli))
1125         return jsNaN();
1126
1127     GregorianDateTime t;
1128     msToGregorianDateTime(milli, utc, t);
1129     return jsNumber(1900 + t.year);
1130 }
1131
1132 JSValue* DateProtoFuncGetUTCFullYear::callAsFunction(ExecState* exec, JSObject* thisObj, const List&)
1133 {
1134     if (!thisObj->inherits(&DateInstance::info))
1135         return throwError(exec, TypeError);
1136
1137     const bool utc = true;
1138
1139     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1140     JSValue* v = thisDateObj->internalValue();
1141     double milli = v->toNumber(exec);
1142     if (isnan(milli))
1143         return jsNaN();
1144
1145     GregorianDateTime t;
1146     msToGregorianDateTime(milli, utc, t);
1147     return jsNumber(1900 + t.year);
1148 }
1149
1150 JSValue* DateProtoFuncToGMTString::callAsFunction(ExecState* exec, JSObject* thisObj, const List&)
1151 {
1152     if (!thisObj->inherits(&DateInstance::info))
1153         return throwError(exec, TypeError);
1154
1155     const bool utc = true;
1156
1157     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1158     JSValue* v = thisDateObj->internalValue();
1159     double milli = v->toNumber(exec);
1160     if (isnan(milli))
1161         return jsString("Invalid Date");
1162
1163     GregorianDateTime t;
1164     msToGregorianDateTime(milli, utc, t);
1165     return jsString(formatDateUTCVariant(t) + " " + formatTime(t, utc));
1166 }
1167
1168 JSValue* DateProtoFuncGetMonth::callAsFunction(ExecState* exec, JSObject* thisObj, const List&)
1169 {
1170     if (!thisObj->inherits(&DateInstance::info))
1171         return throwError(exec, TypeError);
1172
1173     const bool utc = false;
1174
1175     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1176     JSValue* v = thisDateObj->internalValue();
1177     double milli = v->toNumber(exec);
1178     if (isnan(milli))
1179         return jsNaN();
1180
1181     GregorianDateTime t;
1182     msToGregorianDateTime(milli, utc, t);
1183     return jsNumber(t.month);
1184 }
1185
1186 JSValue* DateProtoFuncGetUTCMonth::callAsFunction(ExecState* exec, JSObject* thisObj, const List&)
1187 {
1188     if (!thisObj->inherits(&DateInstance::info))
1189         return throwError(exec, TypeError);
1190
1191     const bool utc = true;
1192
1193     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1194     JSValue* v = thisDateObj->internalValue();
1195     double milli = v->toNumber(exec);
1196     if (isnan(milli))
1197         return jsNaN();
1198
1199     GregorianDateTime t;
1200     msToGregorianDateTime(milli, utc, t);
1201     return jsNumber(t.month);
1202 }
1203
1204 JSValue* DateProtoFuncGetDate::callAsFunction(ExecState* exec, JSObject* thisObj, const List&)
1205 {
1206     if (!thisObj->inherits(&DateInstance::info))
1207         return throwError(exec, TypeError);
1208
1209     const bool utc = false;
1210
1211     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1212     JSValue* v = thisDateObj->internalValue();
1213     double milli = v->toNumber(exec);
1214     if (isnan(milli))
1215         return jsNaN();
1216
1217     GregorianDateTime t;
1218     msToGregorianDateTime(milli, utc, t);
1219     return jsNumber(t.monthDay);
1220 }
1221
1222 JSValue* DateProtoFuncGetUTCDate::callAsFunction(ExecState* exec, JSObject* thisObj, const List&)
1223 {
1224     if (!thisObj->inherits(&DateInstance::info))
1225         return throwError(exec, TypeError);
1226
1227     const bool utc = true;
1228
1229     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1230     JSValue* v = thisDateObj->internalValue();
1231     double milli = v->toNumber(exec);
1232     if (isnan(milli))
1233         return jsNaN();
1234
1235     GregorianDateTime t;
1236     msToGregorianDateTime(milli, utc, t);
1237     return jsNumber(t.monthDay);
1238 }
1239
1240 JSValue* DateProtoFuncGetDay::callAsFunction(ExecState* exec, JSObject* thisObj, const List&)
1241 {
1242     if (!thisObj->inherits(&DateInstance::info))
1243         return throwError(exec, TypeError);
1244
1245     const bool utc = false;
1246
1247     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1248     JSValue* v = thisDateObj->internalValue();
1249     double milli = v->toNumber(exec);
1250     if (isnan(milli))
1251         return jsNaN();
1252
1253     GregorianDateTime t;
1254     msToGregorianDateTime(milli, utc, t);
1255     return jsNumber(t.weekDay);
1256 }
1257
1258 JSValue* DateProtoFuncGetUTCDay::callAsFunction(ExecState* exec, JSObject* thisObj, const List&)
1259 {
1260     if (!thisObj->inherits(&DateInstance::info))
1261         return throwError(exec, TypeError);
1262
1263     const bool utc = true;
1264
1265     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1266     JSValue* v = thisDateObj->internalValue();
1267     double milli = v->toNumber(exec);
1268     if (isnan(milli))
1269         return jsNaN();
1270
1271     GregorianDateTime t;
1272     msToGregorianDateTime(milli, utc, t);
1273     return jsNumber(t.weekDay);
1274 }
1275
1276 JSValue* DateProtoFuncGetHours::callAsFunction(ExecState* exec, JSObject* thisObj, const List&)
1277 {
1278     if (!thisObj->inherits(&DateInstance::info))
1279         return throwError(exec, TypeError);
1280
1281     const bool utc = false;
1282
1283     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1284     JSValue* v = thisDateObj->internalValue();
1285     double milli = v->toNumber(exec);
1286     if (isnan(milli))
1287         return jsNaN();
1288
1289     GregorianDateTime t;
1290     msToGregorianDateTime(milli, utc, t);
1291     return jsNumber(t.hour);
1292 }
1293
1294 JSValue* DateProtoFuncGetUTCHours::callAsFunction(ExecState* exec, JSObject* thisObj, const List&)
1295 {
1296     if (!thisObj->inherits(&DateInstance::info))
1297         return throwError(exec, TypeError);
1298
1299     const bool utc = true;
1300
1301     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1302     JSValue* v = thisDateObj->internalValue();
1303     double milli = v->toNumber(exec);
1304     if (isnan(milli))
1305         return jsNaN();
1306
1307     GregorianDateTime t;
1308     msToGregorianDateTime(milli, utc, t);
1309     return jsNumber(t.hour);
1310 }
1311
1312 JSValue* DateProtoFuncGetMinutes::callAsFunction(ExecState* exec, JSObject* thisObj, const List&)
1313 {
1314     if (!thisObj->inherits(&DateInstance::info))
1315         return throwError(exec, TypeError);
1316
1317     const bool utc = false;
1318
1319     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1320     JSValue* v = thisDateObj->internalValue();
1321     double milli = v->toNumber(exec);
1322     if (isnan(milli))
1323         return jsNaN();
1324
1325     GregorianDateTime t;
1326     msToGregorianDateTime(milli, utc, t);
1327     return jsNumber(t.minute);
1328 }
1329
1330 JSValue* DateProtoFuncGetUTCMinutes::callAsFunction(ExecState* exec, JSObject* thisObj, const List&)
1331 {
1332     if (!thisObj->inherits(&DateInstance::info))
1333         return throwError(exec, TypeError);
1334
1335     const bool utc = true;
1336
1337     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1338     JSValue* v = thisDateObj->internalValue();
1339     double milli = v->toNumber(exec);
1340     if (isnan(milli))
1341         return jsNaN();
1342
1343     GregorianDateTime t;
1344     msToGregorianDateTime(milli, utc, t);
1345     return jsNumber(t.minute);
1346 }
1347
1348 JSValue* DateProtoFuncGetSeconds::callAsFunction(ExecState* exec, JSObject* thisObj, const List&)
1349 {
1350     if (!thisObj->inherits(&DateInstance::info))
1351         return throwError(exec, TypeError);
1352
1353     const bool utc = false;
1354
1355     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1356     JSValue* v = thisDateObj->internalValue();
1357     double milli = v->toNumber(exec);
1358     if (isnan(milli))
1359         return jsNaN();
1360
1361     GregorianDateTime t;
1362     msToGregorianDateTime(milli, utc, t);
1363     return jsNumber(t.second);
1364 }
1365
1366 JSValue* DateProtoFuncGetUTCSeconds::callAsFunction(ExecState* exec, JSObject* thisObj, const List&)
1367 {
1368     if (!thisObj->inherits(&DateInstance::info))
1369         return throwError(exec, TypeError);
1370
1371     const bool utc = true;
1372
1373     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1374     JSValue* v = thisDateObj->internalValue();
1375     double milli = v->toNumber(exec);
1376     if (isnan(milli))
1377         return jsNaN();
1378
1379     GregorianDateTime t;
1380     msToGregorianDateTime(milli, utc, t);
1381     return jsNumber(t.second);
1382 }
1383
1384 JSValue* DateProtoFuncGetMilliSeconds::callAsFunction(ExecState* exec, JSObject* thisObj, const List&)
1385 {
1386     if (!thisObj->inherits(&DateInstance::info))
1387         return throwError(exec, TypeError);
1388
1389     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1390     JSValue* v = thisDateObj->internalValue();
1391     double milli = v->toNumber(exec);
1392     if (isnan(milli))
1393         return jsNaN();
1394
1395     double secs = floor(milli / msPerSecond);
1396     double ms = milli - secs * msPerSecond;
1397     return jsNumber(ms);
1398 }
1399
1400 JSValue* DateProtoFuncGetUTCMilliseconds::callAsFunction(ExecState* exec, JSObject* thisObj, const List&)
1401 {
1402     if (!thisObj->inherits(&DateInstance::info))
1403         return throwError(exec, TypeError);
1404
1405     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1406     JSValue* v = thisDateObj->internalValue();
1407     double milli = v->toNumber(exec);
1408     if (isnan(milli))
1409         return jsNaN();
1410
1411     double secs = floor(milli / msPerSecond);
1412     double ms = milli - secs * msPerSecond;
1413     return jsNumber(ms);
1414 }
1415
1416 JSValue* DateProtoFuncGetTimezoneOffset::callAsFunction(ExecState* exec, JSObject* thisObj, const List&)
1417 {
1418     if (!thisObj->inherits(&DateInstance::info))
1419         return throwError(exec, TypeError);
1420
1421     const bool utc = false;
1422
1423     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1424     JSValue* v = thisDateObj->internalValue();
1425     double milli = v->toNumber(exec);
1426     if (isnan(milli))
1427         return jsNaN();
1428
1429     GregorianDateTime t;
1430     msToGregorianDateTime(milli, utc, t);
1431     return jsNumber(-gmtoffset(t) / minutesPerHour);
1432 }
1433
1434 JSValue* DateProtoFuncSetTime::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1435 {
1436     if (!thisObj->inherits(&DateInstance::info))
1437         return throwError(exec, TypeError);
1438
1439     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1440
1441     double milli = timeClip(args[0]->toNumber(exec));
1442     JSValue* result = jsNumber(milli);
1443     thisDateObj->setInternalValue(result);
1444     return result;
1445 }
1446
1447 JSValue* DateProtoFuncSetMilliSeconds::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1448 {
1449     if (!thisObj->inherits(&DateInstance::info))
1450         return throwError(exec, TypeError);
1451
1452     const bool utc = false;
1453
1454     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1455     JSValue* v = thisDateObj->internalValue();
1456     double milli = v->toNumber(exec);
1457     double secs = floor(milli / msPerSecond);
1458     double ms = milli - secs * msPerSecond;
1459
1460     GregorianDateTime t;
1461     msToGregorianDateTime(milli, utc, t);
1462
1463     fillStructuresUsingTimeArgs(exec, args, 1, &ms, &t);
1464
1465     JSValue* result = jsNumber(gregorianDateTimeToMS(t, ms, utc));
1466     thisDateObj->setInternalValue(result);
1467     return result;
1468 }
1469
1470 JSValue* DateProtoFuncSetUTCMilliseconds::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1471 {
1472     if (!thisObj->inherits(&DateInstance::info))
1473         return throwError(exec, TypeError);
1474
1475     const bool utc = true;
1476
1477     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1478     JSValue* v = thisDateObj->internalValue();
1479     double milli = v->toNumber(exec);
1480     double secs = floor(milli / msPerSecond);
1481     double ms = milli - secs * msPerSecond;
1482
1483     GregorianDateTime t;
1484     msToGregorianDateTime(milli, utc, t);
1485
1486     fillStructuresUsingTimeArgs(exec, args, 1, &ms, &t);
1487
1488     JSValue* result = jsNumber(gregorianDateTimeToMS(t, ms, utc));
1489     thisDateObj->setInternalValue(result);
1490     return result;
1491 }
1492
1493 JSValue* DateProtoFuncSetSeconds::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1494 {
1495     if (!thisObj->inherits(&DateInstance::info))
1496         return throwError(exec, TypeError);
1497
1498     const bool utc = false;
1499
1500     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1501     JSValue* v = thisDateObj->internalValue();
1502     double milli = v->toNumber(exec);
1503     double secs = floor(milli / msPerSecond);
1504     double ms = milli - secs * msPerSecond;
1505
1506     GregorianDateTime t;
1507     msToGregorianDateTime(milli, utc, t);
1508
1509     fillStructuresUsingTimeArgs(exec, args, 2, &ms, &t);
1510
1511     JSValue* result = jsNumber(gregorianDateTimeToMS(t, ms, utc));
1512     thisDateObj->setInternalValue(result);
1513     return result;
1514 }
1515
1516 JSValue* DateProtoFuncSetUTCSeconds::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1517 {
1518     if (!thisObj->inherits(&DateInstance::info))
1519         return throwError(exec, TypeError);
1520
1521     const bool utc = true;
1522
1523     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1524     JSValue* v = thisDateObj->internalValue();
1525     double milli = v->toNumber(exec);
1526     double secs = floor(milli / msPerSecond);
1527     double ms = milli - secs * msPerSecond;
1528
1529     GregorianDateTime t;
1530     msToGregorianDateTime(milli, utc, t);
1531
1532     fillStructuresUsingTimeArgs(exec, args, 2, &ms, &t);
1533
1534     JSValue* result = jsNumber(gregorianDateTimeToMS(t, ms, utc));
1535     thisDateObj->setInternalValue(result);
1536     return result;
1537 }
1538
1539 JSValue* DateProtoFuncSetMinutes::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1540 {
1541     if (!thisObj->inherits(&DateInstance::info))
1542         return throwError(exec, TypeError);
1543
1544     const bool utc = false;
1545
1546     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1547     JSValue* v = thisDateObj->internalValue();
1548     double milli = v->toNumber(exec);
1549     double secs = floor(milli / msPerSecond);
1550     double ms = milli - secs * msPerSecond;
1551
1552     GregorianDateTime t;
1553     msToGregorianDateTime(milli, utc, t);
1554
1555     fillStructuresUsingTimeArgs(exec, args, 3, &ms, &t);
1556
1557     JSValue* result = jsNumber(gregorianDateTimeToMS(t, ms, utc));
1558     thisDateObj->setInternalValue(result);
1559     return result;
1560 }
1561
1562 JSValue* DateProtoFuncSetUTCMinutes::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1563 {
1564     if (!thisObj->inherits(&DateInstance::info))
1565         return throwError(exec, TypeError);
1566
1567     const bool utc = true;
1568
1569     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1570     JSValue* v = thisDateObj->internalValue();
1571     double milli = v->toNumber(exec);
1572     double secs = floor(milli / msPerSecond);
1573     double ms = milli - secs * msPerSecond;
1574
1575     GregorianDateTime t;
1576     msToGregorianDateTime(milli, utc, t);
1577
1578     fillStructuresUsingTimeArgs(exec, args, 3, &ms, &t);
1579
1580     JSValue* result = jsNumber(gregorianDateTimeToMS(t, ms, utc));
1581     thisDateObj->setInternalValue(result);
1582     return result;
1583 }
1584
1585 JSValue* DateProtoFuncSetHours::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1586 {
1587     if (!thisObj->inherits(&DateInstance::info))
1588         return throwError(exec, TypeError);
1589
1590     const bool utc = false;
1591
1592     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1593     JSValue* v = thisDateObj->internalValue();
1594     double milli = v->toNumber(exec);
1595     double secs = floor(milli / msPerSecond);
1596     double ms = milli - secs * msPerSecond;
1597
1598     GregorianDateTime t;
1599     msToGregorianDateTime(milli, utc, t);
1600
1601     fillStructuresUsingTimeArgs(exec, args, 4, &ms, &t);
1602
1603     JSValue* result = jsNumber(gregorianDateTimeToMS(t, ms, utc));
1604     thisDateObj->setInternalValue(result);
1605     return result;
1606 }
1607
1608 JSValue* DateProtoFuncSetUTCHours::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1609 {
1610     if (!thisObj->inherits(&DateInstance::info))
1611         return throwError(exec, TypeError);
1612
1613     const bool utc = true;
1614
1615     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1616     JSValue* v = thisDateObj->internalValue();
1617     double milli = v->toNumber(exec);
1618     double secs = floor(milli / msPerSecond);
1619     double ms = milli - secs * msPerSecond;
1620
1621     GregorianDateTime t;
1622     msToGregorianDateTime(milli, utc, t);
1623
1624     fillStructuresUsingTimeArgs(exec, args, 4, &ms, &t);
1625
1626     JSValue* result = jsNumber(gregorianDateTimeToMS(t, ms, utc));
1627     thisDateObj->setInternalValue(result);
1628     return result;
1629 }
1630
1631 JSValue* DateProtoFuncSetDate::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1632 {
1633     if (!thisObj->inherits(&DateInstance::info))
1634         return throwError(exec, TypeError);
1635
1636     const bool utc = false;
1637
1638     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1639     JSValue* v = thisDateObj->internalValue();
1640     double milli = v->toNumber(exec);
1641     double secs = floor(milli / msPerSecond);
1642     double ms = milli - secs * msPerSecond;
1643
1644     GregorianDateTime t;
1645     msToGregorianDateTime(milli, utc, t);
1646
1647     fillStructuresUsingDateArgs(exec, args, 1, &ms, &t);
1648
1649     JSValue* result = jsNumber(gregorianDateTimeToMS(t, ms, utc));
1650     thisDateObj->setInternalValue(result);
1651     return result;
1652 }
1653
1654 JSValue* DateProtoFuncSetUTCDate::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1655 {
1656     if (!thisObj->inherits(&DateInstance::info))
1657         return throwError(exec, TypeError);
1658
1659     const bool utc = true;
1660
1661     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1662     JSValue* v = thisDateObj->internalValue();
1663     double milli = v->toNumber(exec);
1664     double secs = floor(milli / msPerSecond);
1665     double ms = milli - secs * msPerSecond;
1666
1667     GregorianDateTime t;
1668     msToGregorianDateTime(milli, utc, t);
1669
1670     fillStructuresUsingDateArgs(exec, args, 1, &ms, &t);
1671
1672     JSValue* result = jsNumber(gregorianDateTimeToMS(t, ms, utc));
1673     thisDateObj->setInternalValue(result);
1674     return result;
1675 }
1676
1677 JSValue* DateProtoFuncSetMonth::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1678 {
1679     if (!thisObj->inherits(&DateInstance::info))
1680         return throwError(exec, TypeError);
1681
1682     const bool utc = false;
1683
1684     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1685     JSValue* v = thisDateObj->internalValue();
1686     double milli = v->toNumber(exec);
1687     double secs = floor(milli / msPerSecond);
1688     double ms = milli - secs * msPerSecond;
1689
1690     GregorianDateTime t;
1691     msToGregorianDateTime(milli, utc, t);
1692
1693     fillStructuresUsingDateArgs(exec, args, 2, &ms, &t);    
1694
1695     JSValue* result = jsNumber(gregorianDateTimeToMS(t, ms, utc));
1696     thisDateObj->setInternalValue(result);
1697     return result;
1698 }
1699
1700 JSValue* DateProtoFuncSetUTCMonth::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1701 {
1702     if (!thisObj->inherits(&DateInstance::info))
1703         return throwError(exec, TypeError);
1704
1705     const bool utc = true;
1706
1707     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1708     JSValue* v = thisDateObj->internalValue();
1709     double milli = v->toNumber(exec);
1710     double secs = floor(milli / msPerSecond);
1711     double ms = milli - secs * msPerSecond;
1712
1713     GregorianDateTime t;
1714     msToGregorianDateTime(milli, utc, t);
1715
1716     fillStructuresUsingDateArgs(exec, args, 2, &ms, &t);    
1717
1718     JSValue* result = jsNumber(gregorianDateTimeToMS(t, ms, utc));
1719     thisDateObj->setInternalValue(result);
1720     return result;
1721 }
1722
1723 JSValue* DateProtoFuncSetFullYear::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1724 {
1725     if (!thisObj->inherits(&DateInstance::info))
1726         return throwError(exec, TypeError);
1727
1728     const bool utc = false;
1729
1730     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1731     JSValue* v = thisDateObj->internalValue();
1732     double milli = v->toNumber(exec);
1733     double secs = floor(milli / msPerSecond);
1734     double ms = milli - secs * msPerSecond;
1735
1736     GregorianDateTime t;
1737     msToGregorianDateTime(milli, utc, t);
1738
1739     fillStructuresUsingDateArgs(exec, args, 3, &ms, &t);
1740
1741     JSValue* result = jsNumber(gregorianDateTimeToMS(t, ms, utc));
1742     thisDateObj->setInternalValue(result);
1743     return result;
1744 }
1745
1746 JSValue* DateProtoFuncSetUTCFullYear::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1747 {
1748     if (!thisObj->inherits(&DateInstance::info))
1749         return throwError(exec, TypeError);
1750
1751     const bool utc = true;
1752
1753     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1754     JSValue* v = thisDateObj->internalValue();
1755     double milli = v->toNumber(exec);
1756     double secs = floor(milli / msPerSecond);
1757     double ms = milli - secs * msPerSecond;
1758
1759     GregorianDateTime t;
1760     msToGregorianDateTime(milli, utc, t);
1761
1762     fillStructuresUsingDateArgs(exec, args, 3, &ms, &t);
1763
1764     JSValue* result = jsNumber(gregorianDateTimeToMS(t, ms, utc));
1765     thisDateObj->setInternalValue(result);
1766     return result;
1767 }
1768
1769 JSValue* DateProtoFuncSetYear::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1770 {
1771     if (!thisObj->inherits(&DateInstance::info))
1772         return throwError(exec, TypeError);
1773
1774     const bool utc = false;
1775
1776     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1777     JSValue* v = thisDateObj->internalValue();
1778     double milli = v->toNumber(exec);
1779     double secs = floor(milli / msPerSecond);
1780     double ms = milli - secs * msPerSecond;
1781
1782     GregorianDateTime t;
1783     msToGregorianDateTime(milli, utc, t);
1784
1785     t.year = (args[0]->toInt32(exec) > 99 || args[0]->toInt32(exec) < 0) ? args[0]->toInt32(exec) - 1900 : args[0]->toInt32(exec);
1786
1787     JSValue* result = jsNumber(gregorianDateTimeToMS(t, ms, utc));
1788     thisDateObj->setInternalValue(result);
1789     return result;
1790 }
1791
1792 JSValue* DateProtoFuncGetYear::callAsFunction(ExecState* exec, JSObject* thisObj, const List&)
1793 {
1794     if (!thisObj->inherits(&DateInstance::info))
1795         return throwError(exec, TypeError);
1796
1797     const bool utc = false;
1798
1799     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1800     JSValue* v = thisDateObj->internalValue();
1801     double milli = v->toNumber(exec);
1802     if (isnan(milli))
1803         return jsNaN();
1804
1805     GregorianDateTime t;
1806     msToGregorianDateTime(milli, utc, t);
1807
1808     // IE returns the full year even in getYear.
1809     if (exec->dynamicInterpreter()->compatMode() == Interpreter::IECompat)
1810         return jsNumber(1900 + t.year);
1811     return jsNumber(t.year);
1812 }
1813
1814 } // namespace KJS