[SCM] WebKit Debian packaging branch, debian/experimental, updated. upstream/1.3.3-9427-gc2be6fc

commit-queue at webkit.org commit-queue at webkit.org
Wed Dec 22 14:39:43 UTC 2010


The following commit has been merged in the debian/experimental branch:
commit a6cf1a196771c6292f134eba90b368269897ea24
Author: commit-queue at webkit.org <commit-queue at webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Fri Oct 15 02:45:03 2010 +0000

    2010-10-14  Nathan Vander Wilt  <nate at andyet.net>
    
            Reviewed by Darin Adler.
    
            Added parser for ECMAScript 5 standard date format, so Date.parse can handle RFC 3339 timestamps: https://bugs.webkit.org/show_bug.cgi?id=44632
    
            * runtime/DateConversion.cpp:
            (JSC::parseDate):
            * wtf/DateMath.cpp:
            (WTF::ymdhmsToSeconds):
            (WTF::parseES5DateFromNullTerminatedCharacters):
            * wtf/DateMath.h:
    2010-10-14  Nathan Vander Wilt  <nate at andyet.net>
    
            Reviewed by Darin Adler.
    
            Added tests for https://bugs.webkit.org/show_bug.cgi?id=44632
    
            * fast/js/date-parse-test-expected.txt:
            * fast/js/script-tests/date-parse-test.js:
            (testDateParseExact):
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@69833 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/JavaScriptCore/ChangeLog b/JavaScriptCore/ChangeLog
index 7752d9a..5d99bdc 100644
--- a/JavaScriptCore/ChangeLog
+++ b/JavaScriptCore/ChangeLog
@@ -1,3 +1,16 @@
+2010-10-14  Nathan Vander Wilt  <nate at andyet.net>
+
+        Reviewed by Darin Adler.
+
+        Added parser for ECMAScript 5 standard date format, so Date.parse can handle RFC 3339 timestamps: https://bugs.webkit.org/show_bug.cgi?id=44632
+
+        * runtime/DateConversion.cpp:
+        (JSC::parseDate):
+        * wtf/DateMath.cpp:
+        (WTF::ymdhmsToSeconds):
+        (WTF::parseES5DateFromNullTerminatedCharacters):
+        * wtf/DateMath.h:
+
 2010-10-14  Nikolas Zimmermann  <nzimmermann at rim.com>
 
         Reviewed by Gavin Barraclough.
diff --git a/JavaScriptCore/runtime/DateConversion.cpp b/JavaScriptCore/runtime/DateConversion.cpp
index 7eb82e4..d4b8232 100644
--- a/JavaScriptCore/runtime/DateConversion.cpp
+++ b/JavaScriptCore/runtime/DateConversion.cpp
@@ -57,7 +57,9 @@ double parseDate(ExecState* exec, const UString &date)
 {
     if (date == exec->globalData().cachedDateString)
         return exec->globalData().cachedDateStringValue;
-    double value = parseDateFromNullTerminatedCharacters(exec, date.utf8().data());
+    double value = parseES5DateFromNullTerminatedCharacters(date.utf8().data());
+    if (isnan(value))
+        value = parseDateFromNullTerminatedCharacters(exec, date.utf8().data());
     exec->globalData().cachedDateString = date;
     exec->globalData().cachedDateStringValue = value;
     return value;
diff --git a/JavaScriptCore/wtf/DateMath.cpp b/JavaScriptCore/wtf/DateMath.cpp
index b9a0207..99333ef 100644
--- a/JavaScriptCore/wtf/DateMath.cpp
+++ b/JavaScriptCore/wtf/DateMath.cpp
@@ -3,6 +3,7 @@
  * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
  * Copyright (C) 2009 Google Inc. All rights reserved.
  * Copyright (C) 2007-2009 Torch Mobile, Inc.
+ * Copyright (C) 2010 &yet, LLC. (nate at andyet.net)
  *
  * The Original Code is Mozilla Communicator client code, released
  * March 31, 1998.
@@ -479,7 +480,7 @@ void initializeDates()
     equivalentYearForDST(2000); // Need to call once to initialize a static used in this function.
 }
 
