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