[webkit-changes] cvs commit: JavaScriptCore/kjs date_object.cpp date_object.h

Adele adele at opensource.apple.com
Mon Aug 8 17:29:24 PDT 2005


adele       05/08/08 17:29:24

  Modified:    .        Tag: Safari-2-0-branch ChangeLog
               kjs      Tag: Safari-2-0-branch date_object.cpp
                        date_object.h
  Log:
            Merged fix from TOT to Safari-2-0-branch
            <rdar://problem/3444900> some US-centric date formats not parsed by JavaScript (clock at news8austin.com) (bugzilla 3477)
  
      2005-07-01  Geoffrey Garen  <ggaren at apple.com
  
            -landed patch by Carsten Guenther <cguenther at gmail.com>
  
            -fixes http://bugzilla.opendarwin.org/show_bug.cgi?id=3477
            some US-centric date formats not parsed by JavaScript (clock at news8austin.com)
  
            -relevant tests:
                   mozilla/ecma_3/Date/15.9.5.5.js
                   layout-tests/fast/js/date-parse-test.html
  
            Reviewed by darin.
  
          * kjs/date_object.cpp:
          (day):
          (dayFromYear):
          (daysInYear):
          (timeFromYear):
          (yearFromTime):
          (weekDay):
          (timeZoneOffset):
          (DateProtoFuncImp::call):
          (DateObjectImp::construct):
          (KJS::parseDate):
          (ymdhms_to_seconds):
          (KJS::makeTime):
          (findMonth):
          (KJS::KRFCDate_parseDate):
          * kjs/date_object.h:
  
  Revision  Changes    Path
  No                   revision
  
  
  No                   revision
  
  
  1.677.6.21 +35 -0     JavaScriptCore/ChangeLog
  
  Index: ChangeLog
  ===================================================================
  RCS file: /cvs/root/JavaScriptCore/ChangeLog,v
  retrieving revision 1.677.6.20
  retrieving revision 1.677.6.21
  diff -u -r1.677.6.20 -r1.677.6.21
  --- ChangeLog	6 Aug 2005 01:36:50 -0000	1.677.6.20
  +++ ChangeLog	9 Aug 2005 00:29:22 -0000	1.677.6.21
  @@ -1,3 +1,38 @@
  +2005-08-08  Adele Peterson  <adele at apple.com>
  +
  +          Merged fix from TOT to Safari-2-0-branch
  +          <rdar://problem/3444900> some US-centric date formats not parsed by JavaScript (clock at news8austin.com) (bugzilla 3477)
  +
  +    2005-07-01  Geoffrey Garen  <ggaren at apple.com
  +
  +          -landed patch by Carsten Guenther <cguenther at gmail.com>
  +
  +          -fixes http://bugzilla.opendarwin.org/show_bug.cgi?id=3477
  +          some US-centric date formats not parsed by JavaScript (clock at news8austin.com)
  +
  +          -relevant tests:
  +                 mozilla/ecma_3/Date/15.9.5.5.js
  +                 layout-tests/fast/js/date-parse-test.html
  +
  +          Reviewed by darin.
  +
  +        * kjs/date_object.cpp:
  +        (day):
  +        (dayFromYear):
  +        (daysInYear):
  +        (timeFromYear):
  +        (yearFromTime):
  +        (weekDay):
  +        (timeZoneOffset):
  +        (DateProtoFuncImp::call):
  +        (DateObjectImp::construct):
  +        (KJS::parseDate):
  +        (ymdhms_to_seconds):
  +        (KJS::makeTime):
  +        (findMonth):
  +        (KJS::KRFCDate_parseDate):
  +        * kjs/date_object.h:
  +
   === Safari-416 ===
   
   2005-08-05  Adele Peterson  <adele at apple.com>
  
  
  
  No                   revision
  
  
  No                   revision
  
  
  1.39.8.1  +410 -274  JavaScriptCore/kjs/date_object.cpp
  
  Index: date_object.cpp
  ===================================================================
  RCS file: /cvs/root/JavaScriptCore/kjs/date_object.cpp,v
  retrieving revision 1.39
  retrieving revision 1.39.8.1
  diff -u -r1.39 -r1.39.8.1
  --- date_object.cpp	21 Feb 2005 17:32:35 -0000	1.39
  +++ date_object.cpp	9 Aug 2005 00:29:23 -0000	1.39.8.1
  @@ -58,7 +58,15 @@
   
   #include "date_object.lut.h"
   
  +// some constants
   const time_t invalidDate = -1;
  +const double hoursPerDay = 24;
  +const double minutesPerHour = 60;
  +const double secondsPerMinute = 60;
  +const double msPerSecond = 1000;
  +const double msPerMinute = msPerSecond * secondsPerMinute;
  +const double msPerHour = msPerMinute * minutesPerHour;
  +const double msPerDay = msPerHour * hoursPerDay;
   
   #if APPLE_CHANGES
   
  @@ -255,13 +263,9 @@
       return retVal;
   }
   
  -static UString formatLocaleDate(KJS::ExecState *exec,time_t tv, bool includeDate, bool includeTime, const KJS::List &args)
  +static UString formatLocaleDate(KJS::ExecState *exec, double time, bool includeDate, bool includeTime, const KJS::List &args)
   {
  -    LongDateTime longDateTime;
  -    UCConvertCFAbsoluteTimeToLongDateTime(tv - kCFAbsoluteTimeIntervalSince1970, &longDateTime);
  -
       CFLocaleRef locale = CFLocaleCopyCurrent();
  -    
       int argCount = args.size();
       
       CFDateFormatterStyle    dateStyle = (includeDate ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle);
  @@ -290,8 +294,7 @@
   	CFDateFormatterSetFormat(formatter,customFormatCFString);
   	CFRelease(customFormatCFString);
       }
  -    CFStringRef string = CFDateFormatterCreateStringWithAbsoluteTime(NULL, formatter, tv - kCFAbsoluteTimeIntervalSince1970);
  -
  +    CFStringRef string = CFDateFormatterCreateStringWithAbsoluteTime(NULL, formatter, time - kCFAbsoluteTimeIntervalSince1970);
       // We truncate the string returned from CFDateFormatter if it's absurdly long (> 200 characters).
       // That's not great error handling, but it just won't happen so it doesn't matter.
       UChar buffer[200];
  @@ -313,6 +316,83 @@
   
   using namespace KJS;
   
  +static int day(double t)
  +{
  +  return int(floor(t / msPerDay));
  +}
  +
  +static double dayFromYear(int year)
  +{
  +  return 365.0 * (year - 1970)
  +    + floor((year - 1969) / 4.0)
  +    - floor((year - 1901) / 100.0)
  +    + floor((year - 1601) / 400.0);
  +}
  +
  +// depending on whether it's a leap year or not
  +static int daysInYear(int year)
  +{
  +  if (year % 4 != 0)
  +    return 365;
  +  else if (year % 400 == 0)
  +    return 366;
  +  else if (year % 100 == 0)
  +    return 365;
  +  else
  +    return 366;
  +}
  +
  +// time value of the start of a year
  +static double timeFromYear(int year)
  +{
  +  return msPerDay * dayFromYear(year);
  +}
  +
  +// year determined by time value
  +static int yearFromTime(double t)
  +{
  +  // ### there must be an easier way
  +  // initial guess
  +  int y = 1970 + int(t / (365.25 * msPerDay));
  +  // adjustment
  +  if (timeFromYear(y) > t) {
  +    do {
  +      --y;
  +    } while (timeFromYear(y) > t);
  +  } else {
  +    while (timeFromYear(y + 1) < t)
  +      ++y;
  +  }
  +
  +  return y;
  +}
  +
  +// 0: Sunday, 1: Monday, etc.
  +static int weekDay(double t)
  +{
  +  int wd = (day(t) + 4) % 7;
  +  if (wd < 0)
  +    wd += 7;
  +  return wd;
  +}
  +
  +static double timeZoneOffset(const struct tm *t)
  +{
  +#if defined BSD || defined(__linux__) || defined(__APPLE__)
  +  return -(t->tm_gmtoff / 60);
  +#else
  +#  if defined(__BORLANDC__) || defined(__CYGWIN__)
  +// FIXME consider non one-hour DST change
  +#if !defined(__CYGWIN__)
  +#error please add daylight savings offset here!
  +#endif
  +  return _timezone / 60 - (t->tm_isdst > 0 ? 60 : 0);
  +#  else
  +  return timezone / 60 - (t->tm_isdst > 0 ? 60 : 0 );
  +#  endif
  +#endif
  +}
  +
   // ------------------------------ DateInstanceImp ------------------------------
   
   const ClassInfo DateInstanceImp::info = {"Date", 0, 0, 0};
  @@ -461,15 +541,37 @@
       }
     }
     
  -  time_t tv = (time_t)(milli / 1000.0);
  -  int ms = int(milli - tv * 1000.0);
  +  // check whether time value is outside time_t's usual range
  +  // make the necessary transformations if necessary
  +  int realYearOffset = 0;
  +  double milliOffset = 0.0;
  +  double secs = floor(milli / 1000.0);
  +
  +  if (milli < 0 || milli >= timeFromYear(2038)) {
  +    // ### ugly and probably not very precise
  +    int realYear = yearFromTime(milli);
  +    int base = daysInYear(realYear) == 365 ? 2001 : 2000;
  +    milliOffset = timeFromYear(base) - timeFromYear(realYear);
  +    milli += milliOffset;
  +    realYearOffset = realYear - base;
  +  }
   
  -  struct tm *t;
  -  if (utc)
  -    t = gmtime(&tv);
  -  else
  -    t = localtime(&tv);
  +  time_t tv = (time_t) floor(milli / 1000.0);
  +  int ms = int(milli - tv * 1000.0);
   
  +  struct tm *t = utc ? gmtime(&tv) : localtime(&tv);
  +  // we had an out of range year. use that one (plus/minus offset
  +  // found by calculating tm_year) and fix the week day calculation
  +  if (realYearOffset != 0) {
  +    t->tm_year += realYearOffset;
  +    milli -= milliOffset;
  +    // our own weekday calculation. beware of need for local time.
  +    double m = milli;
  +    if (!utc)
  +      m -= timeZoneOffset(t) * msPerMinute;
  +    t->tm_wday = weekDay(m);
  +  }
  +  
     switch (id) {
   #if APPLE_CHANGES
     case ToString:
  @@ -486,13 +588,13 @@
       result = String(formatDateUTCVariant(*t) + " " + formatTime(*t));
       break;
     case ToLocaleString:
  -    result = String(formatLocaleDate(exec,tv, true, true,args));
  +    result = String(formatLocaleDate(exec, secs, true, true, args));
       break;
     case ToLocaleDateString:
  -    result = String(formatLocaleDate(exec,tv, true, false,args));
  +    result = String(formatLocaleDate(exec, secs, true, false, args));
       break;
     case ToLocaleTimeString:
  -    result = String(formatLocaleDate(exec,tv, false, true,args));
  +    result = String(formatLocaleDate(exec, secs, false, true, args));
       break;
   #else
     case ToString:
  @@ -630,14 +732,10 @@
     if (id == SetYear || id == SetMilliSeconds || id == SetSeconds ||
         id == SetMinutes || id == SetHours || id == SetDate ||
         id == SetMonth || id == SetFullYear ) {
  -    time_t mktimeResult = utc ? timegm(t) : mktime(t);
  -    if (mktimeResult == invalidDate)
  -      result = Number(NaN);
  -    else
  -      result = Number(mktimeResult * 1000.0 + ms);
  +    result = Number(makeTime(t, ms, utc));
       thisObj.setInternalValue(result);
     }
  -
  +  
     return result;
   }
   
  @@ -723,14 +821,10 @@
         t.tm_sec = (numArgs >= 6) ? args[5].toInt32(exec) : 0;
         t.tm_isdst = -1;
         int ms = (numArgs >= 7) ? args[6].toInt32(exec) : 0;
  -      time_t mktimeResult = mktime(&t);
  -      if (mktimeResult == invalidDate)
  -        value = NaN;
  -      else
  -        value = mktimeResult * 1000.0 + ms;
  +      value = makeTime(&t, ms, false);
       }
     }
  -
  +  
     Object proto = exec->lexicalInterpreter()->builtinDatePrototype();
     Object ret(new DateInstanceImp(proto.imp()));
     ret.setInternalValue(Number(timeClip(value)));
  @@ -817,58 +911,16 @@
   #ifdef KJS_VERBOSE
     fprintf(stderr,"KJS::parseDate %s\n",u.ascii());
   #endif
  -  int firstSlash = u.find('/');
  -  if ( firstSlash == -1 )
  -  {
  -    time_t seconds = KRFCDate_parseDate( u );
  -#ifdef KJS_VERBOSE
  -    fprintf(stderr,"KRFCDate_parseDate returned seconds=%d\n",seconds);
  -#endif
  -    if ( seconds == invalidDate )
  -      return NaN;
  -    else
  -      return seconds * 1000.0;
  -  }
  -  else
  -  {
  -    // Found 12/31/2099 on some website -> obviously MM/DD/YYYY
  -    int month = u.substr(0,firstSlash).toULong();
  -    int secondSlash = u.find('/',firstSlash+1);
  -    //fprintf(stdout,"KJS::parseDate firstSlash=%d, secondSlash=%d\n", firstSlash, secondSlash);
  -    if ( secondSlash == -1 )
  -    {
  -      fprintf(stderr,"KJS::parseDate parsing for this format isn't implemented\n%s", u.ascii());
  -      return NaN;
  -    }
  -    int day = u.substr(firstSlash+1,secondSlash-firstSlash-1).toULong();
  -    int year = u.substr(secondSlash+1).toULong();
  -    //fprintf(stdout,"KJS::parseDate day=%d, month=%d, year=%d\n", day, month, year);
  -    struct tm t;
  -    memset( &t, 0, sizeof(t) );
  -#if !APPLE_CHANGES
  -    year = (year > 2037) ? 2037 : year; // mktime is limited to 2037 !!!
  -#endif
  -    t.tm_year = (year >= 0 && year <= 99) ? year : year - 1900;
  -    t.tm_mon = month-1; // mktime wants 0-11 for some reason
  -    t.tm_mday = day;
  -    time_t seconds = mktime(&t);
  -    if ( seconds == invalidDate )
  -    {
  -#if !APPLE_CHANGES
  -      fprintf(stderr,"KJS::parseDate mktime returned -1.\n%s", u.ascii());
  -#endif
  -      return NaN;
  -    }
  -    else
  -      return seconds * 1000.0;
  -  }
  +  double /*time_t*/ seconds = KRFCDate_parseDate( u );
  +
  +  return seconds == invalidDate ? NaN : seconds * 1000.0;
   }
   
   ///// Awful duplication from krfcdate.cpp - we don't link to kdecore
   
  -static unsigned int ymdhms_to_seconds(int year, int mon, int day, int hour, int minute, int second)
  +static double ymdhms_to_seconds(int year, int mon, int day, int hour, int minute, int second)
   {
  -    unsigned int ret = (day - 32075)       /* days */
  +    double ret = (day - 32075)       /* days */
               + 1461L * (year + 4800L + (mon - 14) / 12) / 4
               + 367 * (mon - 2 - (mon - 14) / 12 * 12) / 12
               - 3 * ((year + 4900L + (mon - 14) / 12) / 100) / 4
  @@ -884,8 +936,12 @@
   
   // we follow the recommendation of rfc2822 to consider all
   // obsolete time zones not listed here equivalent to "-0000"
  -static const struct {
  -    const char *tzName;
  +static const struct KnownZone {
  +#ifdef _WIN32
  +    char tzName[4];
  +#else
  +    const char tzName[4];
  +#endif
       int tzOffset;
   } known_zones[] = {
       { "UT", 0 },
  @@ -897,74 +953,128 @@
       { "MST", -420 },
       { "MDT", -360 },
       { "PST", -480 },
  -    { "PDT", -420 },
  -    { 0, 0 }
  +    { "PDT", -420 }
   };
   
  -static inline bool isSpaceOrTab(char c)
  +double KJS::makeTime(struct tm *t, int ms, bool utc)
  +{
  +    int utcOffset;
  +    if (utc) {
  +	time_t zero = 0;
  +#if defined BSD || defined(__linux__) || defined(__APPLE__)
  +	struct tm *t3 = localtime(&zero);
  +        utcOffset = t3->tm_gmtoff;
  +        t->tm_isdst = t3->tm_isdst;
  +#else
  +        (void)localtime(&zero);
  +#  if defined(__BORLANDC__) || defined(__CYGWIN__)
  +        utcOffset = - _timezone;
  +#  else
  +        utcOffset = - timezone;
  +#  endif
  +        t->tm_isdst = 0;
  +#endif
  +    } else {
  +	utcOffset = 0;
  +	t->tm_isdst = -1;
  +    }
  +
  +    double yearOffset = 0.0;
  +    if (t->tm_year < (1970 - 1900) || t->tm_year > (2038 - 1900)) {
  +      // we'll fool mktime() into believing that this year is within
  +      // its normal, portable range (1970-2038) by setting tm_year to
  +      // 2000 or 2001 and adding the difference in milliseconds later.
  +      // choice between offset will depend on whether the year is a
  +      // leap year or not.
  +      int y = t->tm_year + 1900;
  +      int baseYear = daysInYear(y) == 365 ? 2001 : 2000;
  +      const double baseTime = timeFromYear(baseYear);
  +      yearOffset = timeFromYear(y) - baseTime;
  +      t->tm_year = baseYear - 1900;
  +    }
  +
  +    return (mktime(t) + utcOffset) * 1000.0 + ms + yearOffset;
  +}
  +
  +// returns 0-11 (Jan-Dec); -1 on failure
  +static int findMonth(const char *monthStr)
   {
  -    return c == ' ' || c == '\t';
  +  assert(monthStr);
  +  static const char haystack[37] = "janfebmaraprmayjunjulaugsepoctnovdec";
  +  char needle[4];
  +  for (int i = 0; i < 3; ++i) {
  +    if (!*monthStr)
  +      return -1;
  +    needle[i] = tolower(*monthStr++);
  +  }
  +  needle[3] = '\0';
  +  const char *str = strstr(haystack, needle);
  +  if (str) {
  +    int position = str - haystack;
  +    if (position % 3 == 0) {
  +      return position / 3;
  +    }
  +  }
  +  return -1;
   }
   
  -time_t KJS::KRFCDate_parseDate(const UString &_date)
  +double KJS::KRFCDate_parseDate(const UString &_date)
   {
        // This parse a date in the form:
  -     //     Wednesday, 09-Nov-99 23:12:40 GMT
  +     //     Tuesday, 09-Nov-99 23:12:40 GMT
        // or
        //     Sat, 01-Jan-2000 08:00:00 GMT
        // or
        //     Sat, 01 Jan 2000 08:00:00 GMT
        // or
        //     01 Jan 99 22:00 +0100    (exceptions in rfc822/rfc2822)
  -     // ### non RFC format, added for Javascript:
  +     // ### non RFC formats, added for Javascript:
        //     [Wednesday] January 09 1999 23:12:40 GMT
  +     //     [Wednesday] January 09 23:12:40 GMT 1999
        //
        // We ignore the weekday
        //
  +     double result = -1;
        int offset = 0;
  +     bool have_tz = false;
        char *newPosStr;
        const char *dateString = _date.ascii();
        int day = 0;
  -     char monthStr[4];
        int month = -1; // not set yet
        int year = 0;
        int hour = 0;
        int minute = 0;
        int second = 0;
  -
  +     bool have_time = false;
  +     
  +     // for strtol error checking
        errno = 0;
   
        // Skip leading space
  -     while (isSpaceOrTab(*dateString))
  +     while(isspace(*dateString))
        	dateString++;
   
        const char *wordStart = dateString;
        // Check contents of first words if not number
        while(*dateString && !isdigit(*dateString))
        {
  -        if ( isSpaceOrTab(*dateString) && dateString - wordStart >= 3 )
  +        if ( isspace(*dateString) && dateString - wordStart >= 3 )
           {
  -          monthStr[0] = tolower(*wordStart++);
  -          monthStr[1] = tolower(*wordStart++);
  -          monthStr[2] = tolower(*wordStart++);
  -          monthStr[3] = '\0';
  -          //fprintf(stderr,"KJS::parseDate found word starting with '%s'\n", monthStr);
  -          const char *str = strstr(haystack, monthStr);
  -          if (str) {
  -            int position = str - haystack;
  -            if (position % 3 == 0) {
  -              month = position / 3; // Jan=00, Feb=01, Mar=02, ..
  -            }
  -          }
  -          while (isSpaceOrTab(*dateString))
  +          month = findMonth(wordStart);
  +          while(isspace(*dateString))
                dateString++;
             wordStart = dateString;
           }
           else
              dateString++;
        }
  +     // missing delimiter between month and day (like "January29")?
  +     if (month == -1 && dateString && wordStart != dateString) {
  +       month = findMonth(wordStart);
  +       // TODO: emit warning about dubious format found
  +     }
   
  -     while (isSpaceOrTab(*dateString))
  +     while(isspace(*dateString))
        	dateString++;
   
        if (!*dateString)
  @@ -973,119 +1083,226 @@
        // ' 09-Nov-99 23:12:40 GMT'
        day = strtol(dateString, &newPosStr, 10);
        if (errno)
  -        return invalidDate;
  +       return invalidDate;
        dateString = newPosStr;
   
  -     if ((day < 1) || (day > 31))
  -     	return invalidDate;
        if (!*dateString)
        	return invalidDate;
   
  -     if (*dateString == '-' || *dateString == ',')
  -     	dateString++;
  -
  -     while (isSpaceOrTab(*dateString))
  +     if (day < 1)
  +       return invalidDate;
  +     if (day > 31) {
  +       // ### where is the boundary and what happens below?
  +       if (*dateString == '/' && day >= 1000) {
  +         // looks like a YYYY/MM/DD date
  +         if (!*++dateString)
  +           return invalidDate;
  +         year = day;
  +         month = strtol(dateString, &newPosStr, 10) - 1;
  +         if (errno)
  +           return invalidDate;
  +         dateString = newPosStr;
  +         if (*dateString++ != '/' || !*dateString)
  +           return invalidDate;
  +         day = strtol(dateString, &newPosStr, 10);
  +         if (errno)
  +           return invalidDate;
  +         dateString = newPosStr;
  +       } else {
  +         return invalidDate;
  +       }
  +     } else if (*dateString == '/' && day <= 12 && month == -1) {
        	dateString++;
  -
  -     if ( month == -1 ) // not found yet
  +        // This looks like a MM/DD/YYYY date, not an RFC date.....
  +        month = day - 1; // 0-based
  +        day = strtol(dateString, &newPosStr, 10);
  +        if (errno)
  +          return invalidDate;
  +        dateString = newPosStr;
  +        if (*dateString == '/')
  +          dateString++;
  +        if (!*dateString)
  +          return invalidDate;
  +     }
  +     else
        {
  -        for(int i=0; i < 3;i++)
  -        {
  -           if (!*dateString || (*dateString == '-') || isSpaceOrTab(*dateString))
  -              return invalidDate;
  -           monthStr[i] = tolower(*dateString++);
  -        }
  -        monthStr[3] = '\0';
  -
  -        newPosStr = (char*)strstr(haystack, monthStr);
  +       if (*dateString == '-')
  +         dateString++;
   
  -        if (!newPosStr || (newPosStr - haystack) % 3 != 0)
  -           return invalidDate;
  +       while(isspace(*dateString))
  +         dateString++;
   
  -        month = (newPosStr-haystack)/3; // Jan=00, Feb=01, Mar=02, ..
  +       if (*dateString == ',')
  +         dateString++;
   
  -        if ((month < 0) || (month > 11))
  +       if ( month == -1 ) // not found yet
  +       {
  +         month = findMonth(dateString);
  +         if (month == -1)
              return invalidDate;
   
  -        while (*dateString && *dateString != '-' && !isSpaceOrTab(*dateString))
  +         while(*dateString && (*dateString != '-') && !isspace(*dateString))
              dateString++;
   
  -        if (!*dateString)
  +         if (!*dateString)
              return invalidDate;
   
  -        // '-99 23:12:40 GMT'
  -        if (*dateString != '-' && !isSpaceOrTab(*dateString))
  +         // '-99 23:12:40 GMT'
  +         if ((*dateString != '-') && (*dateString != '/') && !isspace(*dateString))
              return invalidDate;
  -        dateString++;
  -     }
  +         dateString++;
  +       }
   
  -     if ((month < 0) || (month > 11))
  -     	return invalidDate;
  +       if ((month < 0) || (month > 11))
  +         return invalidDate;
  +     }
   
        // '99 23:12:40 GMT'
  -     bool gotYear = true;
  -     year = strtol(dateString, &newPosStr, 10);
  -     if (errno)
  -        return invalidDate;
  -     dateString = newPosStr;
  -
  +     if (year <= 0 && *dateString) {
  +       year = strtol(dateString, &newPosStr, 10);
  +       if (errno)
  +         return invalidDate;
  +    }
  +    
        // Don't fail if the time is missing.
  -     if (*dateString == ':' || (isSpaceOrTab(*dateString) && isdigit(dateString[1])))
  +     if (*newPosStr)
        {
  -        if (*dateString == ':') {
  -          hour = year;
  -          gotYear = false;
  -        } else {
  -          // ' 23:12:40 GMT'
  -          ++dateString;
  -        
  -          hour = strtol(dateString, &newPosStr, 10);
  +        // ' 23:12:40 GMT'
  +        if (!isspace(*newPosStr)) {
  +           if ( *newPosStr == ':' ) // Ah, so there was no year, but the number was the hour
  +               year = -1;
  +           else
  +               return invalidDate;
  +        } else // in the normal case (we parsed the year), advance to the next number
  +            dateString = ++newPosStr;
  +
  +        hour = strtol(dateString, &newPosStr, 10);
  +
  +        // Do not check for errno here since we want to continue
  +        // even if errno was set becasue we are still looking
  +        // for the timezone!
  +        // read a number? if not this might be a timezone name
  +        if (newPosStr != dateString) {
  +          have_time = true;
  +          dateString = newPosStr;
  +
  +          if ((hour < 0) || (hour > 23))
  +            return invalidDate;
  +
  +          if (!*dateString)
  +            return invalidDate;
  +
  +          // ':12:40 GMT'
  +          if (*dateString++ != ':')
  +            return invalidDate;
  +
  +          minute = strtol(dateString, &newPosStr, 10);
             if (errno)
               return invalidDate;
             dateString = newPosStr;
  -        }
   
  -        if ((hour < 0) || (hour > 23))
  -           return invalidDate;
  +          if ((minute < 0) || (minute > 59))
  +            return invalidDate;
   
  -        if (!*dateString)
  -           return invalidDate;
  +          // ':40 GMT'
  +          if (*dateString && *dateString != ':' && !isspace(*dateString))
  +            return invalidDate;
   
  -        // ':12:40 GMT'
  -        if (*dateString++ != ':')
  -           return invalidDate;
  +          // seconds are optional in rfc822 + rfc2822
  +          if (*dateString ==':') {
  +            dateString++;
   
  -        minute = strtol(dateString, &newPosStr, 10);
  -        if (errno)
  -          return invalidDate;
  -        dateString = newPosStr;
  +            second = strtol(dateString, &newPosStr, 10);
  +            if (errno)
  +              return invalidDate;
  +            dateString = newPosStr;
  +            
  +            if ((second < 0) || (second > 59))
  +              return invalidDate;
  +          }
  +
  +          while(isspace(*dateString))
  +            dateString++;
  +
  +	  if (strncasecmp(dateString, "AM", 2) == 0) {
  +	    if (hour > 12)
  +	      return invalidDate;
  +	    if (hour == 12)
  +	      hour = 0;
  +	    dateString += 2;
  +	    while (isspace(*dateString))
  +	      dateString++;
  +	  } else if (strncasecmp(dateString, "PM", 2) == 0) {
  +	    if (hour > 12)
  +	      return invalidDate;
  +	    if (hour != 12)
  +	      hour += 12;
  +	    dateString += 2;
  +	    while (isspace(*dateString))
  +	      dateString++;
  +	  }
  +        }
  +     } else {
  +       dateString = newPosStr;
  +     }
   
  -        if ((minute < 0) || (minute > 59))
  +     // don't fail if the time zone is missing, some
  +     // broken mail-/news-clients omit the time zone
  +     if (*dateString) {
  +       if (strncasecmp(dateString, "GMT", 3) == 0 ||
  +	   strncasecmp(dateString, "UTC", 3) == 0) {
  +         dateString += 3;
  +         have_tz = true;
  +       }
  +
  +       while (isspace(*dateString))
  +         ++dateString;
  +
  +       if (strncasecmp(dateString, "GMT", 3) == 0) {
  +         dateString += 3;
  +       }
  +       if ((*dateString == '+') || (*dateString == '-')) {
  +         offset = strtol(dateString, &newPosStr, 10);
  +         if (errno)
              return invalidDate;
  +         dateString = newPosStr;
   
  -        // seconds are optional in rfc822 + rfc2822
  -        if (*dateString ==':') {
  -           dateString++;
  +         if ((offset < -9959) || (offset > 9959))
  +            return invalidDate;
   
  -           second = strtol(dateString, &newPosStr, 10);
  +         int sgn = (offset < 0)? -1:1;
  +         offset = abs(offset);
  +         if ( *dateString == ':' ) { // GMT+05:00
  +           int offset2 = strtol(dateString, &newPosStr, 10);
              if (errno)
                return invalidDate;
              dateString = newPosStr;
  -
  -           if ((second < 0) || (second > 59))
  -              return invalidDate;
  -        }
  +           offset = (offset*60 + offset2)*sgn;
  +         }
  +         else
  +           offset = ((offset / 100)*60 + (offset % 100))*sgn;
  +         have_tz = true;
  +       } else {
  +         for (int i=0; i < int(sizeof(known_zones)/sizeof(KnownZone)); i++) {
  +           if (0 == strncasecmp(dateString, known_zones[i].tzName, strlen(known_zones[i].tzName))) {
  +             offset = known_zones[i].tzOffset;
  +             have_tz = true;
  +             break;
  +           }
  +         }
  +         // Bail out if we found an unknown timezone
  +         if (!have_tz)
  +             return invalidDate;
  +       }
        }
  -     
  -     while (isSpaceOrTab(*dateString))
  +
  +     while(isspace(*dateString))
           dateString++;
   
  -     if (!gotYear) {
  -        year = strtol(dateString, &newPosStr, 10);
  -        if (errno)
  -          return invalidDate;
  -        while (isSpaceOrTab(*dateString))
  -           dateString++;
  +     if ( *dateString && year == -1 ) {
  +       year = strtol(dateString, &newPosStr, 10);
  +       if (errno)
  +         return invalidDate;
        }
   
        // Y2K: Solve 2 digit years
  @@ -1095,106 +1312,25 @@
        if ((year >= 50) && (year < 100))
            year += 1900;  // Y2K
   
  -     if ((year < 1900) || (year > 2500))
  -     	return invalidDate;
  -
  -     if (strncasecmp(dateString, "AM", 2) == 0) {
  -        if (hour < 1 || hour > 12)
  -            return invalidDate;
  -        if (hour == 12)
  -            hour = 0;
  -        dateString += 2;
  -        while (isSpaceOrTab(*dateString))
  -           dateString++;
  -     } else if (strncasecmp(dateString, "PM", 2) == 0) {
  -        if (hour < 1 || hour > 12)
  -            return invalidDate;
  -        if (hour != 12)
  -            hour += 12;
  -        dateString += 2;
  -        while (isSpaceOrTab(*dateString))
  -           dateString++;
  -     }
  -
  -     // don't fail if the time zone is missing, some
  -     // broken mail-/news-clients omit the time zone
  -     bool localTime;
  -     if (*dateString == 0) {
  -        // Other web browsers interpret missing time zone as "current time zone".
  -        localTime = true;
  -     } else {
  -        localTime = false;
  -        if (strncasecmp(dateString, "GMT", 3) == 0) {
  -            dateString += 3;
  -        }
  -        if ((*dateString == '+') || (*dateString == '-')) {
  -           offset = strtol(dateString, &newPosStr, 10);
  -
  -           if (errno || (offset < -9959) || (offset > 9959))
  -              return invalidDate;
  +     if (!have_tz) {
  +       // fall back to midnight, local timezone
  +       struct tm t;
  +       memset(&t, 0, sizeof(tm));
  +       t.tm_mday = day;
  +       t.tm_mon = month;
  +       t.tm_year = year - 1900;
  +       t.tm_isdst = -1;
  +       if (have_time) {
  +         t.tm_sec = second;
  +         t.tm_min = minute;
  +         t.tm_hour = hour;
  +       }
   
  -           int sgn = (offset < 0)? -1:1;
  -           offset = abs(offset);
  -           offset = ((offset / 100)*60 + (offset % 100))*sgn;
  -        } else {
  -           for (int i=0; known_zones[i].tzName != 0; i++) {
  -              if (0 == strncasecmp(dateString, known_zones[i].tzName, strlen(known_zones[i].tzName))) {
  -                 offset = known_zones[i].tzOffset;
  -                 break;
  -              }
  -           }
  -        }
  +       // better not use mktime() as it can't handle the full year range
  +       return makeTime(&t, 0, false) / 1000.0;
        }
  -     if (sizeof(time_t) == 4)
  -     {
  -         if ((time_t)-1 < 0)
  -         {
  -            if (year >= 2038)
  -            {
  -               year = 2038;
  -               month = 0;
  -               day = 1;
  -               hour = 0;
  -               minute = 0;
  -               second = 0;
  -            }
  -         }
  -         else
  -         {
  -            if (year >= 2115)
  -            {
  -               year = 2115;
  -               month = 0;
  -               day = 1;
  -               hour = 0;
  -               minute = 0;
  -               second = 0;
  -            }
  -         }
  -     }
  -
  -    time_t result;
        
  -    if (localTime) {
  -      struct tm tm;
  -      tm.tm_year = year - 1900;
  -      tm.tm_mon = month;
  -      tm.tm_mday = day;
  -      tm.tm_hour = hour;
  -      tm.tm_min = minute;
  -      tm.tm_sec = second;
  -      tm.tm_isdst = -1;
  -      result = mktime(&tm);
  -    } else {
  -     result = ymdhms_to_seconds(year, month+1, day, hour, minute, second);
  -
  -     // avoid negative time values
  -     if ((offset > 0) && (offset > result))
  -        offset = 0;
  -
  -     result -= offset*60;
  -    }
  -
  +     result = ymdhms_to_seconds(year, month+1, day, hour, minute, second) - (offset*60);
        return result;
   }
   
  
  
  
  1.7.12.1  +3 -2      JavaScriptCore/kjs/date_object.h
  
  Index: date_object.h
  ===================================================================
  RCS file: /cvs/root/JavaScriptCore/kjs/date_object.h,v
  retrieving revision 1.7
  retrieving revision 1.7.12.1
  diff -u -r1.7 -r1.7.12.1
  --- date_object.h	12 Aug 2004 17:21:29 -0000	1.7
  +++ date_object.h	9 Aug 2005 00:29:23 -0000	1.7.12.1
  @@ -120,8 +120,9 @@
   
     // helper functions
     double parseDate(const UString &u);
  -  time_t KRFCDate_parseDate(const UString &_date); 
  -  double timeClip(double);
  +  double KRFCDate_parseDate(const UString &_date);
  +  double timeClip(double t);
  +  double makeTime(struct tm *t, int milli, bool utc);
   
   }; // namespace
   
  
  
  



More information about the webkit-changes mailing list