Bug 1860425 - Adjust parsing for timezone numbers without "GMT" prefix r=arai

Differential Revision: https://phabricator.services.mozilla.com/D191618
This commit is contained in:
Vinny Diehl 2023-10-25 09:31:43 +00:00
parent a28468e526
commit c7283bdb04
4 changed files with 191 additions and 32 deletions

View File

@ -1398,6 +1398,8 @@ static bool ParseDate(DateTimeInfo::ForceUTC forceUTC, const CharT* s,
bool seenMonthName = false;
bool seenFullYear = false;
bool negativeYear = false;
// Includes "GMT", "UTC", "UT", and "Z" timezone keywords
bool seenGmtAbbr = false;
size_t index = 0;
@ -1412,16 +1414,8 @@ static bool ParseDate(DateTimeInfo::ForceUTC forceUTC, const CharT* s,
TryParseDashedDatePrefix(s, length, &index, &year, &mon, &mday) ||
TryParseDashedNumericDatePrefix(s, length, &index, &year, &mon, &mday);
if (isDashedDate && index < length) {
if (strchr("T:+", s[index])) {
return false;
}
// If the next char is a '-', we need to skip it so that the next number
// doesn't get parsed as a time zone
if (s[index] == '-') {
index++;
}
if (isDashedDate && index < length && strchr("T:+", s[index])) {
return false;
}
while (index < length) {
@ -1435,6 +1429,17 @@ static bool ParseDate(DateTimeInfo::ForceUTC forceUTC, const CharT* s,
c = ' ';
}
if ((c == '+' || c == '-') &&
// Reject + or - after timezone (still allowing for negative year)
((seenPlusMinus && year != -1) ||
// Reject timezones like "1995-09-26 -04:30" (if the - is right up
// against the previous number, it will get parsed as a time,
// see the other comment below)
(year != -1 && hour == -1 && !seenGmtAbbr &&
!IsAsciiDigit(s[index - 2])))) {
return false;
}
// Spaces, ASCII control characters, periods, and commas are simply ignored.
if (c <= ' ' || c == '.' || c == ',') {
continue;
@ -1515,7 +1520,10 @@ static bool ParseDate(DateTimeInfo::ForceUTC forceUTC, const CharT* s,
year = n;
seenFullYear = true;
negativeYear = true;
} else if ((prevc == '+' || prevc == '-') /* && year>=0 */) {
} else if ((prevc == '+' || prevc == '-') &&
// "1995-09-26-04:30" needs to be parsed as a time,
// not a time zone
(seenGmtAbbr || hour != -1)) {
/* Make ':' case below change tzOffset. */
seenPlusMinus = true;
@ -1564,8 +1572,9 @@ static bool ParseDate(DateTimeInfo::ForceUTC forceUTC, const CharT* s,
}
} else if (index < length && c != ',' && c > ' ' && c != '-' &&
c != '(' &&
// Allow zulu time e.g. "09/26/1995 16:00Z"
!(hour != -1 && strchr("Zz", c)) &&
// Allow zulu time e.g. "09/26/1995 16:00Z", or
// '+' directly after time e.g. 00:00+0500
!(hour != -1 && strchr("Zz+", c)) &&
// Allow '.' after day of month i.e. DD.Mon.YYYY/Mon.DD.YYYY,
// or after year/month in YYYY/MM/DD
(c != '.' || mday != -1) &&
@ -1636,6 +1645,10 @@ static bool ParseDate(DateTimeInfo::ForceUTC forceUTC, const CharT* s,
break;
}
if (action == 10000) {
seenGmtAbbr = true;
}
// Perform action tests from smallest action values to largest.
// Adjust a previously-specified hour for AM/PM accordingly (taking care

View File

@ -44,11 +44,6 @@ const tests = [
["24-Apr-2023 12:34:56 -04:30", "2023-04-24T12:34:56-04:30"],
["24-Apr-2023 GMT", "2023-04-24T00:00:00Z"],
["24-Apr-2023 +04", "2023-04-24T00:00:00+04:00"],
["24-Apr-2023 +04:30", "2023-04-24T00:00:00+04:30"],
["24-Apr-2023 -04", "2023-04-24T00:00:00-04:00"],
["24-Apr-2023 -04:30", "2023-04-24T00:00:00-04:30"],
["24-Apr-2023GMT", "2023-04-24T00:00:00Z"],
["24-Apr-2023GMT-04", "2023-04-24T00:00:00-04:00"],
["24-Apr-2023GMT-04:30", "2023-04-24T00:00:00-04:30"],
@ -56,13 +51,9 @@ const tests = [
["24-Apr-2023GMT+04:30", "2023-04-24T00:00:00+04:30"],
["24-Apr-2023,GMT", "2023-04-24T00:00:00Z"],
["24-Apr-2023,+04", "2023-04-24T00:00:00+04:00"],
["24-Apr-2023,+04:30", "2023-04-24T00:00:00+04:30"],
["24-Apr-2023,-04", "2023-04-24T00:00:00-04:00"],
["24-Apr-2023,-04:30", "2023-04-24T00:00:00-04:30"],
["24-Apr-2023/GMT", "2023-04-24T00:00:00Z"],
["24-Apr-2023/12:34:56", "2023-04-24T12:34:56"],
["24-Apr-2023/GMT", "2023-04-24T00:00:00Z"],
// ==== non dd-MMM-yyyy. Uses fallback path ====
@ -100,6 +91,10 @@ const tests = [
["24-Apr-2312()10:13:14", "2312-04-24T10:13:14"],
// Open paren only comments out the time
["24-Apr-2312(10:13:14", "2312-04-24T00:00:00"],
// mday being 3+ digits, while year being 2-3 digits.
["024-Apr-23", "2023-04-24T00:00:00"],
["024-Apr-023", "2023-04-24T00:00:00"],
];
for (const [testString, isoString] of tests) {
@ -114,10 +109,6 @@ const invalidTests = [
// mday being out of range.
"32-01-32",
// mday being 3+ digits, while year being 2-3 digits.
"024-Apr-22",
"024-Apr-023",
// Duplicate date.
"2012-Apr-08 12/12/12",
@ -133,11 +124,6 @@ const invalidTests = [
"24-Apr-2312+10:13:14",
"24-Apr-2312=10:13:14",
"24-Apr-2312?10:13:14",
// No space between date and time zone w/o GMT
"24-Apr-2023+04",
"24-Apr-2023+04:30",
"24-Apr-2023-04",
];
for (const testString of invalidTests) {

View File

@ -0,0 +1,118 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const accepted = {
"1995-09-26T00:00:00-0500": [
"Sep 26 1995 GMT-0500",
"Sep 26 1995 00:00:00 GMT-0500",
"Sep 26 1995 00:00:00 gmt-0500",
"Sep 26 1995 00:00:00 Z-0500",
"Sep 26 1995 00:00:00 UT-0500",
"Sep 26 1995 00:00:00 UTC-0500",
"Sep 26 1995 00:00:00 -0500",
"Sep 26 1995 00:00:00 -05",
"Sep 26 1995 00:00:00-0500",
"Sep 26 1995 00:00:00-05",
"Sep 26 1995 00:00 -0500",
"Sep 26 1995 00:00 -05",
"Sep 26 1995 00:00-0500",
"Sep 26 1995 00:00-05",
],
"1995-09-26T00:00:00+0500": [
"Sep 26 1995 GMT+0500",
"Sep 26 1995 00:00:00 GMT+0500",
"Sep 26 1995 00:00:00 gmt+0500",
"Sep 26 1995 00:00:00 Z+0500",
"Sep 26 1995 00:00:00 UT+0500",
"Sep 26 1995 00:00:00 UTC+0500",
"Sep 26 1995 00:00:00 +0500",
"Sep 26 1995 00:00:00 +05",
"Sep 26 1995 00:00:00+0500",
"Sep 26 1995 00:00:00+05",
"Sep 26 1995 00:00 +0500",
"Sep 26 1995 00:00 +05",
"Sep 26 1995 00:00+0500",
"Sep 26 1995 00:00+05",
],
"1995-09-26T00:00:00-0430": [
"Sep 26 1995 GMT-04:30",
"Sep 26 1995 00:00:00 GMT-04:30",
"Sep 26 1995 00:00:00 -04:30",
"Sep 26 1995 00:00:00-04:30",
"Sep 26 1995 00:00 -04:30",
"Sep 26 1995 00:00-04:30",
],
"1995-09-26T00:00:00+0430": [
"Sep 26 1995 GMT+04:30",
"Sep 26 1995 00:00:00 GMT+04:30",
"Sep 26 1995 00:00:00 +04:30",
"Sep 26 1995 00:00:00+04:30",
"Sep 26 1995 00:00 +04:30",
"Sep 26 1995 00:00+04:30",
],
"1995-09-26T04:30:00": [
"Sep 26 1995-04:30",
"1995-09-26-04:30",
"1995-Sep-26-04:30",
],
};
const rejected = [
"Sep 26 1995 -05",
"Sep 26 1995-05",
"Sep 26 1995 -04:30",
"1995-09-26 -05",
"1995-09-26 -04:30",
"1995-09-26-05",
"1995-Sep-26 -05",
"1995-Sep-26-05",
"1995-Sep-26,-05",
"Sep 26 1995 +05",
"Sep 26 1995 +04:30",
"Sep 26 1995+05",
"Sep 26 1995+04:30",
"1995-09-26 +05",
"1995-09-26+05",
"1995-Sep-26 +05",
"1995-Sep-26+05",
"1995-Sep-26,+05",
// These cases are allowed by V8 but are parsed as GMT-XXXX no matter the
// abbreviation (e.g. EST-0500 is parsed as GMT-0500 and not GMT-1000). This
// is unexpected and so we are explicitly rejecting them.
"Sep 26 1995 00:00:00 EST-0500",
"Sep 26 1995 00:00:00 MDT-0500",
];
for (const [expected, patterns] of Object.entries(accepted)) {
for (const test of patterns) {
const testDate = new Date(test);
const expectedDate = new Date(expected);
assertEq(
false, isNaN(testDate),
`${test} should be accepted.`
);
assertEq(
testDate.getTime(), expectedDate.getTime(),
`"${test}" should be ${expectedDate} (got ${testDate}).`
);
}
}
for (const reject of rejected) {
assertEq(
true, isNaN(new Date(reject)),
`"${reject}" should be rejected.`
);
}
if (typeof reportCompare === "function")
reportCompare(true, true);

View File

@ -0,0 +1,42 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const accepted = {
"1997-11-05T00:00:00-0800": [
"Wed Nov 05 00:00:00 GMT-0800 1997",
"Nov 05 00:00:00 GMT-0800 1997",
"Nov-05 00:00:00 GMT-0800 1997",
"05-Nov 00:00:00 GMT-0800 1997",
"05-Nov GMT-0800 1997",
],
"-001997-11-05T00:00:00-0800": [
"Wed Nov 05 00:00:00 GMT-0800 -1997",
"Nov 05 00:00:00 GMT-0800 -1997",
"Nov-05 00:00:00 GMT-0800 -1997",
"05-Nov 00:00:00 GMT-0800 -1997",
"05-Nov GMT-0800 -1997",
],
};
for (const [expected, patterns] of Object.entries(accepted)) {
for (const test of patterns) {
const testDate = new Date(test);
const expectedDate = new Date(expected);
assertEq(
false, isNaN(testDate),
`${test} should be accepted.`
);
assertEq(
testDate.getTime(), expectedDate.getTime(),
`"${test}" should be ${expectedDate} (got ${testDate}).`
);
}
}
if (typeof reportCompare === "function")
reportCompare(true, true);