-static inline double ymdhmsToSeconds(long year, int mon, int day, int hour, int minute, int second)
+static inline double ymdhmsToSeconds(long year, int mon, int day, int hour, int minute, double second)
 {
     double days = (day - 32075)
         + floor(1461 * (year + 4800.0 + (mon - 14) / 12) / 4)
@@ -557,6 +558,162 @@ static bool parseLong(const char* string, char** stopPosition, int base, long* r
     return true;
 }
 
+double parseES5DateFromNullTerminatedCharacters(const char* dateString)
+{
+    // This parses a date of the form defined in ECMA-262-5, section 15.9.1.15
+    // (similar to RFC 3339 / ISO 8601: YYYY-MM-DDTHH:mm:ss[.sss]Z).
+    // In most cases it is intentionally strict (e.g. correct field widths, no stray whitespace).
+    
+    static const long daysPerMonth[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+    
+    const char* currentPosition = dateString;
+    char* postParsePosition;
+    
+    // This is a bit more lenient on the year string than ES5 specifies:
+    // instead of restricting to 4 digits (or 6 digits with mandatory +/-),
+    // it accepts any integer value. Consider this an implementation fallback.
+    long year;
+    if (!parseLong(currentPosition, &postParsePosition, 10, &year))
+        return NaN;
+    if (*postParsePosition != '-')
+        return NaN;
+    currentPosition = postParsePosition + 1;
+    
+    long month;
+    if (!isASCIIDigit(*currentPosition))
+        return NaN;
+    if (!parseLong(currentPosition, &postParsePosition, 10, &month))
+        return NaN;
+    if (*postParsePosition != '-' || (postParsePosition - currentPosition) != 2)
+        return NaN;
+    currentPosition = postParsePosition + 1;
+    
+    long day;
+    if (!isASCIIDigit(*currentPosition))
+        return NaN;
+    if (!parseLong(currentPosition, &postParsePosition, 10, &day))
+        return NaN;
+    if (*postParsePosition != 'T' || (postParsePosition - currentPosition) != 2)
+        return NaN;
+    currentPosition = postParsePosition + 1;
+    
+    long hours;
+    if (!isASCIIDigit(*currentPosition))
+        return NaN;
+    if (!parseLong(currentPosition, &postParsePosition, 10, &hours))
+        return NaN;
+    if (*postParsePosition != ':' || (postParsePosition - currentPosition) != 2)
+        return NaN;
+    currentPosition = postParsePosition + 1;
+    
+    long minutes;
+    if (!isASCIIDigit(*currentPosition))
+        return NaN;
+    if (!parseLong(currentPosition, &postParsePosition, 10, &minutes))
+        return NaN;
+    if (*postParsePosition != ':' || (postParsePosition - currentPosition) != 2)
+        return NaN;
+    currentPosition = postParsePosition + 1;
+    
+    long intSeconds;
+    if (!isASCIIDigit(*currentPosition))
+        return NaN;
+    if (!parseLong(currentPosition, &postParsePosition, 10, &intSeconds))
+        return NaN;
+    if ((postParsePosition - currentPosition) != 2)
+        return NaN;
+    
+    double seconds = intSeconds;
+    if (*postParsePosition == '.') {
+        currentPosition = postParsePosition + 1;
+        
+        // In ECMA-262-5 it's a bit unclear if '.' can be present without milliseconds, but
+        // a reasonable interpretation guided by the given examples and RFC 3339 says "no".
+        // We check the next character to avoid reading +/- timezone hours after an invalid decimal.
+        if (!isASCIIDigit(*currentPosition))
+            return NaN;
+        
+        // We are more lenient than ES5 by accepting more or less than 3 fraction digits.
+        long fracSeconds;
+        if (!parseLong(currentPosition, &postParsePosition, 10, &fracSeconds))
+            return NaN;
+        
+        long numFracDigits = postParsePosition - currentPosition;
+        seconds += fracSeconds * pow(10, -numFracDigits);
+    }
+    currentPosition = postParsePosition;
+    
+    // A few of these checks could be done inline above, but since many of them are interrelated
+    // we would be sacrificing readability to "optimize" the (presumably less common) failure path.
+    if (month < 1 || month > 12)
+        return NaN;
+    if (day < 1 || day > daysPerMonth[month - 1])
+        return NaN;
+    if (month == 2 && day > 28 && !isLeapYear(year))
+        return NaN;
+    if (hours < 0 || hours > 24)
+        return NaN;
+    if (hours == 24 && (minutes || seconds))
+        return NaN;
+    if (minutes < 0 || minutes > 59)
+        return NaN;
+    if (seconds < 0 || seconds >= 61)
+        return NaN;
+    if (seconds > 60) {
+        // Discard leap seconds by clamping to the end of a minute.
+        seconds = 60;
+    }
+    
+    long timeZoneSeconds = 0;
+    if (*currentPosition != 'Z') {
+        bool tzNegative;
+        if (*currentPosition == '-')
+            tzNegative = true;
+        else if (*currentPosition == '+')
+            tzNegative = false;
+        else
+            return NaN;
+        currentPosition += 1;
+        
+        long tzHours;
+        long tzHoursAbs;
+        long tzMinutes;
+        
+        if (!isASCIIDigit(*currentPosition))
+            return NaN;
+        if (!parseLong(currentPosition, &postParsePosition, 10, &tzHours))
+            return NaN;
+        if (*postParsePosition != ':' || (postParsePosition - currentPosition) != 2)
+            return NaN;
+        tzHoursAbs = abs(tzHours);
+        currentPosition = postParsePosition + 1;
+        
+        if (!isASCIIDigit(*currentPosition))
+            return NaN;
+        if (!parseLong(currentPosition, &postParsePosition, 10, &tzMinutes))
+            return NaN;
+        if ((postParsePosition - currentPosition) != 2)
+            return NaN;
+        currentPosition = postParsePosition;
+        
+        if (tzHoursAbs > 24)
+            return NaN;
+        if (tzMinutes < 0 || tzMinutes > 59)
+            return NaN;
+        
+        timeZoneSeconds = 60 * (tzMinutes + (60 * tzHoursAbs));
+        if (tzNegative)
+            timeZoneSeconds = -timeZoneSeconds;
+    } else {
+        currentPosition += 1;
+    }
+    if (*currentPosition)
+        return NaN;
+    
+    double dateSeconds = ymdhmsToSeconds(year, month, day, hours, minutes, seconds) - timeZoneSeconds;
+    return dateSeconds * msPerSecond;
+}
+
 // Odd case where 'exec' is allowed to be 0, to accomodate a caller in WebCore.
 static double parseDateFromNullTerminatedCharacters(const char* dateString, bool& haveTZ, int& offset)
 {
diff --git a/JavaScriptCore/wtf/DateMath.h b/JavaScriptCore/wtf/DateMath.h
index 033d25e..0f006ca 100644
--- a/JavaScriptCore/wtf/DateMath.h
+++ b/JavaScriptCore/wtf/DateMath.h
@@ -53,7 +53,8 @@ namespace WTF {
 void initializeDates();
 int equivalentYearForDST(int year);
 
-// Not really math related, but this is currently the only shared place to put these.  
+// Not really math related, but this is currently the only shared place to put these.
+double parseES5DateFromNullTerminatedCharacters(const char* dateString);
 double parseDateFromNullTerminatedCharacters(const char* dateString);
 double timeClip(double);
 
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index 3999668..3c441da 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,13 @@
+2010-10-14  Nathan Vander Wilt  <nate at andyet.net>
+
+        Reviewed by Darin Adler.
+
+        Added tests for https://bugs.webkit.org/show_bug.cgi?id=44632
+
+        * fast/js/date-parse-test-expected.txt:
+        * fast/js/script-tests/date-parse-test.js:
+        (testDateParseExact):
+
 2010-10-14  Justin Schuh  <jschuh at chromium.org>
 
         Reviewed by James Robinson.
diff --git a/LayoutTests/fast/js/date-parse-test-expected.txt b/LayoutTests/fast/js/date-parse-test-expected.txt
index 7da358f..a418cec 100644
--- a/LayoutTests/fast/js/date-parse-test-expected.txt
+++ b/LayoutTests/fast/js/date-parse-test-expected.txt
@@ -3,6 +3,32 @@ Test of JavaScript date parsing.
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
+PASS Date.parse("1995-12-25T01:30:00Z") == 819855000000 is true
+PASS Date.parse("1995-12-25T01:30:00.5Z") == 819855000500 is true
+PASS Date.parse("1995-12-25T01:30:00.009Z") == 819855000009 is true
+PASS Date.parse("1995-12-25T01:30:00+00:00") == 819855000000 is true
+PASS Date.parse("1995-12-25T01:30:00.0+00:01") == 819854940000 is true
+PASS Date.parse("1995-12-25T01:30:00.0-00:01") == 819855060000 is true
+PASS Date.parse("1995-12-25T01:30:00.0+01:01") == 819851340000 is true
+PASS Date.parse("1995-12-25T01:30:00.0-01:01") == 819858660000 is true
+PASS Date.parse("0000-01-01T00:00:00Z") == -62167219200000 is true
+PASS Date.parse("+99999-12-31T24:00:00Z") == 3093527980800000 is true
+PASS Date.parse("-99999-01-01T00:00:00Z") == -3217830796800000 is true
+PASS Date.parse("1995-12-31T23:59:60Z") == 820454400000 is true
+PASS Date.parse("1995-12-31T23:59:60.5Z") == 820454400000 is true
+PASS Date.parse("1995-13-25T01:30:00Z") is NaN
+PASS Date.parse("1995-00-25T01:30:00Z") is NaN
+PASS Date.parse("1995--1-25T01:30:00Z") is NaN
+PASS Date.parse("1995-01-25T01:05:-0.3Z") is NaN
+PASS Date.parse("1995/12/25T01:30:00Z") is NaN
+PASS Date.parse("1995-12-25T1:30:00Z") is NaN
+PASS Date.parse("1995-12-25T01:30:00.Z") is NaN
+PASS Date.parse("1995-12-25T01:30:00.+1Z") is NaN
+PASS Date.parse("1995-12-25T01:30:00Z ") is NaN
+PASS Date.parse("1995-12-25T01:30:00+00:00 ") is NaN
+PASS Date.parse("1995-02-29T00:00:00Z") is NaN
+PASS Date.parse("1995-12-25 01:30:00Z") is NaN
+PASS Date.parse("1995-12-25T01:30:00z") is NaN
 PASS Date.parse("Dec 25 1995 GMT") == 819849600000 is true
 PASS Date.parse("DEC 25 1995 GMT") == 819849600000 is true
 PASS Date.parse("dec 25 1995 gmt") == 819849600000 is true
diff --git a/LayoutTests/fast/js/script-tests/date-parse-test.js b/LayoutTests/fast/js/script-tests/date-parse-test.js
index 3f23e53..f5ab25d 100644
--- a/LayoutTests/fast/js/script-tests/date-parse-test.js
+++ b/LayoutTests/fast/js/script-tests/date-parse-test.js
@@ -28,6 +28,49 @@ function testDateParse(date, numericResult)
     }
 }
 
+function testDateParseExact(date, numericResult)
+{
+    if (numericResult == "NaN") {
+        shouldBeNaN('Date.parse("' + date + '")');
+    } else {
+        shouldBeTrue('Date.parse("' + date + '") == ' + numericResult.toString());
+    }
+}
+
+
+// test ECMAScript 5 standard date parsing
+testDateParseExact("1995-12-25T01:30:00Z", "819855000000");
+testDateParseExact("1995-12-25T01:30:00.5Z", "819855000500");
+testDateParseExact("1995-12-25T01:30:00.009Z", "819855000009");
+testDateParseExact("1995-12-25T01:30:00+00:00", "819855000000");
+testDateParseExact("1995-12-25T01:30:00.0+00:01", "819854940000");
+testDateParseExact("1995-12-25T01:30:00.0-00:01", "819855060000");
+testDateParseExact("1995-12-25T01:30:00.0+01:01", "819851340000");
+testDateParseExact("1995-12-25T01:30:00.0-01:01", "819858660000");
+
+testDateParseExact("0000-01-01T00:00:00Z", "-62167219200000");
+testDateParseExact("+99999-12-31T24:00:00Z", "3093527980800000");
+testDateParseExact("-99999-01-01T00:00:00Z", "-3217830796800000");
+testDateParseExact("1995-12-31T23:59:60Z", "820454400000");
+testDateParseExact("1995-12-31T23:59:60.5Z", "820454400000");
+
+testDateParseExact("1995-13-25T01:30:00Z", "NaN");
+testDateParseExact("1995-00-25T01:30:00Z", "NaN");
+testDateParseExact("1995--1-25T01:30:00Z", "NaN");
+testDateParseExact("1995-01-25T01:05:-0.3Z", "NaN");
+testDateParseExact("1995/12/25T01:30:00Z", "NaN");
+testDateParseExact("1995-12-25T1:30:00Z", "NaN");
+testDateParseExact("1995-12-25T01:30:00.Z", "NaN");
+testDateParseExact("1995-12-25T01:30:00.+1Z", "NaN");
+testDateParseExact("1995-12-25T01:30:00Z ", "NaN");
+testDateParseExact("1995-12-25T01:30:00+00:00 ", "NaN");
+testDateParseExact("1995-02-29T00:00:00Z", "NaN");
+testDateParseExact("1995-12-25 01:30:00Z", "NaN");
+testDateParseExact("1995-12-25T01:30:00z", "NaN");
+
+
+// test old implementation fallback
+
 var timeZoneOffset = Date.parse(" Dec 25 1995 1:30 ") - Date.parse(" Dec 25 1995 1:30 GMT ");
 
 testDateParse("Dec 25 1995 GMT", "819849600000");
@@ -43,7 +86,7 @@ testDateParse("Dec 25 1995 1:30 AM ", "819855000000 + timeZoneOffset");
 
 testDateParse("Dec 25 1995 13:30 GMT", "819898200000");
 testDateParse("Dec 25 1995 13:30", "819898200000 + timeZoneOffset");
-testDateParse('Dec 25 13:30 1995', "819898200000 + timeZoneOffset");
+testDateParse("Dec 25 13:30 1995", "819898200000 + timeZoneOffset");
 testDateParse("Dec 25 1995 13:30 ", "819898200000 + timeZoneOffset");
 testDateParse("Dec 25 1995 1:30 PM GMT", "819898200000");
 testDateParse("Dec 25 1995 1:30 PM", "819898200000 + timeZoneOffset");

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list