2b34923901f1b487dc58497babc0e92bb93d99ba
[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, 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 "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[0]) {
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     *ms = milliseconds;
284 }
285
286 // Converts a list of arguments sent to a Date member function into years, months, and milliseconds, updating
287 // ms (representing milliseconds) and t (representing the rest of the date structure) appropriately.
288 //
289 // Format of member function: f([years,] [months,] [days])
290 static void fillStructuresUsingDateArgs(ExecState *exec, const List &args, int maxArgs, double *ms, GregorianDateTime *t)
291 {
292     int idx = 0;
293     int numArgs = args.size();
294   
295     // JS allows extra trailing arguments -- ignore them
296     if (numArgs > maxArgs)
297         numArgs = maxArgs;
298   
299     // years
300     if (maxArgs >= 3 && idx < numArgs)
301         t->year = args[idx++]->toInt32(exec) - 1900;
302   
303     // months
304     if (maxArgs >= 2 && idx < numArgs)
305         t->month = args[idx++]->toInt32(exec);
306   
307     // days
308     if (idx < numArgs) {
309         t->monthDay = 0;
310         *ms += args[idx]->toInt32(exec) * msPerDay;
311     }
312 }
313
314 // ------------------------------ DateInstance ------------------------------
315
316 const ClassInfo DateInstance::info = {"Date", 0, 0};
317
318 DateInstance::DateInstance(JSObject *proto)
319   : JSWrapperObject(proto)
320 {
321 }
322
323 bool DateInstance::getTime(GregorianDateTime &t, int &offset) const
324 {
325     double milli = internalValue()->getNumber();
326     if (isnan(milli))
327         return false;
328     
329     msToGregorianDateTime(milli, false, t);
330     offset = gmtoffset(t);
331     return true;
332 }
333
334 bool DateInstance::getUTCTime(GregorianDateTime &t) const
335 {
336     double milli = internalValue()->getNumber();
337     if (isnan(milli))
338         return false;
339     
340     msToGregorianDateTime(milli, true, t);
341     return true;
342 }
343
344 bool DateInstance::getTime(double &milli, int &offset) const
345 {
346     milli = internalValue()->getNumber();
347     if (isnan(milli))
348         return false;
349     
350     GregorianDateTime t;
351     msToGregorianDateTime(milli, false, t);
352     offset = gmtoffset(t);
353     return true;
354 }
355
356 bool DateInstance::getUTCTime(double &milli) const
357 {
358     milli = internalValue()->getNumber();
359     if (isnan(milli))
360         return false;
361     
362     return true;
363 }
364
365 static inline bool isTime_tSigned()
366 {
367     time_t minusOne = (time_t)(-1);
368     return minusOne < 0;
369 }
370
371 // ------------------------------ DatePrototype -----------------------------
372
373 const ClassInfo DatePrototype::info = {"Date", &DateInstance::info, &dateTable};
374
375 /* Source for date_object.lut.h
376    FIXMEL We could use templates to simplify the UTC variants.
377 @begin dateTable 61
378   toString              dateProtoFuncToString                DontEnum|Function       0
379   toUTCString           dateProtoFuncToUTCString             DontEnum|Function       0
380   toDateString          dateProtoFuncToDateString            DontEnum|Function       0
381   toTimeString          dateProtoFuncToTimeString            DontEnum|Function       0
382   toLocaleString        dateProtoFuncToLocaleString          DontEnum|Function       0
383   toLocaleDateString    dateProtoFuncToLocaleDateString      DontEnum|Function       0
384   toLocaleTimeString    dateProtoFuncToLocaleTimeString      DontEnum|Function       0
385   valueOf               dateProtoFuncValueOf                 DontEnum|Function       0
386   getTime               dateProtoFuncGetTime                 DontEnum|Function       0
387   getFullYear           dateProtoFuncGetFullYear             DontEnum|Function       0
388   getUTCFullYear        dateProtoFuncGetUTCFullYear          DontEnum|Function       0
389   toGMTString           dateProtoFuncToGMTString             DontEnum|Function       0
390   getMonth              dateProtoFuncGetMonth                DontEnum|Function       0
391   getUTCMonth           dateProtoFuncGetUTCMonth             DontEnum|Function       0
392   getDate               dateProtoFuncGetDate                 DontEnum|Function       0
393   getUTCDate            dateProtoFuncGetUTCDate              DontEnum|Function       0
394   getDay                dateProtoFuncGetDay                  DontEnum|Function       0
395   getUTCDay             dateProtoFuncGetUTCDay               DontEnum|Function       0
396   getHours              dateProtoFuncGetHours                DontEnum|Function       0
397   getUTCHours           dateProtoFuncGetUTCHours             DontEnum|Function       0
398   getMinutes            dateProtoFuncGetMinutes              DontEnum|Function       0
399   getUTCMinutes         dateProtoFuncGetUTCMinutes           DontEnum|Function       0
400   getSeconds            dateProtoFuncGetSeconds              DontEnum|Function       0
401   getUTCSeconds         dateProtoFuncGetUTCSeconds           DontEnum|Function       0
402   getMilliseconds       dateProtoFuncGetMilliSeconds         DontEnum|Function       0
403   getUTCMilliseconds    dateProtoFuncGetUTCMilliseconds      DontEnum|Function       0
404   getTimezoneOffset     dateProtoFuncGetTimezoneOffset       DontEnum|Function       0
405   setTime               dateProtoFuncSetTime                 DontEnum|Function       1
406   setMilliseconds       dateProtoFuncSetMilliSeconds         DontEnum|Function       1
407   setUTCMilliseconds    dateProtoFuncSetUTCMilliseconds      DontEnum|Function       1
408   setSeconds            dateProtoFuncSetSeconds              DontEnum|Function       2
409   setUTCSeconds         dateProtoFuncSetUTCSeconds           DontEnum|Function       2
410   setMinutes            dateProtoFuncSetMinutes              DontEnum|Function       3
411   setUTCMinutes         dateProtoFuncSetUTCMinutes           DontEnum|Function       3
412   setHours              dateProtoFuncSetHours                DontEnum|Function       4
413   setUTCHours           dateProtoFuncSetUTCHours             DontEnum|Function       4
414   setDate               dateProtoFuncSetDate                 DontEnum|Function       1
415   setUTCDate            dateProtoFuncSetUTCDate              DontEnum|Function       1
416   setMonth              dateProtoFuncSetMonth                DontEnum|Function       2
417   setUTCMonth           dateProtoFuncSetUTCMonth             DontEnum|Function       2
418   setFullYear           dateProtoFuncSetFullYear             DontEnum|Function       3
419   setUTCFullYear        dateProtoFuncSetUTCFullYear          DontEnum|Function       3
420   setYear               dateProtoFuncSetYear                 DontEnum|Function       1
421   getYear               dateProtoFuncGetYear                 DontEnum|Function       0
422 @end
423 */
424 // ECMA 15.9.4
425
426 DatePrototype::DatePrototype(ExecState *, ObjectPrototype *objectProto)
427   : DateInstance(objectProto)
428 {
429     setInternalValue(jsNaN());
430     // The constructor will be added later, after DateObjectImp has been built.
431 }
432
433 bool DatePrototype::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
434 {
435     return getStaticFunctionSlot<JSObject>(exec, &dateTable, this, propertyName, slot);
436 }
437
438 // ------------------------------ DateObjectImp --------------------------------
439
440 // TODO: MakeTime (15.9.11.1) etc. ?
441
442 DateObjectImp::DateObjectImp(ExecState* exec, FunctionPrototype* funcProto, DatePrototype* dateProto)
443   : InternalFunctionImp(funcProto, dateProto->classInfo()->className)
444 {
445   static const Identifier* parsePropertyName = new Identifier("parse");
446   static const Identifier* UTCPropertyName = new Identifier("UTC");
447
448   putDirect(exec->propertyNames().prototype, dateProto, DontEnum|DontDelete|ReadOnly);
449   putDirectFunction(new DateObjectFuncImp(exec, funcProto, DateObjectFuncImp::Parse, 1, *parsePropertyName), DontEnum);
450   putDirectFunction(new DateObjectFuncImp(exec, funcProto, DateObjectFuncImp::UTC, 7, *UTCPropertyName), DontEnum);
451   putDirect(exec->propertyNames().length, 7, ReadOnly|DontDelete|DontEnum);
452 }
453
454 bool DateObjectImp::implementsConstruct() const
455 {
456     return true;
457 }
458
459 // ECMA 15.9.3
460 JSObject *DateObjectImp::construct(ExecState *exec, const List &args)
461 {
462   int numArgs = args.size();
463
464   double value;
465
466   if (numArgs == 0) { // new Date() ECMA 15.9.3.3
467     value = getCurrentUTCTime();
468   } else if (numArgs == 1) {
469     if (args[0]->isObject(&DateInstance::info))
470       value = static_cast<DateInstance*>(args[0])->internalValue()->toNumber(exec);
471     else {
472       JSValue* primitive = args[0]->toPrimitive(exec);
473       if (primitive->isString())
474         value = parseDate(primitive->getString());
475       else
476         value = primitive->toNumber(exec);
477     }
478   } else {
479     if (isnan(args[0]->toNumber(exec))
480         || isnan(args[1]->toNumber(exec))
481         || (numArgs >= 3 && isnan(args[2]->toNumber(exec)))
482         || (numArgs >= 4 && isnan(args[3]->toNumber(exec)))
483         || (numArgs >= 5 && isnan(args[4]->toNumber(exec)))
484         || (numArgs >= 6 && isnan(args[5]->toNumber(exec)))
485         || (numArgs >= 7 && isnan(args[6]->toNumber(exec)))) {
486       value = NaN;
487     } else {
488       GregorianDateTime t;
489       int year = args[0]->toInt32(exec);
490       t.year = (year >= 0 && year <= 99) ? year : year - 1900;
491       t.month = args[1]->toInt32(exec);
492       t.monthDay = (numArgs >= 3) ? args[2]->toInt32(exec) : 1;
493       t.hour = args[3]->toInt32(exec);
494       t.minute = args[4]->toInt32(exec);
495       t.second = args[5]->toInt32(exec);
496       t.isDST = -1;
497       double ms = (numArgs >= 7) ? args[6]->toNumber(exec) : 0;
498       value = gregorianDateTimeToMS(t, ms, false);
499     }
500   }
501   
502   DateInstance *ret = new DateInstance(exec->lexicalGlobalObject()->datePrototype());
503   ret->setInternalValue(jsNumber(timeClip(value)));
504   return ret;
505 }
506
507 // ECMA 15.9.2
508 JSValue *DateObjectImp::callAsFunction(ExecState * /*exec*/, JSObject * /*thisObj*/, const List &/*args*/)
509 {
510     time_t t = time(0);
511     GregorianDateTime ts(*localtime(&t));
512     return jsString(formatDate(ts) + " " + formatTime(ts, false));
513 }
514
515 // ------------------------------ DateObjectFuncImp ----------------------------
516
517 DateObjectFuncImp::DateObjectFuncImp(ExecState* exec, FunctionPrototype* funcProto, int i, int len, const Identifier& name)
518     : InternalFunctionImp(funcProto, name), id(i)
519 {
520     putDirect(exec->propertyNames().length, len, DontDelete|ReadOnly|DontEnum);
521 }
522
523 // ECMA 15.9.4.2 - 3
524 JSValue *DateObjectFuncImp::callAsFunction(ExecState* exec, JSObject*, const List& args)
525 {
526   if (id == Parse) {
527     return jsNumber(parseDate(args[0]->toString(exec)));
528   }
529   else { // UTC
530     int n = args.size();
531     if (isnan(args[0]->toNumber(exec))
532         || isnan(args[1]->toNumber(exec))
533         || (n >= 3 && isnan(args[2]->toNumber(exec)))
534         || (n >= 4 && isnan(args[3]->toNumber(exec)))
535         || (n >= 5 && isnan(args[4]->toNumber(exec)))
536         || (n >= 6 && isnan(args[5]->toNumber(exec)))
537         || (n >= 7 && isnan(args[6]->toNumber(exec)))) {
538       return jsNaN();
539     }
540
541     GregorianDateTime t;
542     memset(&t, 0, sizeof(t));
543     int year = args[0]->toInt32(exec);
544     t.year = (year >= 0 && year <= 99) ? year : year - 1900;
545     t.month = args[1]->toInt32(exec);
546     t.monthDay = (n >= 3) ? args[2]->toInt32(exec) : 1;
547     t.hour = args[3]->toInt32(exec);
548     t.minute = args[4]->toInt32(exec);
549     t.second = args[5]->toInt32(exec);
550     double ms = (n >= 7) ? args[6]->toNumber(exec) : 0;
551     return jsNumber(gregorianDateTimeToMS(t, ms, true));
552   }
553 }
554
555 // -----------------------------------------------------------------------------
556
557 // Code originally from krfcdate.cpp, but we don't want to use kdecore, and we want double range.
558
559 static inline double ymdhmsToSeconds(long year, int mon, int day, int hour, int minute, int second)
560 {
561     double days = (day - 32075)
562         + floor(1461 * (year + 4800.0 + (mon - 14) / 12) / 4)
563         + 367 * (mon - 2 - (mon - 14) / 12 * 12) / 12
564         - floor(3 * ((year + 4900.0 + (mon - 14) / 12) / 100) / 4)
565         - 2440588;
566     return ((days * hoursPerDay + hour) * minutesPerHour + minute) * secondsPerMinute + second;
567 }
568
569 // We follow the recommendation of RFC 2822 to consider all
570 // obsolete time zones not listed here equivalent to "-0000".
571 static const struct KnownZone {
572 #if !PLATFORM(WIN_OS)
573     const
574 #endif
575         char tzName[4];
576     int tzOffset;
577 } known_zones[] = {
578     { "UT", 0 },
579     { "GMT", 0 },
580     { "EST", -300 },
581     { "EDT", -240 },
582     { "CST", -360 },
583     { "CDT", -300 },
584     { "MST", -420 },
585     { "MDT", -360 },
586     { "PST", -480 },
587     { "PDT", -420 }
588 };
589
590 inline static void skipSpacesAndComments(const char*& s)
591 {
592     int nesting = 0;
593     char ch;
594     while ((ch = *s)) {
595         if (!isASCIISpace(ch)) {
596             if (ch == '(')
597                 nesting++;
598             else if (ch == ')' && nesting > 0)
599                 nesting--;
600             else if (nesting == 0)
601                 break;
602         }
603         s++;
604     }
605 }
606
607 // returns 0-11 (Jan-Dec); -1 on failure
608 static int findMonth(const char* monthStr)
609 {
610     ASSERT(monthStr);
611     char needle[4];
612     for (int i = 0; i < 3; ++i) {
613         if (!*monthStr)
614             return -1;
615         needle[i] = static_cast<char>(toASCIILower(*monthStr++));
616     }
617     needle[3] = '\0';
618     const char *haystack = "janfebmaraprmayjunjulaugsepoctnovdec";
619     const char *str = strstr(haystack, needle);
620     if (str) {
621         int position = static_cast<int>(str - haystack);
622         if (position % 3 == 0)
623             return position / 3;
624     }
625     return -1;
626 }
627
628 static double parseDate(const UString &date)
629 {
630     // This parses a date in the form:
631     //     Tuesday, 09-Nov-99 23:12:40 GMT
632     // or
633     //     Sat, 01-Jan-2000 08:00:00 GMT
634     // or
635     //     Sat, 01 Jan 2000 08:00:00 GMT
636     // or
637     //     01 Jan 99 22:00 +0100    (exceptions in rfc822/rfc2822)
638     // ### non RFC formats, added for Javascript:
639     //     [Wednesday] January 09 1999 23:12:40 GMT
640     //     [Wednesday] January 09 23:12:40 GMT 1999
641     //
642     // We ignore the weekday.
643
644     CString dateCString = date.UTF8String();
645     const char *dateString = dateCString.c_str();
646      
647     // Skip leading space
648     skipSpacesAndComments(dateString);
649
650     long month = -1;
651     const char *wordStart = dateString;
652     // Check contents of first words if not number
653     while (*dateString && !isASCIIDigit(*dateString)) {
654         if (isASCIISpace(*dateString) || *dateString == '(') {
655             if (dateString - wordStart >= 3)
656                 month = findMonth(wordStart);
657             skipSpacesAndComments(dateString);
658             wordStart = dateString;
659         } else
660            dateString++;
661     }
662
663     // Missing delimiter between month and day (like "January29")?
664     if (month == -1 && wordStart != dateString)
665         month = findMonth(wordStart);
666
667     skipSpacesAndComments(dateString);
668
669     if (!*dateString)
670         return NaN;
671
672     // ' 09-Nov-99 23:12:40 GMT'
673     char *newPosStr;
674     errno = 0;
675     long day = strtol(dateString, &newPosStr, 10);
676     if (errno)
677         return NaN;
678     dateString = newPosStr;
679
680     if (!*dateString)
681         return NaN;
682
683     if (day < 0)
684         return NaN;
685
686     long year = 0;
687     if (day > 31) {
688         // ### where is the boundary and what happens below?
689         if (*dateString != '/')
690             return NaN;
691         // looks like a YYYY/MM/DD date
692         if (!*++dateString)
693             return NaN;
694         year = day;
695         month = strtol(dateString, &newPosStr, 10) - 1;
696         if (errno)
697             return NaN;
698         dateString = newPosStr;
699         if (*dateString++ != '/' || !*dateString)
700             return NaN;
701         day = strtol(dateString, &newPosStr, 10);
702         if (errno)
703             return NaN;
704         dateString = newPosStr;
705     } else if (*dateString == '/' && month == -1) {
706         dateString++;
707         // This looks like a MM/DD/YYYY date, not an RFC date.
708         month = day - 1; // 0-based
709         day = strtol(dateString, &newPosStr, 10);
710         if (errno)
711             return NaN;
712         if (day < 1 || day > 31)
713             return NaN;
714         dateString = newPosStr;
715         if (*dateString == '/')
716             dateString++;
717         if (!*dateString)
718             return NaN;
719      } else {
720         if (*dateString == '-')
721             dateString++;
722
723         skipSpacesAndComments(dateString);
724
725         if (*dateString == ',')
726             dateString++;
727
728         if (month == -1) { // not found yet
729             month = findMonth(dateString);
730             if (month == -1)
731                 return NaN;
732
733             while (*dateString && *dateString != '-' && *dateString != ',' && !isASCIISpace(*dateString))
734                 dateString++;
735
736             if (!*dateString)
737                 return NaN;
738
739             // '-99 23:12:40 GMT'
740             if (*dateString != '-' && *dateString != '/' && *dateString != ',' && !isASCIISpace(*dateString))
741                 return NaN;
742             dateString++;
743         }
744     }
745
746     if (month < 0 || month > 11)
747         return NaN;
748
749     // '99 23:12:40 GMT'
750     if (year <= 0 && *dateString) {
751         year = strtol(dateString, &newPosStr, 10);
752         if (errno)
753             return NaN;
754     }
755     
756     // Don't fail if the time is missing.
757     long hour = 0;
758     long minute = 0;
759     long second = 0;
760     if (!*newPosStr)
761         dateString = newPosStr;
762     else {
763         // ' 23:12:40 GMT'
764         if (!(isASCIISpace(*newPosStr) || *newPosStr == ',')) {
765             if (*newPosStr != ':')
766                 return NaN;
767             // There was no year; the number was the hour.
768             year = -1;
769         } else {
770             // in the normal case (we parsed the year), advance to the next number
771             dateString = ++newPosStr;
772             skipSpacesAndComments(dateString);
773         }
774
775         hour = strtol(dateString, &newPosStr, 10);
776         // Do not check for errno here since we want to continue
777         // even if errno was set becasue we are still looking
778         // for the timezone!
779
780         // Read a number? If not, this might be a timezone name.
781         if (newPosStr != dateString) {
782             dateString = newPosStr;
783
784             if (hour < 0 || hour > 23)
785                 return NaN;
786
787             if (!*dateString)
788                 return NaN;
789
790             // ':12:40 GMT'
791             if (*dateString++ != ':')
792                 return NaN;
793
794             minute = strtol(dateString, &newPosStr, 10);
795             if (errno)
796                 return NaN;
797             dateString = newPosStr;
798
799             if (minute < 0 || minute > 59)
800                 return NaN;
801
802             // ':40 GMT'
803             if (*dateString && *dateString != ':' && !isASCIISpace(*dateString))
804                 return NaN;
805
806             // seconds are optional in rfc822 + rfc2822
807             if (*dateString ==':') {
808                 dateString++;
809
810                 second = strtol(dateString, &newPosStr, 10);
811                 if (errno)
812                     return NaN;
813                 dateString = newPosStr;
814             
815                 if (second < 0 || second > 59)
816                     return NaN;
817             }
818
819             skipSpacesAndComments(dateString);
820
821             if (strncasecmp(dateString, "AM", 2) == 0) {
822                 if (hour > 12)
823                     return NaN;
824                 if (hour == 12)
825                     hour = 0;
826                 dateString += 2;
827                 skipSpacesAndComments(dateString);
828             } else if (strncasecmp(dateString, "PM", 2) == 0) {
829                 if (hour > 12)
830                     return NaN;
831                 if (hour != 12)
832                     hour += 12;
833                 dateString += 2;
834                 skipSpacesAndComments(dateString);
835             }
836         }
837     }
838
839     bool haveTZ = false;
840     int offset = 0;
841
842     // Don't fail if the time zone is missing. 
843     // Some websites omit the time zone (4275206).
844     if (*dateString) {
845         if (strncasecmp(dateString, "GMT", 3) == 0 || strncasecmp(dateString, "UTC", 3) == 0) {
846             dateString += 3;
847             haveTZ = true;
848         }
849
850         if (*dateString == '+' || *dateString == '-') {
851             long o = strtol(dateString, &newPosStr, 10);
852             if (errno)
853                 return NaN;
854             dateString = newPosStr;
855
856             if (o < -9959 || o > 9959)
857                 return NaN;
858
859             int sgn = (o < 0) ? -1 : 1;
860             o = abs(o);
861             if (*dateString != ':') {
862                 offset = ((o / 100) * 60 + (o % 100)) * sgn;
863             } else { // GMT+05:00
864                 long o2 = strtol(dateString, &newPosStr, 10);
865                 if (errno)
866                     return NaN;
867                 dateString = newPosStr;
868                 offset = (o * 60 + o2) * sgn;
869             }
870             haveTZ = true;
871         } else {
872             for (int i = 0; i < int(sizeof(known_zones) / sizeof(KnownZone)); i++) {
873                 if (0 == strncasecmp(dateString, known_zones[i].tzName, strlen(known_zones[i].tzName))) {
874                     offset = known_zones[i].tzOffset;
875                     dateString += strlen(known_zones[i].tzName);
876                     haveTZ = true;
877                     break;
878                 }
879             }
880         }
881     }
882
883     skipSpacesAndComments(dateString);
884
885     if (*dateString && year == -1) {
886         year = strtol(dateString, &newPosStr, 10);
887         if (errno)
888             return NaN;
889         dateString = newPosStr;
890     }
891      
892     skipSpacesAndComments(dateString);
893      
894     // Trailing garbage
895     if (*dateString)
896         return NaN;
897
898     // Y2K: Handle 2 digit years.
899     if (year >= 0 && year < 100) {
900         if (year < 50)
901             year += 2000;
902         else
903             year += 1900;
904     }
905
906     // fall back to local timezone
907     if (!haveTZ) {
908         GregorianDateTime t;
909         memset(&t, 0, sizeof(tm));
910         t.monthDay = day;
911         t.month = month;
912         t.year = year - 1900;
913         t.isDST = -1;
914         t.second = second;
915         t.minute = minute;
916         t.hour = hour;
917
918         // Use our gregorianDateTimeToMS() rather than mktime() as the latter can't handle the full year range.
919         return gregorianDateTimeToMS(t, 0, false);
920     }
921
922     return (ymdhmsToSeconds(year, month + 1, day, hour, minute, second) - (offset * 60.0)) * msPerSecond;
923 }
924
925 double timeClip(double t)
926 {
927     if (!isfinite(t))
928         return NaN;
929     if (fabs(t) > 8.64E15)
930         return NaN;
931     return trunc(t);
932 }
933
934 // Functions
935
936 JSValue* dateProtoFuncToString(ExecState* exec, JSObject* thisObj, const List&)
937 {
938     if (!thisObj->inherits(&DateInstance::info))
939         return throwError(exec, TypeError);
940
941     const bool utc = false;
942
943     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
944     JSValue* v = thisDateObj->internalValue();
945     double milli = v->toNumber(exec);
946     if (isnan(milli))
947         return jsString("Invalid Date");
948
949     GregorianDateTime t;
950     msToGregorianDateTime(milli, utc, t);
951     return jsString(formatDate(t) + " " + formatTime(t, utc));
952 }
953
954 JSValue* dateProtoFuncToUTCString(ExecState* exec, JSObject* thisObj, const List&)
955 {
956     if (!thisObj->inherits(&DateInstance::info))
957         return throwError(exec, TypeError);
958
959     const bool utc = true;
960
961     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
962     JSValue* v = thisDateObj->internalValue();
963     double milli = v->toNumber(exec);
964     if (isnan(milli))
965         return jsString("Invalid Date");
966
967     GregorianDateTime t;
968     msToGregorianDateTime(milli, utc, t);
969     return jsString(formatDateUTCVariant(t) + " " + formatTime(t, utc));
970 }
971
972 JSValue* dateProtoFuncToDateString(ExecState* exec, JSObject* thisObj, const List&)
973 {
974     if (!thisObj->inherits(&DateInstance::info))
975         return throwError(exec, TypeError);
976
977     const bool utc = false;
978
979     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
980     JSValue* v = thisDateObj->internalValue();
981     double milli = v->toNumber(exec);
982     if (isnan(milli))
983         return jsString("Invalid Date");
984
985     GregorianDateTime t;
986     msToGregorianDateTime(milli, utc, t);
987     return jsString(formatDate(t));
988 }
989
990 JSValue* dateProtoFuncToTimeString(ExecState* exec, JSObject* thisObj, const List&)
991 {
992     if (!thisObj->inherits(&DateInstance::info))
993         return throwError(exec, TypeError);
994
995     const bool utc = false;
996
997     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
998     JSValue* v = thisDateObj->internalValue();
999     double milli = v->toNumber(exec);
1000     if (isnan(milli))
1001         return jsString("Invalid Date");
1002
1003     GregorianDateTime t;
1004     msToGregorianDateTime(milli, utc, t);
1005     return jsString(formatTime(t, utc));
1006 }
1007
1008 JSValue* dateProtoFuncToLocaleString(ExecState* exec, JSObject* thisObj, const List& args)
1009 {
1010     if (!thisObj->inherits(&DateInstance::info))
1011         return throwError(exec, TypeError);
1012
1013     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1014     JSValue* v = thisDateObj->internalValue();
1015     double milli = v->toNumber(exec);
1016     if (isnan(milli))
1017         return jsString("Invalid Date");
1018
1019 #if PLATFORM(MAC)
1020     double secs = floor(milli / msPerSecond);
1021     return jsString(formatLocaleDate(exec, secs, true, true, args));
1022 #else
1023     UNUSED_PARAM(args);
1024
1025     const bool utc = false;
1026
1027     GregorianDateTime t;
1028     msToGregorianDateTime(milli, utc, t);
1029     return formatLocaleDate(t, LocaleDateAndTime);
1030 #endif
1031 }
1032
1033 JSValue* dateProtoFuncToLocaleDateString(ExecState* exec, JSObject* thisObj, const List& args)
1034 {
1035     if (!thisObj->inherits(&DateInstance::info))
1036         return throwError(exec, TypeError);
1037
1038     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1039     JSValue* v = thisDateObj->internalValue();
1040     double milli = v->toNumber(exec);
1041     if (isnan(milli))
1042         return jsString("Invalid Date");
1043
1044 #if PLATFORM(MAC)
1045     double secs = floor(milli / msPerSecond);
1046     return jsString(formatLocaleDate(exec, secs, true, false, args));
1047 #else
1048     UNUSED_PARAM(args);
1049
1050     const bool utc = false;
1051
1052     GregorianDateTime t;
1053     msToGregorianDateTime(milli, utc, t);
1054     return formatLocaleDate(t, LocaleDate);
1055 #endif
1056 }
1057
1058 JSValue* dateProtoFuncToLocaleTimeString(ExecState* exec, JSObject* thisObj, const List& args)
1059 {
1060     if (!thisObj->inherits(&DateInstance::info))
1061         return throwError(exec, TypeError);
1062
1063     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1064     JSValue* v = thisDateObj->internalValue();
1065     double milli = v->toNumber(exec);
1066     if (isnan(milli))
1067         return jsString("Invalid Date");
1068
1069 #if PLATFORM(MAC)
1070     double secs = floor(milli / msPerSecond);
1071     return jsString(formatLocaleDate(exec, secs, false, true, args));
1072 #else
1073     UNUSED_PARAM(args);
1074
1075     const bool utc = false;
1076
1077     GregorianDateTime t;
1078     msToGregorianDateTime(milli, utc, t);
1079     return formatLocaleDate(t, LocaleTime);
1080 #endif
1081 }
1082
1083 JSValue* dateProtoFuncValueOf(ExecState* exec, JSObject* thisObj, const List&)
1084 {
1085     if (!thisObj->inherits(&DateInstance::info))
1086         return throwError(exec, TypeError);
1087
1088     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1089     JSValue* v = thisDateObj->internalValue();
1090     double milli = v->toNumber(exec);
1091     if (isnan(milli))
1092         return jsNaN();
1093
1094     return jsNumber(milli);
1095 }
1096
1097 JSValue* dateProtoFuncGetTime(ExecState* exec, JSObject* thisObj, const List&)
1098 {
1099     if (!thisObj->inherits(&DateInstance::info))
1100         return throwError(exec, TypeError);
1101
1102     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1103     JSValue* v = thisDateObj->internalValue();
1104     double milli = v->toNumber(exec);
1105     if (isnan(milli))
1106         return jsNaN();
1107
1108     return jsNumber(milli);
1109 }
1110
1111 JSValue* dateProtoFuncGetFullYear(ExecState* exec, JSObject* thisObj, const List&)
1112 {
1113     if (!thisObj->inherits(&DateInstance::info))
1114         return throwError(exec, TypeError);
1115
1116     const bool utc = false;
1117
1118     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1119     JSValue* v = thisDateObj->internalValue();
1120     double milli = v->toNumber(exec);
1121     if (isnan(milli))
1122         return jsNaN();
1123
1124     GregorianDateTime t;
1125     msToGregorianDateTime(milli, utc, t);
1126     return jsNumber(1900 + t.year);
1127 }
1128
1129 JSValue* dateProtoFuncGetUTCFullYear(ExecState* exec, JSObject* thisObj, const List&)
1130 {
1131     if (!thisObj->inherits(&DateInstance::info))
1132         return throwError(exec, TypeError);
1133
1134     const bool utc = true;
1135
1136     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1137     JSValue* v = thisDateObj->internalValue();
1138     double milli = v->toNumber(exec);
1139     if (isnan(milli))
1140         return jsNaN();
1141
1142     GregorianDateTime t;
1143     msToGregorianDateTime(milli, utc, t);
1144     return jsNumber(1900 + t.year);
1145 }
1146
1147 JSValue* dateProtoFuncToGMTString(ExecState* exec, JSObject* thisObj, const List&)
1148 {
1149     if (!thisObj->inherits(&DateInstance::info))
1150         return throwError(exec, TypeError);
1151
1152     const bool utc = true;
1153
1154     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1155     JSValue* v = thisDateObj->internalValue();
1156     double milli = v->toNumber(exec);
1157     if (isnan(milli))
1158         return jsString("Invalid Date");
1159
1160     GregorianDateTime t;
1161     msToGregorianDateTime(milli, utc, t);
1162     return jsString(formatDateUTCVariant(t) + " " + formatTime(t, utc));
1163 }
1164
1165 JSValue* dateProtoFuncGetMonth(ExecState* exec, JSObject* thisObj, const List&)
1166 {
1167     if (!thisObj->inherits(&DateInstance::info))
1168         return throwError(exec, TypeError);
1169
1170     const bool utc = false;
1171
1172     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1173     JSValue* v = thisDateObj->internalValue();
1174     double milli = v->toNumber(exec);
1175     if (isnan(milli))
1176         return jsNaN();
1177
1178     GregorianDateTime t;
1179     msToGregorianDateTime(milli, utc, t);
1180     return jsNumber(t.month);
1181 }
1182
1183 JSValue* dateProtoFuncGetUTCMonth(ExecState* exec, JSObject* thisObj, const List&)
1184 {
1185     if (!thisObj->inherits(&DateInstance::info))
1186         return throwError(exec, TypeError);
1187
1188     const bool utc = true;
1189
1190     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1191     JSValue* v = thisDateObj->internalValue();
1192     double milli = v->toNumber(exec);
1193     if (isnan(milli))
1194         return jsNaN();
1195
1196     GregorianDateTime t;
1197     msToGregorianDateTime(milli, utc, t);
1198     return jsNumber(t.month);
1199 }
1200
1201 JSValue* dateProtoFuncGetDate(ExecState* exec, JSObject* thisObj, const List&)
1202 {
1203     if (!thisObj->inherits(&DateInstance::info))
1204         return throwError(exec, TypeError);
1205
1206     const bool utc = false;
1207
1208     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1209     JSValue* v = thisDateObj->internalValue();
1210     double milli = v->toNumber(exec);
1211     if (isnan(milli))
1212         return jsNaN();
1213
1214     GregorianDateTime t;
1215     msToGregorianDateTime(milli, utc, t);
1216     return jsNumber(t.monthDay);
1217 }
1218
1219 JSValue* dateProtoFuncGetUTCDate(ExecState* exec, JSObject* thisObj, const List&)
1220 {
1221     if (!thisObj->inherits(&DateInstance::info))
1222         return throwError(exec, TypeError);
1223
1224     const bool utc = true;
1225
1226     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1227     JSValue* v = thisDateObj->internalValue();
1228     double milli = v->toNumber(exec);
1229     if (isnan(milli))
1230         return jsNaN();
1231
1232     GregorianDateTime t;
1233     msToGregorianDateTime(milli, utc, t);
1234     return jsNumber(t.monthDay);
1235 }
1236
1237 JSValue* dateProtoFuncGetDay(ExecState* exec, JSObject* thisObj, const List&)
1238 {
1239     if (!thisObj->inherits(&DateInstance::info))
1240         return throwError(exec, TypeError);
1241
1242     const bool utc = false;
1243
1244     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1245     JSValue* v = thisDateObj->internalValue();
1246     double milli = v->toNumber(exec);
1247     if (isnan(milli))
1248         return jsNaN();
1249
1250     GregorianDateTime t;
1251     msToGregorianDateTime(milli, utc, t);
1252     return jsNumber(t.weekDay);
1253 }
1254
1255 JSValue* dateProtoFuncGetUTCDay(ExecState* exec, JSObject* thisObj, const List&)
1256 {
1257     if (!thisObj->inherits(&DateInstance::info))
1258         return throwError(exec, TypeError);
1259
1260     const bool utc = true;
1261
1262     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1263     JSValue* v = thisDateObj->internalValue();
1264     double milli = v->toNumber(exec);
1265     if (isnan(milli))
1266         return jsNaN();
1267
1268     GregorianDateTime t;
1269     msToGregorianDateTime(milli, utc, t);
1270     return jsNumber(t.weekDay);
1271 }
1272
1273 JSValue* dateProtoFuncGetHours(ExecState* exec, JSObject* thisObj, const List&)
1274 {
1275     if (!thisObj->inherits(&DateInstance::info))
1276         return throwError(exec, TypeError);
1277
1278     const bool utc = false;
1279
1280     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1281     JSValue* v = thisDateObj->internalValue();
1282     double milli = v->toNumber(exec);
1283     if (isnan(milli))
1284         return jsNaN();
1285
1286     GregorianDateTime t;
1287     msToGregorianDateTime(milli, utc, t);
1288     return jsNumber(t.hour);
1289 }
1290
1291 JSValue* dateProtoFuncGetUTCHours(ExecState* exec, JSObject* thisObj, const List&)
1292 {
1293     if (!thisObj->inherits(&DateInstance::info))
1294         return throwError(exec, TypeError);
1295
1296     const bool utc = true;
1297
1298     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1299     JSValue* v = thisDateObj->internalValue();
1300     double milli = v->toNumber(exec);
1301     if (isnan(milli))
1302         return jsNaN();
1303
1304     GregorianDateTime t;
1305     msToGregorianDateTime(milli, utc, t);
1306     return jsNumber(t.hour);
1307 }
1308
1309 JSValue* dateProtoFuncGetMinutes(ExecState* exec, JSObject* thisObj, const List&)
1310 {
1311     if (!thisObj->inherits(&DateInstance::info))
1312         return throwError(exec, TypeError);
1313
1314     const bool utc = false;
1315
1316     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1317     JSValue* v = thisDateObj->internalValue();
1318     double milli = v->toNumber(exec);
1319     if (isnan(milli))
1320         return jsNaN();
1321
1322     GregorianDateTime t;
1323     msToGregorianDateTime(milli, utc, t);
1324     return jsNumber(t.minute);
1325 }
1326
1327 JSValue* dateProtoFuncGetUTCMinutes(ExecState* exec, JSObject* thisObj, const List&)
1328 {
1329     if (!thisObj->inherits(&DateInstance::info))
1330         return throwError(exec, TypeError);
1331
1332     const bool utc = true;
1333
1334     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1335     JSValue* v = thisDateObj->internalValue();
1336     double milli = v->toNumber(exec);
1337     if (isnan(milli))
1338         return jsNaN();
1339
1340     GregorianDateTime t;
1341     msToGregorianDateTime(milli, utc, t);
1342     return jsNumber(t.minute);
1343 }
1344
1345 JSValue* dateProtoFuncGetSeconds(ExecState* exec, JSObject* thisObj, const List&)
1346 {
1347     if (!thisObj->inherits(&DateInstance::info))
1348         return throwError(exec, TypeError);
1349
1350     const bool utc = false;
1351
1352     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1353     JSValue* v = thisDateObj->internalValue();
1354     double milli = v->toNumber(exec);
1355     if (isnan(milli))
1356         return jsNaN();
1357
1358     GregorianDateTime t;
1359     msToGregorianDateTime(milli, utc, t);
1360     return jsNumber(t.second);
1361 }
1362
1363 JSValue* dateProtoFuncGetUTCSeconds(ExecState* exec, JSObject* thisObj, const List&)
1364 {
1365     if (!thisObj->inherits(&DateInstance::info))
1366         return throwError(exec, TypeError);
1367
1368     const bool utc = true;
1369
1370     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1371     JSValue* v = thisDateObj->internalValue();
1372     double milli = v->toNumber(exec);
1373     if (isnan(milli))
1374         return jsNaN();
1375
1376     GregorianDateTime t;
1377     msToGregorianDateTime(milli, utc, t);
1378     return jsNumber(t.second);
1379 }
1380
1381 JSValue* dateProtoFuncGetMilliSeconds(ExecState* exec, JSObject* thisObj, const List&)
1382 {
1383     if (!thisObj->inherits(&DateInstance::info))
1384         return throwError(exec, TypeError);
1385
1386     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1387     JSValue* v = thisDateObj->internalValue();
1388     double milli = v->toNumber(exec);
1389     if (isnan(milli))
1390         return jsNaN();
1391
1392     double secs = floor(milli / msPerSecond);
1393     double ms = milli - secs * msPerSecond;
1394     return jsNumber(ms);
1395 }
1396
1397 JSValue* dateProtoFuncGetUTCMilliseconds(ExecState* exec, JSObject* thisObj, const List&)
1398 {
1399     if (!thisObj->inherits(&DateInstance::info))
1400         return throwError(exec, TypeError);
1401
1402     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1403     JSValue* v = thisDateObj->internalValue();
1404     double milli = v->toNumber(exec);
1405     if (isnan(milli))
1406         return jsNaN();
1407
1408     double secs = floor(milli / msPerSecond);
1409     double ms = milli - secs * msPerSecond;
1410     return jsNumber(ms);
1411 }
1412
1413 JSValue* dateProtoFuncGetTimezoneOffset(ExecState* exec, JSObject* thisObj, const List&)
1414 {
1415     if (!thisObj->inherits(&DateInstance::info))
1416         return throwError(exec, TypeError);
1417
1418     const bool utc = false;
1419
1420     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1421     JSValue* v = thisDateObj->internalValue();
1422     double milli = v->toNumber(exec);
1423     if (isnan(milli))
1424         return jsNaN();
1425
1426     GregorianDateTime t;
1427     msToGregorianDateTime(milli, utc, t);
1428     return jsNumber(-gmtoffset(t) / minutesPerHour);
1429 }
1430
1431 JSValue* dateProtoFuncSetTime(ExecState* exec, JSObject* thisObj, const List& args)
1432 {
1433     if (!thisObj->inherits(&DateInstance::info))
1434         return throwError(exec, TypeError);
1435
1436     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1437
1438     double milli = timeClip(args[0]->toNumber(exec));
1439     JSValue* result = jsNumber(milli);
1440     thisDateObj->setInternalValue(result);
1441     return result;
1442 }
1443
1444 static JSValue* setNewValueFromTimeArgs(ExecState* exec, JSObject* thisObj, const List& args, int numArgsToUse, bool inputIsUTC)
1445 {
1446     if (!thisObj->inherits(&DateInstance::info))
1447         return throwError(exec, TypeError);
1448
1449     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
1450     JSValue* v = thisDateObj->internalValue();
1451     double milli = v->toNumber(exec);
1452     double secs = floor(milli / msPerSecond);
1453     double ms = milli - secs * msPerSecond;
1454
1455     GregorianDateTime t;
1456     msToGregorianDateTime(milli, inputIsUTC, t);
1457
1458     fillStructuresUsingTimeArgs(exec, args, numArgsToUse, &ms, &t);
1459
1460     JSValue* result = jsNumber(gregorianDateTimeToMS(t, ms, inputIsUTC));
1461     thisDateObj->setInternalValue(result);
1462     return result;
1463 }
1464
1465 static JSValue* setNewValueFromDateArgs(ExecState* exec, JSObject* thisObj, const List& args, int numArgsToUse, bool inputIsUTC)
1466 {
1467     if (!thisObj->inherits(&DateInstance::info))
1468         return throwError(exec, TypeError);
1469
1470     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
1471     JSValue* v = thisDateObj->internalValue();
1472     double milli = v->toNumber(exec);
1473     double secs = floor(milli / msPerSecond);
1474     double ms = milli - secs * msPerSecond;
1475
1476     GregorianDateTime t;
1477     msToGregorianDateTime(milli, inputIsUTC, t);
1478
1479     fillStructuresUsingDateArgs(exec, args, numArgsToUse, &ms, &t);
1480
1481     JSValue* result = jsNumber(gregorianDateTimeToMS(t, ms, inputIsUTC));
1482     thisDateObj->setInternalValue(result);
1483     return result;
1484 }
1485
1486 JSValue* dateProtoFuncSetMilliSeconds(ExecState* exec, JSObject* thisObj, const List& args)
1487 {
1488     const bool inputIsUTC = false;
1489     return setNewValueFromTimeArgs(exec, thisObj, args, 1, inputIsUTC);
1490 }
1491
1492 JSValue* dateProtoFuncSetUTCMilliseconds(ExecState* exec, JSObject* thisObj, const List& args)
1493 {
1494     const bool inputIsUTC = true;
1495     return setNewValueFromTimeArgs(exec, thisObj, args, 1, inputIsUTC);
1496 }
1497
1498 JSValue* dateProtoFuncSetSeconds(ExecState* exec, JSObject* thisObj, const List& args)
1499 {
1500     const bool inputIsUTC = false;
1501     return setNewValueFromTimeArgs(exec, thisObj, args, 2, inputIsUTC);
1502 }
1503
1504 JSValue* dateProtoFuncSetUTCSeconds(ExecState* exec, JSObject* thisObj, const List& args)
1505 {
1506     const bool inputIsUTC = true;
1507     return setNewValueFromTimeArgs(exec, thisObj, args, 2, inputIsUTC);
1508 }
1509
1510 JSValue* dateProtoFuncSetMinutes(ExecState* exec, JSObject* thisObj, const List& args)
1511 {
1512     const bool inputIsUTC = false;
1513     return setNewValueFromTimeArgs(exec, thisObj, args, 3, inputIsUTC);
1514 }
1515
1516 JSValue* dateProtoFuncSetUTCMinutes(ExecState* exec, JSObject* thisObj, const List& args)
1517 {
1518     const bool inputIsUTC = true;
1519     return setNewValueFromTimeArgs(exec, thisObj, args, 3, inputIsUTC);
1520 }
1521
1522 JSValue* dateProtoFuncSetHours(ExecState* exec, JSObject* thisObj, const List& args)
1523 {
1524     const bool inputIsUTC = false;
1525     return setNewValueFromTimeArgs(exec, thisObj, args, 4, inputIsUTC);
1526 }
1527
1528 JSValue* dateProtoFuncSetUTCHours(ExecState* exec, JSObject* thisObj, const List& args)
1529 {
1530     const bool inputIsUTC = true;
1531     return setNewValueFromTimeArgs(exec, thisObj, args, 4, inputIsUTC);
1532 }
1533
1534 JSValue* dateProtoFuncSetDate(ExecState* exec, JSObject* thisObj, const List& args)
1535 {
1536     const bool inputIsUTC = false;
1537     return setNewValueFromDateArgs(exec, thisObj, args, 1, inputIsUTC);
1538 }
1539
1540 JSValue* dateProtoFuncSetUTCDate(ExecState* exec, JSObject* thisObj, const List& args)
1541 {
1542     const bool inputIsUTC = true;
1543     return setNewValueFromDateArgs(exec, thisObj, args, 1, inputIsUTC);
1544 }
1545
1546 JSValue* dateProtoFuncSetMonth(ExecState* exec, JSObject* thisObj, const List& args)
1547 {
1548     const bool inputIsUTC = false;
1549     return setNewValueFromDateArgs(exec, thisObj, args, 2, inputIsUTC);
1550 }
1551
1552 JSValue* dateProtoFuncSetUTCMonth(ExecState* exec, JSObject* thisObj, const List& args)
1553 {
1554     const bool inputIsUTC = true;
1555     return setNewValueFromDateArgs(exec, thisObj, args, 2, inputIsUTC);
1556 }
1557
1558 JSValue* dateProtoFuncSetFullYear(ExecState* exec, JSObject* thisObj, const List& args)
1559 {
1560     const bool inputIsUTC = false;
1561     return setNewValueFromDateArgs(exec, thisObj, args, 3, inputIsUTC);
1562 }
1563
1564 JSValue* dateProtoFuncSetUTCFullYear(ExecState* exec, JSObject* thisObj, const List& args)
1565 {
1566     const bool inputIsUTC = true;
1567     return setNewValueFromDateArgs(exec, thisObj, args, 3, inputIsUTC);
1568 }
1569
1570 JSValue* dateProtoFuncSetYear(ExecState* exec, JSObject* thisObj, const List& args)
1571 {
1572     if (!thisObj->inherits(&DateInstance::info))
1573         return throwError(exec, TypeError);
1574
1575     const bool utc = false;
1576
1577     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1578     JSValue* v = thisDateObj->internalValue();
1579     double milli = v->toNumber(exec);
1580     double secs = floor(milli / msPerSecond);
1581     double ms = milli - secs * msPerSecond;
1582
1583     GregorianDateTime t;
1584     msToGregorianDateTime(milli, utc, t);
1585
1586     t.year = (args[0]->toInt32(exec) > 99 || args[0]->toInt32(exec) < 0) ? args[0]->toInt32(exec) - 1900 : args[0]->toInt32(exec);
1587
1588     JSValue* result = jsNumber(gregorianDateTimeToMS(t, ms, utc));
1589     thisDateObj->setInternalValue(result);
1590     return result;
1591 }
1592
1593 JSValue* dateProtoFuncGetYear(ExecState* exec, JSObject* thisObj, const List&)
1594 {
1595     if (!thisObj->inherits(&DateInstance::info))
1596         return throwError(exec, TypeError);
1597
1598     const bool utc = false;
1599
1600     DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); 
1601     JSValue* v = thisDateObj->internalValue();
1602     double milli = v->toNumber(exec);
1603     if (isnan(milli))
1604         return jsNaN();
1605
1606     GregorianDateTime t;
1607     msToGregorianDateTime(milli, utc, t);
1608
1609     // NOTE: IE returns the full year even in getYear.
1610     return jsNumber(t.year);
1611 }
1612
1613 } // namespace KJS