Ignore:
Timestamp:
Jun 29, 2008, 12:53:42 PM (17 years ago)
Author:
[email protected]
Message:

2008-06-29 Sam Weinig <[email protected]>

Rubber-stamped by Oliver Hunt.

Splits DateConstructor and DatePrototype out of date_object.h/cpp
Moves shared Date code into DateMath.

  • DerivedSources.make:
  • GNUmakefile.am:
  • JavaScriptCore.pri:
  • JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • JavaScriptCoreSources.bkl:
  • kjs/AllInOneFile.cpp:
  • kjs/DateConstructor.cpp: Copied from kjs/date_object.cpp.
  • kjs/DateConstructor.h: Copied from kjs/date_object.h.
  • kjs/DateMath.cpp: (KJS::ymdhmsToSeconds): (KJS::): (KJS::skipSpacesAndComments): (KJS::findMonth): (KJS::parseDate): (KJS::timeClip): (KJS::formatDate): (KJS::formatDateUTCVariant): (KJS::formatTime):
  • kjs/DateMath.h: (KJS::gmtoffset):
  • kjs/DatePrototype.cpp: Copied from kjs/date_object.cpp.
  • kjs/DatePrototype.h: Copied from kjs/date_object.h.
  • kjs/JSGlobalObject.cpp:
  • kjs/JSObject.cpp:
  • kjs/date_object.cpp:
  • kjs/date_object.h:
  • kjs/internal.cpp:
File:
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/kjs/DateConstructor.cpp

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