Changeset 34872 in webkit for trunk/JavaScriptCore/kjs


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:
Location:
trunk/JavaScriptCore/kjs
Files:
8 edited
4 copied

Legend:

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

    r34863 r34872  
    4040#endif
    4141#include "CommonIdentifiers.cpp"
     42#include "DateConstructor.cpp"
     43#include "DateMath.cpp"
     44#include "DatePrototype.cpp"
    4245#include "date_object.cpp"
    43 #include "DateMath.cpp"
    4446#include "dtoa.cpp"
    4547#include "error_object.cpp"
  • 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
  • trunk/JavaScriptCore/kjs/DateConstructor.h

    r34860 r34872  
    11/*
    2  *  This file is part of the KDE libraries
    32 *  Copyright (C) 1999-2000 Harri Porten ([email protected])
     3 *  Copyright (C) 2008 Apple Inc. All rights reserved.
    44 *
    55 *  This library is free software; you can redistribute it and/or
     
    1919 */
    2020
    21 #ifndef DATE_OBJECT_H
    22 #define DATE_OBJECT_H
     21#ifndef DateConstructor_h
     22#define DateConstructor_h
    2323
    2424#include "JSFunction.h"
    25 #include "JSWrapperObject.h"
    26 #include "lookup.h"
    2725
    2826namespace KJS {
    2927
    30     struct GregorianDateTime;
     28    class DatePrototype;
    3129    class FunctionPrototype;
    32     class ObjectPrototype;
    33 
    34     class DateInstance : public JSWrapperObject {
    35     public:
    36         DateInstance(JSObject* prototype);
    37         virtual ~DateInstance();
    38 
    39         double internalNumber() const { return internalValue()->uncheckedGetNumber(); }
    40 
    41         bool getTime(GregorianDateTime&, int& offset) const;
    42         bool getUTCTime(GregorianDateTime&) const;
    43         bool getTime(double& milliseconds, int& offset) const;
    44         bool getUTCTime(double& milliseconds) const;
    45        
    46         static const ClassInfo info;
    47 
    48         void msToGregorianDateTime(double, bool outputIsUTC, GregorianDateTime&) const;
    49 
    50     private:
    51         virtual const ClassInfo* classInfo() const { return &info; }
    52 
    53         using JSWrapperObject::internalValue;
    54 
    55         struct Cache;
    56         mutable Cache* m_cache;
    57     };
    58 
    59     /**
    60      * @internal
    61      *
    62      * The initial value of Date.prototype (and thus all objects created
    63      * with the Date constructor
    64      */
    65     class DatePrototype : public DateInstance {
    66     public:
    67         DatePrototype(ExecState *, ObjectPrototype *);
    68         virtual bool getOwnPropertySlot(ExecState *, const Identifier &, PropertySlot&);
    69         virtual const ClassInfo *classInfo() const { return &info; }
    70         static const ClassInfo info;
    71     };
    7230
    7331    /**
     
    8442    };
    8543
    86 } // namespace
     44} // namespace KJS
    8745
    88 #endif
     46#endif // DateConstructor_h
  • trunk/JavaScriptCore/kjs/DateMath.cpp

    r34581 r34872  
    4343#include "DateMath.h"
    4444
     45#include "JSValue.h"
    4546#include <math.h>
    4647#include <stdint.h>
    47 #include <JSValue.h>
    48 
     48#include <time.h>
     49#include <wtf/ASCIICType.h>
    4950#include <wtf/Assertions.h>
     51#include <wtf/MathExtras.h>
     52#include <wtf/StringExtras.h>
    5053
    5154#if PLATFORM(DARWIN)
     
    526529}
    527530
     531static inline double ymdhmsToSeconds(long year, int mon, int day, int hour, int minute, int second)
     532{
     533    double days = (day - 32075)
     534        + floor(1461 * (year + 4800.0 + (mon - 14) / 12) / 4)
     535        + 367 * (mon - 2 - (mon - 14) / 12 * 12) / 12
     536        - floor(3 * ((year + 4900.0 + (mon - 14) / 12) / 100) / 4)
     537        - 2440588;
     538    return ((days * hoursPerDay + hour) * minutesPerHour + minute) * secondsPerMinute + second;
     539}
     540
     541// We follow the recommendation of RFC 2822 to consider all
     542// obsolete time zones not listed here equivalent to "-0000".
     543static const struct KnownZone {
     544#if !PLATFORM(WIN_OS)
     545    const
     546#endif
     547        char tzName[4];
     548    int tzOffset;
     549} known_zones[] = {
     550    { "UT", 0 },
     551    { "GMT", 0 },
     552    { "EST", -300 },
     553    { "EDT", -240 },
     554    { "CST", -360 },
     555    { "CDT", -300 },
     556    { "MST", -420 },
     557    { "MDT", -360 },
     558    { "PST", -480 },
     559    { "PDT", -420 }
     560};
     561
     562inline static void skipSpacesAndComments(const char*& s)
     563{
     564    int nesting = 0;
     565    char ch;
     566    while ((ch = *s)) {
     567        if (!isASCIISpace(ch)) {
     568            if (ch == '(')
     569                nesting++;
     570            else if (ch == ')' && nesting > 0)
     571                nesting--;
     572            else if (nesting == 0)
     573                break;
     574        }
     575        s++;
     576    }
     577}
     578
     579// returns 0-11 (Jan-Dec); -1 on failure
     580static int findMonth(const char* monthStr)
     581{
     582    ASSERT(monthStr);
     583    char needle[4];
     584    for (int i = 0; i < 3; ++i) {
     585        if (!*monthStr)
     586            return -1;
     587        needle[i] = static_cast<char>(toASCIILower(*monthStr++));
     588    }
     589    needle[3] = '\0';
     590    const char *haystack = "janfebmaraprmayjunjulaugsepoctnovdec";
     591    const char *str = strstr(haystack, needle);
     592    if (str) {
     593        int position = static_cast<int>(str - haystack);
     594        if (position % 3 == 0)
     595            return position / 3;
     596    }
     597    return -1;
     598}
     599
     600double parseDate(const UString &date)
     601{
     602    // This parses a date in the form:
     603    //     Tuesday, 09-Nov-99 23:12:40 GMT
     604    // or
     605    //     Sat, 01-Jan-2000 08:00:00 GMT
     606    // or
     607    //     Sat, 01 Jan 2000 08:00:00 GMT
     608    // or
     609    //     01 Jan 99 22:00 +0100    (exceptions in rfc822/rfc2822)
     610    // ### non RFC formats, added for Javascript:
     611    //     [Wednesday] January 09 1999 23:12:40 GMT
     612    //     [Wednesday] January 09 23:12:40 GMT 1999
     613    //
     614    // We ignore the weekday.
     615
     616    CString dateCString = date.UTF8String();
     617    const char *dateString = dateCString.c_str();
     618     
     619    // Skip leading space
     620    skipSpacesAndComments(dateString);
     621
     622    long month = -1;
     623    const char *wordStart = dateString;
     624    // Check contents of first words if not number
     625    while (*dateString && !isASCIIDigit(*dateString)) {
     626        if (isASCIISpace(*dateString) || *dateString == '(') {
     627            if (dateString - wordStart >= 3)
     628                month = findMonth(wordStart);
     629            skipSpacesAndComments(dateString);
     630            wordStart = dateString;
     631        } else
     632           dateString++;
     633    }
     634
     635    // Missing delimiter between month and day (like "January29")?
     636    if (month == -1 && wordStart != dateString)
     637        month = findMonth(wordStart);
     638
     639    skipSpacesAndComments(dateString);
     640
     641    if (!*dateString)
     642        return NaN;
     643
     644    // ' 09-Nov-99 23:12:40 GMT'
     645    char *newPosStr;
     646    errno = 0;
     647    long day = strtol(dateString, &newPosStr, 10);
     648    if (errno)
     649        return NaN;
     650    dateString = newPosStr;
     651
     652    if (!*dateString)
     653        return NaN;
     654
     655    if (day < 0)
     656        return NaN;
     657
     658    long year = 0;
     659    if (day > 31) {
     660        // ### where is the boundary and what happens below?
     661        if (*dateString != '/')
     662            return NaN;
     663        // looks like a YYYY/MM/DD date
     664        if (!*++dateString)
     665            return NaN;
     666        year = day;
     667        month = strtol(dateString, &newPosStr, 10) - 1;
     668        if (errno)
     669            return NaN;
     670        dateString = newPosStr;
     671        if (*dateString++ != '/' || !*dateString)
     672            return NaN;
     673        day = strtol(dateString, &newPosStr, 10);
     674        if (errno)
     675            return NaN;
     676        dateString = newPosStr;
     677    } else if (*dateString == '/' && month == -1) {
     678        dateString++;
     679        // This looks like a MM/DD/YYYY date, not an RFC date.
     680        month = day - 1; // 0-based
     681        day = strtol(dateString, &newPosStr, 10);
     682        if (errno)
     683            return NaN;
     684        if (day < 1 || day > 31)
     685            return NaN;
     686        dateString = newPosStr;
     687        if (*dateString == '/')
     688            dateString++;
     689        if (!*dateString)
     690            return NaN;
     691     } else {
     692        if (*dateString == '-')
     693            dateString++;
     694
     695        skipSpacesAndComments(dateString);
     696
     697        if (*dateString == ',')
     698            dateString++;
     699
     700        if (month == -1) { // not found yet
     701            month = findMonth(dateString);
     702            if (month == -1)
     703                return NaN;
     704
     705            while (*dateString && *dateString != '-' && *dateString != ',' && !isASCIISpace(*dateString))
     706                dateString++;
     707
     708            if (!*dateString)
     709                return NaN;
     710
     711            // '-99 23:12:40 GMT'
     712            if (*dateString != '-' && *dateString != '/' && *dateString != ',' && !isASCIISpace(*dateString))
     713                return NaN;
     714            dateString++;
     715        }
     716    }
     717
     718    if (month < 0 || month > 11)
     719        return NaN;
     720
     721    // '99 23:12:40 GMT'
     722    if (year <= 0 && *dateString) {
     723        year = strtol(dateString, &newPosStr, 10);
     724        if (errno)
     725            return NaN;
     726    }
     727   
     728    // Don't fail if the time is missing.
     729    long hour = 0;
     730    long minute = 0;
     731    long second = 0;
     732    if (!*newPosStr)
     733        dateString = newPosStr;
     734    else {
     735        // ' 23:12:40 GMT'
     736        if (!(isASCIISpace(*newPosStr) || *newPosStr == ',')) {
     737            if (*newPosStr != ':')
     738                return NaN;
     739            // There was no year; the number was the hour.
     740            year = -1;
     741        } else {
     742            // in the normal case (we parsed the year), advance to the next number
     743            dateString = ++newPosStr;
     744            skipSpacesAndComments(dateString);
     745        }
     746
     747        hour = strtol(dateString, &newPosStr, 10);
     748        // Do not check for errno here since we want to continue
     749        // even if errno was set becasue we are still looking
     750        // for the timezone!
     751
     752        // Read a number? If not, this might be a timezone name.
     753        if (newPosStr != dateString) {
     754            dateString = newPosStr;
     755
     756            if (hour < 0 || hour > 23)
     757                return NaN;
     758
     759            if (!*dateString)
     760                return NaN;
     761
     762            // ':12:40 GMT'
     763            if (*dateString++ != ':')
     764                return NaN;
     765
     766            minute = strtol(dateString, &newPosStr, 10);
     767            if (errno)
     768                return NaN;
     769            dateString = newPosStr;
     770
     771            if (minute < 0 || minute > 59)
     772                return NaN;
     773
     774            // ':40 GMT'
     775            if (*dateString && *dateString != ':' && !isASCIISpace(*dateString))
     776                return NaN;
     777
     778            // seconds are optional in rfc822 + rfc2822
     779            if (*dateString ==':') {
     780                dateString++;
     781
     782                second = strtol(dateString, &newPosStr, 10);
     783                if (errno)
     784                    return NaN;
     785                dateString = newPosStr;
     786           
     787                if (second < 0 || second > 59)
     788                    return NaN;
     789            }
     790
     791            skipSpacesAndComments(dateString);
     792
     793            if (strncasecmp(dateString, "AM", 2) == 0) {
     794                if (hour > 12)
     795                    return NaN;
     796                if (hour == 12)
     797                    hour = 0;
     798                dateString += 2;
     799                skipSpacesAndComments(dateString);
     800            } else if (strncasecmp(dateString, "PM", 2) == 0) {
     801                if (hour > 12)
     802                    return NaN;
     803                if (hour != 12)
     804                    hour += 12;
     805                dateString += 2;
     806                skipSpacesAndComments(dateString);
     807            }
     808        }
     809    }
     810
     811    bool haveTZ = false;
     812    int offset = 0;
     813
     814    // Don't fail if the time zone is missing.
     815    // Some websites omit the time zone (4275206).
     816    if (*dateString) {
     817        if (strncasecmp(dateString, "GMT", 3) == 0 || strncasecmp(dateString, "UTC", 3) == 0) {
     818            dateString += 3;
     819            haveTZ = true;
     820        }
     821
     822        if (*dateString == '+' || *dateString == '-') {
     823            long o = strtol(dateString, &newPosStr, 10);
     824            if (errno)
     825                return NaN;
     826            dateString = newPosStr;
     827
     828            if (o < -9959 || o > 9959)
     829                return NaN;
     830
     831            int sgn = (o < 0) ? -1 : 1;
     832            o = abs(o);
     833            if (*dateString != ':') {
     834                offset = ((o / 100) * 60 + (o % 100)) * sgn;
     835            } else { // GMT+05:00
     836                long o2 = strtol(dateString, &newPosStr, 10);
     837                if (errno)
     838                    return NaN;
     839                dateString = newPosStr;
     840                offset = (o * 60 + o2) * sgn;
     841            }
     842            haveTZ = true;
     843        } else {
     844            for (int i = 0; i < int(sizeof(known_zones) / sizeof(KnownZone)); i++) {
     845                if (0 == strncasecmp(dateString, known_zones[i].tzName, strlen(known_zones[i].tzName))) {
     846                    offset = known_zones[i].tzOffset;
     847                    dateString += strlen(known_zones[i].tzName);
     848                    haveTZ = true;
     849                    break;
     850                }
     851            }
     852        }
     853    }
     854
     855    skipSpacesAndComments(dateString);
     856
     857    if (*dateString && year == -1) {
     858        year = strtol(dateString, &newPosStr, 10);
     859        if (errno)
     860            return NaN;
     861        dateString = newPosStr;
     862    }
     863     
     864    skipSpacesAndComments(dateString);
     865     
     866    // Trailing garbage
     867    if (*dateString)
     868        return NaN;
     869
     870    // Y2K: Handle 2 digit years.
     871    if (year >= 0 && year < 100) {
     872        if (year < 50)
     873            year += 2000;
     874        else
     875            year += 1900;
     876    }
     877
     878    // fall back to local timezone
     879    if (!haveTZ) {
     880        GregorianDateTime t;
     881        t.monthDay = day;
     882        t.month = month;
     883        t.year = year - 1900;
     884        t.isDST = -1;
     885        t.second = second;
     886        t.minute = minute;
     887        t.hour = hour;
     888
     889        // Use our gregorianDateTimeToMS() rather than mktime() as the latter can't handle the full year range.
     890        return gregorianDateTimeToMS(t, 0, false);
     891    }
     892
     893    return (ymdhmsToSeconds(year, month + 1, day, hour, minute, second) - (offset * 60.0)) * msPerSecond;
     894}
     895
     896double timeClip(double t)
     897{
     898    if (!isfinite(t))
     899        return NaN;
     900    if (fabs(t) > 8.64E15)
     901        return NaN;
     902    return trunc(t);
     903}
     904
     905UString formatDate(const GregorianDateTime &t)
     906{
     907    char buffer[100];
     908    snprintf(buffer, sizeof(buffer), "%s %s %02d %04d",
     909        weekdayName[(t.weekDay + 6) % 7],
     910        monthName[t.month], t.monthDay, t.year + 1900);
     911    return buffer;
     912}
     913
     914UString formatDateUTCVariant(const GregorianDateTime &t)
     915{
     916    char buffer[100];
     917    snprintf(buffer, sizeof(buffer), "%s, %02d %s %04d",
     918        weekdayName[(t.weekDay + 6) % 7],
     919        t.monthDay, monthName[t.month], t.year + 1900);
     920    return buffer;
     921}
     922
     923UString formatTime(const GregorianDateTime &t, bool utc)
     924{
     925    char buffer[100];
     926    if (utc) {
     927        snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d GMT", t.hour, t.minute, t.second);
     928    } else {
     929        int offset = abs(gmtoffset(t));
     930        char tzname[70];
     931        struct tm gtm = t;
     932        strftime(tzname, sizeof(tzname), "%Z", &gtm);
     933
     934        if (tzname[0]) {
     935            snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d GMT%c%02d%02d (%s)",
     936                t.hour, t.minute, t.second,
     937                gmtoffset(t) < 0 ? '-' : '+', offset / (60*60), (offset / 60) % 60, tzname);
     938        } else {
     939            snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d GMT%c%02d%02d",
     940                t.hour, t.minute, t.second,
     941                gmtoffset(t) < 0 ? '-' : '+', offset / (60*60), (offset / 60) % 60);
     942        }
     943    }
     944    return UString(buffer);
     945}
     946
    528947} // namespace KJS
  • trunk/JavaScriptCore/kjs/DateMath.h

    r33930 r34872  
    4848namespace KJS {
    4949
     50class UString;
    5051struct GregorianDateTime;
    5152
     
    5859double getCurrentUTCTimeWithMicroseconds();
    5960void getLocalTime(const time_t*, tm*);
     61
     62// Not really math related, but this is currently the only shared place to put these. 
     63double parseDate(const UString&);
     64double timeClip(double);
     65UString formatDate(const GregorianDateTime&);
     66UString formatDateUTCVariant(const GregorianDateTime&);
     67UString formatTime(const GregorianDateTime&, bool inputIsUTC);
    6068
    6169
     
    174182};
    175183
    176 }   //namespace KJS
     184static inline int gmtoffset(const GregorianDateTime& t)
     185{
     186    return t.utcOffset;
     187}
     188
     189} // namespace KJS
    177190
    178191#endif // DateMath_h
  • trunk/JavaScriptCore/kjs/DatePrototype.cpp

    r34860 r34872  
    2121
    2222#include "config.h"
    23 #include "date_object.h"
     23#include "DatePrototype.h"
    2424
    2525#include "DateMath.h"
    2626#include "JSString.h"
    2727#include "ObjectPrototype.h"
     28#include "date_object.h"
    2829#include "error_object.h"
    29 #include "operations.h"
    3030#include <float.h>
    3131#include <limits.h>
    3232#include <locale.h>
    3333#include <math.h>
    34 #include <stdio.h>
    35 #include <stdlib.h>
    36 #include <string.h>
    3734#include <time.h>
    38 #include <wtf/ASCIICType.h>
    3935#include <wtf/Assertions.h>
    4036#include <wtf/MathExtras.h>
     
    113109}
    114110
    115 #include "date_object.lut.h"
     111#include "DatePrototype.lut.h"
    116112
    117113namespace 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 };
    133114
    134115#if PLATFORM(MAC)
     
    238219#endif // PLATFORM(WIN_OS)
    239220
    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 
    282221// Converts a list of arguments sent to a Date member function into milliseconds, updating
    283222// ms (representing milliseconds) and t (representing the rest of the date structure) appropriately.
     
    359298}
    360299
    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 -----------------------------
     300
     301
     302
    448303
    449304const ClassInfo DatePrototype::info = {"Date", &DateInstance::info, 0, ExecState::dateTable};
     
    512367}
    513368
    514 // ------------------------------ DateConstructor --------------------------------
    515 
    516 // TODO: MakeTime (15.9.11.1) etc. ?
    517 
    518 static JSValue* dateParse(ExecState*, JSObject*, JSValue*, const ArgList&);
    519 static JSValue* dateNow(ExecState*, JSObject*, JSValue*, const ArgList&);
    520 static JSValue* dateUTC(ExecState*, JSObject*, JSValue*, const ArgList&);
    521 
    522 DateConstructor::DateConstructor(ExecState* exec, FunctionPrototype* funcProto, DatePrototype* dateProto)
    523   : InternalFunction(funcProto, Identifier(exec, dateProto->classInfo()->className))
    524 {
    525   putDirect(exec->propertyNames().prototype, dateProto, DontEnum|DontDelete|ReadOnly);
    526   putDirectFunction(new (exec) PrototypeFunction(exec, funcProto, 1, exec->propertyNames().parse, dateParse), DontEnum);
    527   putDirectFunction(new (exec) PrototypeFunction(exec, funcProto, 7, exec->propertyNames().UTC, dateUTC), DontEnum);
    528   putDirectFunction(new (exec) PrototypeFunction(exec, funcProto, 0, exec->propertyNames().now, dateNow), DontEnum);
    529   putDirect(exec, exec->propertyNames().length, 7, ReadOnly | DontEnum | DontDelete);
    530 }
    531 
    532 // ECMA 15.9.3
    533 static JSObject* constructDate(ExecState* exec, JSObject*, const ArgList& args)
    534 {
    535   int numArgs = args.size();
    536 
    537   double value;
    538 
    539   if (numArgs == 0) { // new Date() ECMA 15.9.3.3
    540     value = getCurrentUTCTime();
    541   } else if (numArgs == 1) {
    542     if (args[0]->isObject(&DateInstance::info))
    543       value = static_cast<DateInstance*>(args[0])->internalNumber();
    544     else {
    545       JSValue* primitive = args[0]->toPrimitive(exec);
    546       if (primitive->isString())
    547         value = parseDate(primitive->getString());
    548       else
    549         value = primitive->toNumber(exec);
    550     }
    551   } else {
    552     if (isnan(args[0]->toNumber(exec))
    553         || isnan(args[1]->toNumber(exec))
    554         || (numArgs >= 3 && isnan(args[2]->toNumber(exec)))
    555         || (numArgs >= 4 && isnan(args[3]->toNumber(exec)))
    556         || (numArgs >= 5 && isnan(args[4]->toNumber(exec)))
    557         || (numArgs >= 6 && isnan(args[5]->toNumber(exec)))
    558         || (numArgs >= 7 && isnan(args[6]->toNumber(exec)))) {
    559       value = NaN;
    560     } else {
    561       GregorianDateTime t;
    562       int year = args[0]->toInt32(exec);
    563       t.year = (year >= 0 && year <= 99) ? year : year - 1900;
    564       t.month = args[1]->toInt32(exec);
    565       t.monthDay = (numArgs >= 3) ? args[2]->toInt32(exec) : 1;
    566       t.hour = args[3]->toInt32(exec);
    567       t.minute = args[4]->toInt32(exec);
    568       t.second = args[5]->toInt32(exec);
    569       t.isDST = -1;
    570       double ms = (numArgs >= 7) ? args[6]->toNumber(exec) : 0;
    571       value = gregorianDateTimeToMS(t, ms, false);
    572     }
    573   }
    574  
    575   DateInstance* ret = new (exec) DateInstance(exec->lexicalGlobalObject()->datePrototype());
    576   ret->setInternalValue(jsNumber(exec, timeClip(value)));
    577   return ret;
    578 }
    579 
    580 ConstructType DateConstructor::getConstructData(ConstructData& constructData)
    581 {
    582     constructData.native.function = constructDate;
    583     return ConstructTypeNative;
    584 }
    585 
    586 // ECMA 15.9.2
    587 static JSValue* callDate(ExecState* exec, JSObject*, JSValue*, const ArgList&)
    588 {
    589     time_t localTime = time(0);
    590     tm localTM;
    591     getLocalTime(&localTime, &localTM);
    592     GregorianDateTime ts(localTM);
    593     return jsString(exec, formatDate(ts) + " " + formatTime(ts, false));
    594 }
    595 
    596 CallType DateConstructor::getCallData(CallData& callData)
    597 {
    598     callData.native.function = callDate;
    599     return CallTypeNative;
    600 }
    601 
    602 static JSValue* dateParse(ExecState* exec, JSObject*, JSValue*, const ArgList& args)
    603 {
    604     return jsNumber(exec, parseDate(args[0]->toString(exec)));
    605 }
    606 
    607 static JSValue* dateNow(ExecState* exec, JSObject*, JSValue*, const ArgList&)
    608 {
    609     return jsNumber(exec, getCurrentUTCTime());
    610 }
    611 
    612 static JSValue* dateUTC(ExecState* exec, JSObject*, JSValue*, const ArgList& args)
    613 {
    614     int n = args.size();
    615     if (isnan(args[0]->toNumber(exec))
    616             || isnan(args[1]->toNumber(exec))
    617             || (n >= 3 && isnan(args[2]->toNumber(exec)))
    618             || (n >= 4 && isnan(args[3]->toNumber(exec)))
    619             || (n >= 5 && isnan(args[4]->toNumber(exec)))
    620             || (n >= 6 && isnan(args[5]->toNumber(exec)))
    621             || (n >= 7 && isnan(args[6]->toNumber(exec)))) {
    622         return jsNaN(exec);
    623     }
    624 
    625     GregorianDateTime t;
    626     int year = args[0]->toInt32(exec);
    627     t.year = (year >= 0 && year <= 99) ? year : year - 1900;
    628     t.month = args[1]->toInt32(exec);
    629     t.monthDay = (n >= 3) ? args[2]->toInt32(exec) : 1;
    630     t.hour = args[3]->toInt32(exec);
    631     t.minute = args[4]->toInt32(exec);
    632     t.second = args[5]->toInt32(exec);
    633     double ms = (n >= 7) ? args[6]->toNumber(exec) : 0;
    634     return jsNumber(exec, gregorianDateTimeToMS(t, ms, true));
    635 }
    636 
    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 
    1015369// Functions
    1016370
  • trunk/JavaScriptCore/kjs/DatePrototype.h

    r34860 r34872  
    11/*
    2  *  This file is part of the KDE libraries
    32 *  Copyright (C) 1999-2000 Harri Porten ([email protected])
     3 *  Copyright (C) 2008 Apple Inc. All rights reserved.
    44 *
    55 *  This library is free software; you can redistribute it and/or
     
    1919 */
    2020
    21 #ifndef DATE_OBJECT_H
    22 #define DATE_OBJECT_H
     21#ifndef DatePrototype_h
     22#define DatePrototype_h
    2323
    24 #include "JSFunction.h"
    25 #include "JSWrapperObject.h"
    26 #include "lookup.h"
     24#include "date_object.h"
    2725
    2826namespace KJS {
    2927
    30     struct GregorianDateTime;
    31     class FunctionPrototype;
    3228    class ObjectPrototype;
    33 
    34     class DateInstance : public JSWrapperObject {
    35     public:
    36         DateInstance(JSObject* prototype);
    37         virtual ~DateInstance();
    38 
    39         double internalNumber() const { return internalValue()->uncheckedGetNumber(); }
    40 
    41         bool getTime(GregorianDateTime&, int& offset) const;
    42         bool getUTCTime(GregorianDateTime&) const;
    43         bool getTime(double& milliseconds, int& offset) const;
    44         bool getUTCTime(double& milliseconds) const;
    45        
    46         static const ClassInfo info;
    47 
    48         void msToGregorianDateTime(double, bool outputIsUTC, GregorianDateTime&) const;
    49 
    50     private:
    51         virtual const ClassInfo* classInfo() const { return &info; }
    52 
    53         using JSWrapperObject::internalValue;
    54 
    55         struct Cache;
    56         mutable Cache* m_cache;
    57     };
    5829
    5930    /**
     
    7142    };
    7243
    73     /**
    74      * @internal
    75      *
    76      * The initial value of the the global variable's "Date" property
    77      */
    78     class DateConstructor : public InternalFunction {
    79     public:
    80         DateConstructor(ExecState*, FunctionPrototype*, DatePrototype*);
    81     private:
    82         virtual ConstructType getConstructData(ConstructData&);
    83         virtual CallType getCallData(CallData&);
    84     };
     44} // namespace KJS
    8545
    86 } // namespace
    87 
    88 #endif
     46#endif // DatePrototype_h
  • trunk/JavaScriptCore/kjs/JSGlobalObject.cpp

    r34863 r34872  
    3636#include "BooleanPrototype.h"
    3737#include "CodeBlock.h"
     38#include "DateConstructor.h"
     39#include "DatePrototype.h"
    3840#include "FunctionConstructor.h"
    3941#include "FunctionPrototype.h"
     
    4951#include "StringConstructor.h"
    5052#include "StringPrototype.h"
    51 #include "date_object.h"
    5253#include "debugger.h"
    5354#include "error_object.h"
  • trunk/JavaScriptCore/kjs/JSObject.cpp

    r34855 r34872  
    2626#include "JSObject.h"
    2727
     28#include "DatePrototype.h"
    2829#include "ObjectPrototype.h"
    2930#include "PropertyNameArray.h"
    30 #include "date_object.h"
    3131#include "error_object.h"
    3232#include "nodes.h"
  • trunk/JavaScriptCore/kjs/date_object.cpp

    r34857 r34872  
    2424
    2525#include "DateMath.h"
    26 #include "JSString.h"
    27 #include "ObjectPrototype.h"
    28 #include "error_object.h"
    29 #include "operations.h"
    30 #include <float.h>
    31 #include <limits.h>
    32 #include <locale.h>
    3326#include <math.h>
    34 #include <stdio.h>
    35 #include <stdlib.h>
    36 #include <string.h>
    37 #include <time.h>
    38 #include <wtf/ASCIICType.h>
    39 #include <wtf/Assertions.h>
    4027#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
    51 
    52 #if HAVE(SYS_TIME_H)
    53 #include <sys/time.h>
    54 #endif
    55 
    56 #if HAVE(SYS_TIMEB_H)
    57 #include <sys/timeb.h>
    58 #endif
    59 
    60 #if PLATFORM(MAC)
    61 #include <CoreFoundation/CoreFoundation.h>
    62 #endif
    63 
    64 using namespace WTF;
    6528
    6629namespace 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 }
    12630
    12731struct DateInstance::Cache {
     
    13135    GregorianDateTime m_cachedGregorianDateTimeUTC;
    13236};
    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 ------------------------------
    36237
    36338const ClassInfo DateInstance::info = {"Date", 0, 0, 0};
     
    439114}
    440115
    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 --------------------------------
    515 
    516 // TODO: MakeTime (15.9.11.1) etc. ?
    517 
    518 static JSValue* dateParse(ExecState*, JSObject*, JSValue*, const ArgList&);
    519 static JSValue* dateNow(ExecState*, JSObject*, JSValue*, const ArgList&);
    520 static JSValue* dateUTC(ExecState*, JSObject*, JSValue*, const ArgList&);
    521 
    522 DateConstructor::DateConstructor(ExecState* exec, FunctionPrototype* funcProto, DatePrototype* dateProto)
    523   : InternalFunction(funcProto, Identifier(exec, dateProto->classInfo()->className))
    524 {
    525   putDirect(exec->propertyNames().prototype, dateProto, DontEnum|DontDelete|ReadOnly);
    526   putDirectFunction(new (exec) PrototypeFunction(exec, funcProto, 1, exec->propertyNames().parse, dateParse), DontEnum);
    527   putDirectFunction(new (exec) PrototypeFunction(exec, funcProto, 7, exec->propertyNames().UTC, dateUTC), DontEnum);
    528   putDirectFunction(new (exec) PrototypeFunction(exec, funcProto, 0, exec->propertyNames().now, dateNow), DontEnum);
    529   putDirect(exec, exec->propertyNames().length, 7, ReadOnly | DontEnum | DontDelete);
    530 }
    531 
    532 // ECMA 15.9.3
    533 static JSObject* constructDate(ExecState* exec, JSObject*, const ArgList& args)
    534 {
    535   int numArgs = args.size();
    536 
    537   double value;
    538 
    539   if (numArgs == 0) { // new Date() ECMA 15.9.3.3
    540     value = getCurrentUTCTime();
    541   } else if (numArgs == 1) {
    542     if (args[0]->isObject(&DateInstance::info))
    543       value = static_cast<DateInstance*>(args[0])->internalNumber();
    544     else {
    545       JSValue* primitive = args[0]->toPrimitive(exec);
    546       if (primitive->isString())
    547         value = parseDate(primitive->getString());
    548       else
    549         value = primitive->toNumber(exec);
    550     }
    551   } else {
    552     if (isnan(args[0]->toNumber(exec))
    553         || isnan(args[1]->toNumber(exec))
    554         || (numArgs >= 3 && isnan(args[2]->toNumber(exec)))
    555         || (numArgs >= 4 && isnan(args[3]->toNumber(exec)))
    556         || (numArgs >= 5 && isnan(args[4]->toNumber(exec)))
    557         || (numArgs >= 6 && isnan(args[5]->toNumber(exec)))
    558         || (numArgs >= 7 && isnan(args[6]->toNumber(exec)))) {
    559       value = NaN;
    560     } else {
    561       GregorianDateTime t;
    562       int year = args[0]->toInt32(exec);
    563       t.year = (year >= 0 && year <= 99) ? year : year - 1900;
    564       t.month = args[1]->toInt32(exec);
    565       t.monthDay = (numArgs >= 3) ? args[2]->toInt32(exec) : 1;
    566       t.hour = args[3]->toInt32(exec);
    567       t.minute = args[4]->toInt32(exec);
    568       t.second = args[5]->toInt32(exec);
    569       t.isDST = -1;
    570       double ms = (numArgs >= 7) ? args[6]->toNumber(exec) : 0;
    571       value = gregorianDateTimeToMS(t, ms, false);
    572     }
    573   }
    574  
    575   DateInstance* ret = new (exec) DateInstance(exec->lexicalGlobalObject()->datePrototype());
    576   ret->setInternalValue(jsNumber(exec, timeClip(value)));
    577   return ret;
    578 }
    579 
    580 ConstructType DateConstructor::getConstructData(ConstructData& constructData)
    581 {
    582     constructData.native.function = constructDate;
    583     return ConstructTypeNative;
    584 }
    585 
    586 // ECMA 15.9.2
    587 static JSValue* callDate(ExecState* exec, JSObject*, JSValue*, const ArgList&)
    588 {
    589     time_t localTime = time(0);
    590     tm localTM;
    591     getLocalTime(&localTime, &localTM);
    592     GregorianDateTime ts(localTM);
    593     return jsString(exec, formatDate(ts) + " " + formatTime(ts, false));
    594 }
    595 
    596 CallType DateConstructor::getCallData(CallData& callData)
    597 {
    598     callData.native.function = callDate;
    599     return CallTypeNative;
    600 }
    601 
    602 static JSValue* dateParse(ExecState* exec, JSObject*, JSValue*, const ArgList& args)
    603 {
    604     return jsNumber(exec, parseDate(args[0]->toString(exec)));
    605 }
    606 
    607 static JSValue* dateNow(ExecState* exec, JSObject*, JSValue*, const ArgList&)
    608 {
    609     return jsNumber(exec, getCurrentUTCTime());
    610 }
    611 
    612 static JSValue* dateUTC(ExecState* exec, JSObject*, JSValue*, const ArgList& args)
    613 {
    614     int n = args.size();
    615     if (isnan(args[0]->toNumber(exec))
    616             || isnan(args[1]->toNumber(exec))
    617             || (n >= 3 && isnan(args[2]->toNumber(exec)))
    618             || (n >= 4 && isnan(args[3]->toNumber(exec)))
    619             || (n >= 5 && isnan(args[4]->toNumber(exec)))
    620             || (n >= 6 && isnan(args[5]->toNumber(exec)))
    621             || (n >= 7 && isnan(args[6]->toNumber(exec)))) {
    622         return jsNaN(exec);
    623     }
    624 
    625     GregorianDateTime t;
    626     int year = args[0]->toInt32(exec);
    627     t.year = (year >= 0 && year <= 99) ? year : year - 1900;
    628     t.month = args[1]->toInt32(exec);
    629     t.monthDay = (n >= 3) ? args[2]->toInt32(exec) : 1;
    630     t.hour = args[3]->toInt32(exec);
    631     t.minute = args[4]->toInt32(exec);
    632     t.second = args[5]->toInt32(exec);
    633     double ms = (n >= 7) ? args[6]->toNumber(exec) : 0;
    634     return jsNumber(exec, gregorianDateTimeToMS(t, ms, true));
    635 }
    636 
    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 
    1711116} // namespace KJS
  • trunk/JavaScriptCore/kjs/date_object.h

    r34754 r34872  
    11/*
    2  *  This file is part of the KDE libraries
    32 *  Copyright (C) 1999-2000 Harri Porten ([email protected])
     3 *  Copyright (C) 2008 Apple Inc. All rights reserved.
    44 *
    55 *  This library is free software; you can redistribute it and/or
     
    2222#define DATE_OBJECT_H
    2323
    24 #include "JSFunction.h"
    2524#include "JSWrapperObject.h"
    26 #include "lookup.h"
    2725
    2826namespace KJS {
     
    5755    };
    5856
    59     /**
    60      * @internal
    61      *
    62      * The initial value of Date.prototype (and thus all objects created
    63      * with the Date constructor
    64      */
    65     class DatePrototype : public DateInstance {
    66     public:
    67         DatePrototype(ExecState *, ObjectPrototype *);
    68         virtual bool getOwnPropertySlot(ExecState *, const Identifier &, PropertySlot&);
    69         virtual const ClassInfo *classInfo() const { return &info; }
    70         static const ClassInfo info;
    71     };
    72 
    73     /**
    74      * @internal
    75      *
    76      * The initial value of the the global variable's "Date" property
    77      */
    78     class DateConstructor : public InternalFunction {
    79     public:
    80         DateConstructor(ExecState*, FunctionPrototype*, DatePrototype*);
    81     private:
    82         virtual ConstructType getConstructData(ConstructData&);
    83         virtual CallType getCallData(CallData&);
    84     };
    85 
    86 } // namespace
     57} // namespace KJS
    8758
    8859#endif
  • trunk/JavaScriptCore/kjs/internal.cpp

    r34863 r34872  
    3131#include "StringPrototype.h"
    3232#include "collector.h"
    33 #include "date_object.h"
    3433#include "debugger.h"
    3534#include "error_object.h"
Note: See TracChangeset for help on using the changeset viewer.