Changeset 34872 in webkit for trunk/JavaScriptCore/kjs
- Timestamp:
- Jun 29, 2008, 12:53:42 PM (17 years ago)
- Location:
- trunk/JavaScriptCore/kjs
- Files:
-
- 8 edited
- 4 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/JavaScriptCore/kjs/AllInOneFile.cpp
r34863 r34872 40 40 #endif 41 41 #include "CommonIdentifiers.cpp" 42 #include "DateConstructor.cpp" 43 #include "DateMath.cpp" 44 #include "DatePrototype.cpp" 42 45 #include "date_object.cpp" 43 #include "DateMath.cpp"44 46 #include "dtoa.cpp" 45 47 #include "error_object.cpp" -
trunk/JavaScriptCore/kjs/DateConstructor.cpp
r34860 r34872 21 21 22 22 #include "config.h" 23 #include " date_object.h"23 #include "DateConstructor.h" 24 24 25 25 #include "DateMath.h" 26 #include "DatePrototype.h" 26 27 #include "JSString.h" 27 28 #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" 33 30 #include <math.h> 34 #include <stdio.h>35 #include <stdlib.h>36 #include <string.h>37 31 #include <time.h> 38 #include <wtf/ASCIICType.h>39 #include <wtf/Assertions.h>40 32 #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 #endif47 48 #if HAVE(SYS_PARAM_H)49 #include <sys/param.h>50 #endif51 33 52 34 #if HAVE(SYS_TIME_H) … … 58 40 #endif 59 41 60 #if PLATFORM(MAC)61 #include <CoreFoundation/CoreFoundation.h>62 #endif63 64 using namespace WTF;65 66 42 namespace 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 #else200 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 needed208 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 formatting216 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 buffer224 if (yearNeedsOffset && format != LocaleTime) {225 static const int yearLen = 5; // FIXME will be a problem in the year 10,000226 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", >m);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, updating283 // 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 them294 if (numArgs > maxArgs)295 numArgs = maxArgs;296 297 // hours298 if (maxArgs >= 4 && idx < numArgs) {299 t->hour = 0;300 milliseconds += args[idx++]->toInt32(exec, ok) * msPerHour;301 }302 303 // minutes304 if (maxArgs >= 3 && idx < numArgs && ok) {305 t->minute = 0;306 milliseconds += args[idx++]->toInt32(exec, ok) * msPerMinute;307 }308 309 // seconds310 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 // milliseconds319 if (idx < numArgs) {320 double millis = args[idx]->toNumber(exec);321 ok = isfinite(millis);322 milliseconds += millis;323 } else324 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, updating331 // 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 them341 if (numArgs > maxArgs)342 numArgs = maxArgs;343 344 // years345 if (maxArgs >= 3 && idx < numArgs)346 t->year = args[idx++]->toInt32(exec, ok) - 1900;347 348 // months349 if (maxArgs >= 2 && idx < numArgs && ok)350 t->month = args[idx++]->toInt32(exec, ok);351 352 // days353 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) const377 {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) const400 {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) const411 {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) const421 {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) const433 {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.h452 FIXME: We could use templates to simplify the UTC variants.453 @begin dateTable454 toString dateProtoFuncToString DontEnum|Function 0455 toUTCString dateProtoFuncToUTCString DontEnum|Function 0456 toDateString dateProtoFuncToDateString DontEnum|Function 0457 toTimeString dateProtoFuncToTimeString DontEnum|Function 0458 toLocaleString dateProtoFuncToLocaleString DontEnum|Function 0459 toLocaleDateString dateProtoFuncToLocaleDateString DontEnum|Function 0460 toLocaleTimeString dateProtoFuncToLocaleTimeString DontEnum|Function 0461 valueOf dateProtoFuncValueOf DontEnum|Function 0462 getTime dateProtoFuncGetTime DontEnum|Function 0463 getFullYear dateProtoFuncGetFullYear DontEnum|Function 0464 getUTCFullYear dateProtoFuncGetUTCFullYear DontEnum|Function 0465 toGMTString dateProtoFuncToGMTString DontEnum|Function 0466 getMonth dateProtoFuncGetMonth DontEnum|Function 0467 getUTCMonth dateProtoFuncGetUTCMonth DontEnum|Function 0468 getDate dateProtoFuncGetDate DontEnum|Function 0469 getUTCDate dateProtoFuncGetUTCDate DontEnum|Function 0470 getDay dateProtoFuncGetDay DontEnum|Function 0471 getUTCDay dateProtoFuncGetUTCDay DontEnum|Function 0472 getHours dateProtoFuncGetHours DontEnum|Function 0473 getUTCHours dateProtoFuncGetUTCHours DontEnum|Function 0474 getMinutes dateProtoFuncGetMinutes DontEnum|Function 0475 getUTCMinutes dateProtoFuncGetUTCMinutes DontEnum|Function 0476 getSeconds dateProtoFuncGetSeconds DontEnum|Function 0477 getUTCSeconds dateProtoFuncGetUTCSeconds DontEnum|Function 0478 getMilliseconds dateProtoFuncGetMilliSeconds DontEnum|Function 0479 getUTCMilliseconds dateProtoFuncGetUTCMilliseconds DontEnum|Function 0480 getTimezoneOffset dateProtoFuncGetTimezoneOffset DontEnum|Function 0481 setTime dateProtoFuncSetTime DontEnum|Function 1482 setMilliseconds dateProtoFuncSetMilliSeconds DontEnum|Function 1483 setUTCMilliseconds dateProtoFuncSetUTCMilliseconds DontEnum|Function 1484 setSeconds dateProtoFuncSetSeconds DontEnum|Function 2485 setUTCSeconds dateProtoFuncSetUTCSeconds DontEnum|Function 2486 setMinutes dateProtoFuncSetMinutes DontEnum|Function 3487 setUTCMinutes dateProtoFuncSetUTCMinutes DontEnum|Function 3488 setHours dateProtoFuncSetHours DontEnum|Function 4489 setUTCHours dateProtoFuncSetUTCHours DontEnum|Function 4490 setDate dateProtoFuncSetDate DontEnum|Function 1491 setUTCDate dateProtoFuncSetUTCDate DontEnum|Function 1492 setMonth dateProtoFuncSetMonth DontEnum|Function 2493 setUTCMonth dateProtoFuncSetUTCMonth DontEnum|Function 2494 setFullYear dateProtoFuncSetFullYear DontEnum|Function 3495 setUTCFullYear dateProtoFuncSetUTCFullYear DontEnum|Function 3496 setYear dateProtoFuncSetYear DontEnum|Function 1497 getYear dateProtoFuncGetYear DontEnum|Function 0498 @end499 */500 // ECMA 15.9.4501 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 43 516 44 // TODO: MakeTime (15.9.11.1) etc. ? … … 635 163 } 636 164 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) / 12646 - 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 all652 // obsolete time zones not listed here equivalent to "-0000".653 static const struct KnownZone {654 #if !PLATFORM(WIN_OS)655 const656 #endif657 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 failure690 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 GMT714 // or715 // Sat, 01-Jan-2000 08:00:00 GMT716 // or717 // Sat, 01 Jan 2000 08:00:00 GMT718 // or719 // 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 GMT722 // [Wednesday] January 09 23:12:40 GMT 1999723 //724 // We ignore the weekday.725 726 CString dateCString = date.UTF8String();727 const char *dateString = dateCString.c_str();728 729 // Skip leading space730 skipSpacesAndComments(dateString);731 732 long month = -1;733 const char *wordStart = dateString;734 // Check contents of first words if not number735 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 } else742 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 date774 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-based791 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 yet811 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 number853 dateString = ++newPosStr;854 skipSpacesAndComments(dateString);855 }856 857 hour = strtol(dateString, &newPosStr, 10);858 // Do not check for errno here since we want to continue859 // even if errno was set becasue we are still looking860 // 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 + rfc2822889 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:00946 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 garbage977 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 else985 year += 1900;986 }987 988 // fall back to local timezone989 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 // Functions1016 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 #else1099 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 #endif1107 }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 #else1123 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 #endif1131 }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 #else1147 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 #endif1155 }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 1711 165 } // namespace KJS -
trunk/JavaScriptCore/kjs/DateConstructor.h
r34860 r34872 1 1 /* 2 * This file is part of the KDE libraries3 2 * Copyright (C) 1999-2000 Harri Porten ([email protected]) 3 * Copyright (C) 2008 Apple Inc. All rights reserved. 4 4 * 5 5 * This library is free software; you can redistribute it and/or … … 19 19 */ 20 20 21 #ifndef D ATE_OBJECT_H22 #define D ATE_OBJECT_H21 #ifndef DateConstructor_h 22 #define DateConstructor_h 23 23 24 24 #include "JSFunction.h" 25 #include "JSWrapperObject.h"26 #include "lookup.h"27 25 28 26 namespace KJS { 29 27 30 struct GregorianDateTime;28 class DatePrototype; 31 29 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 * @internal61 *62 * The initial value of Date.prototype (and thus all objects created63 * with the Date constructor64 */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 30 73 31 /** … … 84 42 }; 85 43 86 } // namespace 44 } // namespace KJS 87 45 88 #endif 46 #endif // DateConstructor_h -
trunk/JavaScriptCore/kjs/DateMath.cpp
r34581 r34872 43 43 #include "DateMath.h" 44 44 45 #include "JSValue.h" 45 46 #include <math.h> 46 47 #include <stdint.h> 47 #include < JSValue.h>48 48 #include <time.h> 49 #include <wtf/ASCIICType.h> 49 50 #include <wtf/Assertions.h> 51 #include <wtf/MathExtras.h> 52 #include <wtf/StringExtras.h> 50 53 51 54 #if PLATFORM(DARWIN) … … 526 529 } 527 530 531 static 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". 543 static 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 562 inline 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 580 static 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 600 double 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 896 double 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 905 UString 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 914 UString 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 923 UString 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", >m); 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 528 947 } // namespace KJS -
trunk/JavaScriptCore/kjs/DateMath.h
r33930 r34872 48 48 namespace KJS { 49 49 50 class UString; 50 51 struct GregorianDateTime; 51 52 … … 58 59 double getCurrentUTCTimeWithMicroseconds(); 59 60 void getLocalTime(const time_t*, tm*); 61 62 // Not really math related, but this is currently the only shared place to put these. 63 double parseDate(const UString&); 64 double timeClip(double); 65 UString formatDate(const GregorianDateTime&); 66 UString formatDateUTCVariant(const GregorianDateTime&); 67 UString formatTime(const GregorianDateTime&, bool inputIsUTC); 60 68 61 69 … … 174 182 }; 175 183 176 } //namespace KJS 184 static inline int gmtoffset(const GregorianDateTime& t) 185 { 186 return t.utcOffset; 187 } 188 189 } // namespace KJS 177 190 178 191 #endif // DateMath_h -
trunk/JavaScriptCore/kjs/DatePrototype.cpp
r34860 r34872 21 21 22 22 #include "config.h" 23 #include " date_object.h"23 #include "DatePrototype.h" 24 24 25 25 #include "DateMath.h" 26 26 #include "JSString.h" 27 27 #include "ObjectPrototype.h" 28 #include "date_object.h" 28 29 #include "error_object.h" 29 #include "operations.h"30 30 #include <float.h> 31 31 #include <limits.h> 32 32 #include <locale.h> 33 33 #include <math.h> 34 #include <stdio.h>35 #include <stdlib.h>36 #include <string.h>37 34 #include <time.h> 38 #include <wtf/ASCIICType.h>39 35 #include <wtf/Assertions.h> 40 36 #include <wtf/MathExtras.h> … … 113 109 } 114 110 115 #include " date_object.lut.h"111 #include "DatePrototype.lut.h" 116 112 117 113 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 114 134 115 #if PLATFORM(MAC) … … 238 219 #endif // PLATFORM(WIN_OS) 239 220 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", >m);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 221 // Converts a list of arguments sent to a Date member function into milliseconds, updating 283 222 // ms (representing milliseconds) and t (representing the rest of the date structure) appropriately. … … 359 298 } 360 299 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 448 303 449 304 const ClassInfo DatePrototype::info = {"Date", &DateInstance::info, 0, ExecState::dateTable}; … … 512 367 } 513 368 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.3533 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.3540 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 else549 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.2587 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) / 12646 - 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 all652 // obsolete time zones not listed here equivalent to "-0000".653 static const struct KnownZone {654 #if !PLATFORM(WIN_OS)655 const656 #endif657 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 failure690 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 GMT714 // or715 // Sat, 01-Jan-2000 08:00:00 GMT716 // or717 // Sat, 01 Jan 2000 08:00:00 GMT718 // or719 // 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 GMT722 // [Wednesday] January 09 23:12:40 GMT 1999723 //724 // We ignore the weekday.725 726 CString dateCString = date.UTF8String();727 const char *dateString = dateCString.c_str();728 729 // Skip leading space730 skipSpacesAndComments(dateString);731 732 long month = -1;733 const char *wordStart = dateString;734 // Check contents of first words if not number735 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 } else742 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 date774 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-based791 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 yet811 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 number853 dateString = ++newPosStr;854 skipSpacesAndComments(dateString);855 }856 857 hour = strtol(dateString, &newPosStr, 10);858 // Do not check for errno here since we want to continue859 // even if errno was set becasue we are still looking860 // 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 + rfc2822889 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:00946 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 garbage977 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 else985 year += 1900;986 }987 988 // fall back to local timezone989 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 369 // Functions 1016 370 -
trunk/JavaScriptCore/kjs/DatePrototype.h
r34860 r34872 1 1 /* 2 * This file is part of the KDE libraries3 2 * Copyright (C) 1999-2000 Harri Porten ([email protected]) 3 * Copyright (C) 2008 Apple Inc. All rights reserved. 4 4 * 5 5 * This library is free software; you can redistribute it and/or … … 19 19 */ 20 20 21 #ifndef D ATE_OBJECT_H22 #define D ATE_OBJECT_H21 #ifndef DatePrototype_h 22 #define DatePrototype_h 23 23 24 #include "JSFunction.h" 25 #include "JSWrapperObject.h" 26 #include "lookup.h" 24 #include "date_object.h" 27 25 28 26 namespace KJS { 29 27 30 struct GregorianDateTime;31 class FunctionPrototype;32 28 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 29 59 30 /** … … 71 42 }; 72 43 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 85 45 86 } // namespace 87 88 #endif 46 #endif // DatePrototype_h -
trunk/JavaScriptCore/kjs/JSGlobalObject.cpp
r34863 r34872 36 36 #include "BooleanPrototype.h" 37 37 #include "CodeBlock.h" 38 #include "DateConstructor.h" 39 #include "DatePrototype.h" 38 40 #include "FunctionConstructor.h" 39 41 #include "FunctionPrototype.h" … … 49 51 #include "StringConstructor.h" 50 52 #include "StringPrototype.h" 51 #include "date_object.h"52 53 #include "debugger.h" 53 54 #include "error_object.h" -
trunk/JavaScriptCore/kjs/JSObject.cpp
r34855 r34872 26 26 #include "JSObject.h" 27 27 28 #include "DatePrototype.h" 28 29 #include "ObjectPrototype.h" 29 30 #include "PropertyNameArray.h" 30 #include "date_object.h"31 31 #include "error_object.h" 32 32 #include "nodes.h" -
trunk/JavaScriptCore/kjs/date_object.cpp
r34857 r34872 24 24 25 25 #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>33 26 #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>40 27 #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 #endif47 48 #if HAVE(SYS_PARAM_H)49 #include <sys/param.h>50 #endif51 52 #if HAVE(SYS_TIME_H)53 #include <sys/time.h>54 #endif55 56 #if HAVE(SYS_TIMEB_H)57 #include <sys/timeb.h>58 #endif59 60 #if PLATFORM(MAC)61 #include <CoreFoundation/CoreFoundation.h>62 #endif63 64 using namespace WTF;65 28 66 29 namespace 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 30 127 31 struct DateInstance::Cache { … … 131 35 GregorianDateTime m_cachedGregorianDateTimeUTC; 132 36 }; 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 #else200 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 needed208 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 formatting216 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 buffer224 if (yearNeedsOffset && format != LocaleTime) {225 static const int yearLen = 5; // FIXME will be a problem in the year 10,000226 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", >m);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, updating283 // 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 them294 if (numArgs > maxArgs)295 numArgs = maxArgs;296 297 // hours298 if (maxArgs >= 4 && idx < numArgs) {299 t->hour = 0;300 milliseconds += args[idx++]->toInt32(exec, ok) * msPerHour;301 }302 303 // minutes304 if (maxArgs >= 3 && idx < numArgs && ok) {305 t->minute = 0;306 milliseconds += args[idx++]->toInt32(exec, ok) * msPerMinute;307 }308 309 // seconds310 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 // milliseconds319 if (idx < numArgs) {320 double millis = args[idx]->toNumber(exec);321 ok = isfinite(millis);322 milliseconds += millis;323 } else324 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, updating331 // 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 them341 if (numArgs > maxArgs)342 numArgs = maxArgs;343 344 // years345 if (maxArgs >= 3 && idx < numArgs)346 t->year = args[idx++]->toInt32(exec, ok) - 1900;347 348 // months349 if (maxArgs >= 2 && idx < numArgs && ok)350 t->month = args[idx++]->toInt32(exec, ok);351 352 // days353 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 37 363 38 const ClassInfo DateInstance::info = {"Date", 0, 0, 0}; … … 439 114 } 440 115 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.h452 FIXME: We could use templates to simplify the UTC variants.453 @begin dateTable454 toString dateProtoFuncToString DontEnum|Function 0455 toUTCString dateProtoFuncToUTCString DontEnum|Function 0456 toDateString dateProtoFuncToDateString DontEnum|Function 0457 toTimeString dateProtoFuncToTimeString DontEnum|Function 0458 toLocaleString dateProtoFuncToLocaleString DontEnum|Function 0459 toLocaleDateString dateProtoFuncToLocaleDateString DontEnum|Function 0460 toLocaleTimeString dateProtoFuncToLocaleTimeString DontEnum|Function 0461 valueOf dateProtoFuncValueOf DontEnum|Function 0462 getTime dateProtoFuncGetTime DontEnum|Function 0463 getFullYear dateProtoFuncGetFullYear DontEnum|Function 0464 getUTCFullYear dateProtoFuncGetUTCFullYear DontEnum|Function 0465 toGMTString dateProtoFuncToGMTString DontEnum|Function 0466 getMonth dateProtoFuncGetMonth DontEnum|Function 0467 getUTCMonth dateProtoFuncGetUTCMonth DontEnum|Function 0468 getDate dateProtoFuncGetDate DontEnum|Function 0469 getUTCDate dateProtoFuncGetUTCDate DontEnum|Function 0470 getDay dateProtoFuncGetDay DontEnum|Function 0471 getUTCDay dateProtoFuncGetUTCDay DontEnum|Function 0472 getHours dateProtoFuncGetHours DontEnum|Function 0473 getUTCHours dateProtoFuncGetUTCHours DontEnum|Function 0474 getMinutes dateProtoFuncGetMinutes DontEnum|Function 0475 getUTCMinutes dateProtoFuncGetUTCMinutes DontEnum|Function 0476 getSeconds dateProtoFuncGetSeconds DontEnum|Function 0477 getUTCSeconds dateProtoFuncGetUTCSeconds DontEnum|Function 0478 getMilliseconds dateProtoFuncGetMilliSeconds DontEnum|Function 0479 getUTCMilliseconds dateProtoFuncGetUTCMilliseconds DontEnum|Function 0480 getTimezoneOffset dateProtoFuncGetTimezoneOffset DontEnum|Function 0481 setTime dateProtoFuncSetTime DontEnum|Function 1482 setMilliseconds dateProtoFuncSetMilliSeconds DontEnum|Function 1483 setUTCMilliseconds dateProtoFuncSetUTCMilliseconds DontEnum|Function 1484 setSeconds dateProtoFuncSetSeconds DontEnum|Function 2485 setUTCSeconds dateProtoFuncSetUTCSeconds DontEnum|Function 2486 setMinutes dateProtoFuncSetMinutes DontEnum|Function 3487 setUTCMinutes dateProtoFuncSetUTCMinutes DontEnum|Function 3488 setHours dateProtoFuncSetHours DontEnum|Function 4489 setUTCHours dateProtoFuncSetUTCHours DontEnum|Function 4490 setDate dateProtoFuncSetDate DontEnum|Function 1491 setUTCDate dateProtoFuncSetUTCDate DontEnum|Function 1492 setMonth dateProtoFuncSetMonth DontEnum|Function 2493 setUTCMonth dateProtoFuncSetUTCMonth DontEnum|Function 2494 setFullYear dateProtoFuncSetFullYear DontEnum|Function 3495 setUTCFullYear dateProtoFuncSetUTCFullYear DontEnum|Function 3496 setYear dateProtoFuncSetYear DontEnum|Function 1497 getYear dateProtoFuncGetYear DontEnum|Function 0498 @end499 */500 // ECMA 15.9.4501 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.3533 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.3540 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 else549 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.2587 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) / 12646 - 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 all652 // obsolete time zones not listed here equivalent to "-0000".653 static const struct KnownZone {654 #if !PLATFORM(WIN_OS)655 const656 #endif657 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 failure690 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 GMT714 // or715 // Sat, 01-Jan-2000 08:00:00 GMT716 // or717 // Sat, 01 Jan 2000 08:00:00 GMT718 // or719 // 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 GMT722 // [Wednesday] January 09 23:12:40 GMT 1999723 //724 // We ignore the weekday.725 726 CString dateCString = date.UTF8String();727 const char *dateString = dateCString.c_str();728 729 // Skip leading space730 skipSpacesAndComments(dateString);731 732 long month = -1;733 const char *wordStart = dateString;734 // Check contents of first words if not number735 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 } else742 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 date774 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-based791 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 yet811 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 number853 dateString = ++newPosStr;854 skipSpacesAndComments(dateString);855 }856 857 hour = strtol(dateString, &newPosStr, 10);858 // Do not check for errno here since we want to continue859 // even if errno was set becasue we are still looking860 // 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 + rfc2822889 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:00946 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 garbage977 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 else985 year += 1900;986 }987 988 // fall back to local timezone989 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 // Functions1016 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 #else1099 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 #endif1107 }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 #else1123 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 #endif1131 }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 #else1147 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 #endif1155 }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 1711 116 } // namespace KJS -
trunk/JavaScriptCore/kjs/date_object.h
r34754 r34872 1 1 /* 2 * This file is part of the KDE libraries3 2 * Copyright (C) 1999-2000 Harri Porten ([email protected]) 3 * Copyright (C) 2008 Apple Inc. All rights reserved. 4 4 * 5 5 * This library is free software; you can redistribute it and/or … … 22 22 #define DATE_OBJECT_H 23 23 24 #include "JSFunction.h"25 24 #include "JSWrapperObject.h" 26 #include "lookup.h"27 25 28 26 namespace KJS { … … 57 55 }; 58 56 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 87 58 88 59 #endif -
trunk/JavaScriptCore/kjs/internal.cpp
r34863 r34872 31 31 #include "StringPrototype.h" 32 32 #include "collector.h" 33 #include "date_object.h"34 33 #include "debugger.h" 35 34 #include "error_object.h"
Note:
See TracChangeset
for help on using the changeset viewer.