Added: trunk/JSTests/stress/relaxed-timezone-designators.js (0 => 254939)
--- trunk/JSTests/stress/relaxed-timezone-designators.js (rev 0)
+++ trunk/JSTests/stress/relaxed-timezone-designators.js 2020-01-22 20:55:31 UTC (rev 254939)
@@ -0,0 +1,96 @@
+function shouldBe(actual, expected) {
+ if (Number.isNaN(actual) || actual !== expected)
+ throw new Error('bad value: ' + actual);
+}
+
+function parsedDate(string) {
+ return Date.parse(string);
+}
+
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000+`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000-`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000+0`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000-0`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000+000`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000-000`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000+00000`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000-00000`)), true);
+
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000+:00`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000-:00`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000+0:00`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000-0:00`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000+000:00`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000-000:00`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000+0000:00`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000-0000:00`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000+00000:00`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000-00000:00`)), true);
+
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000+00:`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000-00:`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000+00:0`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000-00:0`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000+00:000`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000-00:000`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000+00:0000`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000-00:0000`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000+00:00000`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000-00:00000`)), true);
+
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000+25`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000-25`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000+2500`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000-2500`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000+0080`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000-0080`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000+0060`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000-0060`)), true);
+
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000+24A`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000-24A`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000+2400A`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000-2400A`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000+0080A`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000-0080A`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000+0059A`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000-0059A`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000+24:00A`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000-24:00A`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000+00:80A`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000-00:80A`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000+00:59A`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000-00:59A`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000+24:00:`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000-24:00:`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000+00:80:`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000-00:80:`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000+00:59:`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000-00:59:`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000+24:00:00`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000-24:00:00`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000+00:80:00`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000-00:80:00`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000+00:59:00`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000-00:59:00`)), true);
+
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000++2`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000-+2`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000++200`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000-+200`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000+00:0+`)), true);
+shouldBe(Number.isNaN(parsedDate(`1970-01-01T00:00:00.000-00:0+`)), true);
+
+shouldBe(parsedDate(`1970-01-01T00:00:00.000+00`), 0);
+shouldBe(parsedDate(`1970-01-01T00:00:00.000-00`), 0);
+shouldBe(parsedDate(`1970-01-01T00:00:00.000+0000`), 0);
+shouldBe(parsedDate(`1970-01-01T00:00:00.000-0000`), 0);
+shouldBe(parsedDate(`1970-01-01T00:00:00.000+0030`), -(60 * 30 * 1000));
+shouldBe(parsedDate(`1970-01-01T00:00:00.000-0030`), +(60 * 30 * 1000));
+shouldBe(parsedDate(`1970-01-01T00:00:00.000+0130`), -(60 * (30 + 60) * 1000));
+shouldBe(parsedDate(`1970-01-01T00:00:00.000-0130`), +(60 * (30 + 60) * 1000));
+
+shouldBe(parsedDate(`1970-01-01T00:00:00.000+24:59`), -((24 * 60 + 59) * 60 * 1000));
+shouldBe(parsedDate(`1970-01-01T00:00:00.000-24:59`), +((24 * 60 + 59) * 60 * 1000));
+shouldBe(parsedDate(`1970-01-01T00:00:00.000+2459`), -((24 * 60 + 59) * 60 * 1000));
+shouldBe(parsedDate(`1970-01-01T00:00:00.000-2459`), +((24 * 60 + 59) * 60 * 1000));
Modified: trunk/LayoutTests/js/script-tests/date-parse-test.js (254938 => 254939)
--- trunk/LayoutTests/js/script-tests/date-parse-test.js 2020-01-22 20:52:50 UTC (rev 254938)
+++ trunk/LayoutTests/js/script-tests/date-parse-test.js 2020-01-22 20:55:31 UTC (rev 254939)
@@ -130,9 +130,12 @@
shouldBe("String(Date.parse('1970-01-01T00:00:00.000-'))", '"NaN"');
shouldBe("String(Date.parse('1970-01-01T00:00:00.000+'))", '"NaN"');
shouldBe("String(Date.parse('1970-01-01T00:00:00.000+0'))", '"NaN"');
-shouldBe("String(Date.parse('1970-01-01T00:00:00.000+00'))", '"NaN"');
+shouldBe("String(Date.parse('1970-01-01T00:00:00.000+00'))", '"0"');
shouldBe("String(Date.parse('1970-01-01T00:00:00.000+00:'))", '"NaN"');
shouldBe("String(Date.parse('1970-01-01T00:00:00.000+00:0'))", '"NaN"');
+shouldBe("String(Date.parse('1970-01-01T00:00:00.000+0000'))", '"0"');
+shouldBe("String(Date.parse('1970-01-01T00:00:00.000+0000:'))", '"NaN"');
+shouldBe("String(Date.parse('1970-01-01T00:00:00.000+0000:0'))", '"NaN"');
shouldBe("String(Date.parse('1970-01-01T00:00:00.000+0:0'))", '"NaN"');
// test old implementation fallback
Modified: trunk/Source/WTF/wtf/DateMath.cpp (254938 => 254939)
--- trunk/Source/WTF/wtf/DateMath.cpp 2020-01-22 20:52:50 UTC (rev 254938)
+++ trunk/Source/WTF/wtf/DateMath.cpp 2020-01-22 20:55:31 UTC (rev 254939)
@@ -518,7 +518,7 @@
return postParsePosition;
}
-// Parses a time with the format HH:mm[:ss[.sss]][Z|(+|-)00:00].
+// Parses a time with the format HH:mm[:ss[.sss]][Z|(+|-)(00:00|0000|00)].
// Fractional seconds parsing is lenient, allows any number of digits.
// Returns 0 if a parse error occurs, else returns the end of the parsed portion of the string.
static char* parseES5TimePortion(char* currentPosition, long& hours, long& minutes, double& seconds, bool& isLocalTime, long& timeZoneSeconds)
@@ -577,6 +577,7 @@
if (*currentPosition == 'Z')
return currentPosition + 1;
+ // Parse (+|-)(00:00|0000|00).
bool tzNegative;
if (*currentPosition == '-')
tzNegative = true;
@@ -588,25 +589,39 @@
}
++currentPosition;
- long tzHours;
- long tzHoursAbs;
- long tzMinutes;
+ long tzHours = 0;
+ long tzHoursAbs = 0;
+ long tzMinutes = 0;
if (!isASCIIDigit(*currentPosition))
return 0;
if (!parseLong(currentPosition, &postParsePosition, 10, &tzHours))
return 0;
- if (*postParsePosition != ':' || (postParsePosition - currentPosition) != 2)
- return 0;
- tzHoursAbs = labs(tzHours);
- currentPosition = postParsePosition + 1;
+ if (*postParsePosition != ':') {
+ if ((postParsePosition - currentPosition) == 2) {
+ // "00" case.
+ tzHoursAbs = labs(tzHours);
+ } else if ((postParsePosition - currentPosition) == 4) {
+ // "0000" case.
+ tzHoursAbs = labs(tzHours);
+ tzMinutes = tzHoursAbs % 100;
+ tzHoursAbs = tzHoursAbs / 100;
+ } else
+ return 0;
+ } else {
+ // "00:00" case.
+ if ((postParsePosition - currentPosition) != 2)
+ return 0;
+ tzHoursAbs = labs(tzHours);
+ currentPosition = postParsePosition + 1; // Skip ":".
- if (!isASCIIDigit(*currentPosition))
- return 0;
- if (!parseLong(currentPosition, &postParsePosition, 10, &tzMinutes))
- return 0;
- if ((postParsePosition - currentPosition) != 2)
- return 0;
+ if (!isASCIIDigit(*currentPosition))
+ return 0;
+ if (!parseLong(currentPosition, &postParsePosition, 10, &tzMinutes))
+ return 0;
+ if ((postParsePosition - currentPosition) != 2)
+ return 0;
+ }
currentPosition = postParsePosition;
if (tzHoursAbs > 24)
@@ -647,7 +662,7 @@
// Look for a time portion.
// Note: As of ES2016, when a UTC offset is missing, date-time forms are local time while date-only forms are UTC.
if (*currentPosition == 'T') {
- // Parse the time HH:mm[:ss[.sss]][Z|(+|-)00:00]
+ // Parse the time HH:mm[:ss[.sss]][Z|(+|-)(00:00|0000|00)]
currentPosition = parseES5TimePortion(currentPosition + 1, hours, minutes, seconds, isLocalTime, timeZoneSeconds);
if (!currentPosition)
return std::numeric_limits<double>::quiet_NaN();