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