[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