Bug 1265136 - Modify Date.parse's handling of two digit years to improve cross-compatibility; r=Waldo

--HG--
extra : rebase_source : 06add939e56d61394e05903c2e43049b1f831e00
This commit is contained in:
Morgan Phillips 2016-05-20 13:01:01 -07:00
Родитель e343bcae34
Коммит 7f8892b27f
5 изменённых файлов: 109 добавлений и 236 удалений

Просмотреть файл

@ -1104,55 +1104,49 @@ ParseDate(const CharT* s, size_t length, ClippedTime* result)
* Case 1. The input string contains an English month name.
* The form of the string can be month f l, or f month l, or
* f l month which each evaluate to the same date.
* If f and l are both greater than or equal to 70, or
* both less than 70, the date is invalid.
* The year is taken to be the greater of the values f, l.
* If the year is greater than or equal to 70 and less than 100,
* it is considered to be the number of years after 1900.
* If f and l are both greater than or equal to 100 the date
* is invalid.
*
* The year is taken to be either the greater of the values f, l or
* whichever is set to zero. If the year is greater than or equal to
* 50 and less than 100, it is considered to be the number of years
* after 1900. If the year is less than 50 it is considered to be the
* number of years after 2000, otherwise it is considered to be the
* number of years after 0.
*
* Case 2. The input string is of the form "f/m/l" where f, m and l are
* integers, e.g. 7/16/45.
* Adjust the mon, mday and year values to achieve 100% MSIE
* compatibility.
* a. If 0 <= f < 70, f/m/l is interpreted as month/day/year.
* i. If year < 100, it is the number of years after 1900
* ii. If year >= 100, it is the number of years after 0.
* b. If 70 <= f < 100
* i. If m < 70, f/m/l is interpreted as
* year/month/day where year is the number of years after
* 1900.
* ii. If m >= 70, the date is invalid.
* c. If f >= 100
* i. If m < 70, f/m/l is interpreted as
* year/month/day where year is the number of years after 0.
* ii. If m >= 70, the date is invalid.
* integers, e.g. 7/16/45. mon, mday and year values are adjusted
* to achieve Chrome compatibility.
*
* a. If 0 < f <= 12 and 0 < l <= 31, f/m/l is interpreted as
* month/day/year.
* i. If year < 50, it is the number of years after 2000
* ii. If year >= 50, it is the number of years after 1900.
* iii. If year >= 100, it is the number of years after 0.
* b. If 31 < f and 0 < m <= 12 and 0 < l <= 31 f/m/l is
* interpreted as year/month/day
* i. If year < 50, it is the number of years after 2000
* ii. If year >= 50, it is the number of years after 1900.
* iii. If year >= 100, it is the number of years after 0.
*/
if (seenMonthName) {
if ((mday >= 70 && year >= 70) || (mday < 70 && year < 70))
if (mday >= 100 && mon >= 100)
return false;
if (mday > year) {
if (year > 0 && (mday == 0 || mday > year)) {
int temp = year;
year = mday;
mday = temp;
}
if (year >= 70 && year < 100) {
year += 1900;
}
} else if (mon < 70) { /* (a) month/day/year */
if (year < 100) {
year += 1900;
}
} else if (mon < 100) { /* (b) year/month/day */
if (mday < 70) {
int temp = year;
year = mon + 1900;
mon = mday;
mday = temp;
} else {
if (mday <= 0 || mday > 31)
return false;
}
} else { /* (c) year/month/day */
if (mday < 70) {
} else if (0 < mon && mon <= 12 && 0 < mday && mday <= 31) {
/* (a) month/day/year */
} else {
/* (b) year/month/day */
if (mon > 31 && mday <= 12 && year <= 31) {
int temp = year;
year = mon;
mon = mday;
@ -1162,6 +1156,11 @@ ParseDate(const CharT* s, size_t length, ClippedTime* result)
}
}
if (year < 50)
year += 2000;
else if (year >= 50 && year < 100)
year += 1900;
mon -= 1; /* convert month to 0-based */
if (sec < 0)
sec = 0;

Просмотреть файл

@ -1,60 +0,0 @@
/* -*- tab-width: 2; indent-tabs-mode: nil; js-indent-level: 2 -*- */
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/
* Contributor: Bob Clary
*/
//-----------------------------------------------------------------------------
var BUGNUMBER = 273292;
var summary = '15.9.3.2 new Date(value)';
var actual = '';
var expect = '';
var date1;
var date2;
var i;
var validDateStrings = [
"11/69/2004",
"11/70/2004",
"69/69/2004",
"69/69/69",
"69/69/1969",
"70/69/70",
"70/69/1970",
"70/69/2004"
];
var invalidDateStrings = [
"70/70/70",
"70/70/1970",
"70/70/2004"
];
printBugNumber(BUGNUMBER);
printStatus (summary);
expect = 0;
for (i = 0; i < validDateStrings.length; i++)
{
date1 = new Date(validDateStrings[i]);
date2 = new Date(date1.toDateString());
actual = date2 - date1;
reportCompare(expect, actual, inSection(i) + ' ' +
validDateStrings[i]);
}
expect = true;
var offset = validDateStrings.length;
for (i = 0; i < invalidDateStrings.length; i++)
{
date1 = new Date(invalidDateStrings[i]);
actual = isNaN(date1);
reportCompare(expect, actual, inSection(i + offset) + ' ' +
invalidDateStrings[i] + ' is invalid.');
}

Просмотреть файл

@ -0,0 +1,69 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommonn.org/licenses/publicdomain/
*/
/*
* For the sake of cross compatibility with other implementations we
* implement date parsing heuristics which support single and double
* digit years. See bug: 1265136
*/
/**************
* BEGIN TEST *
**************/
for (let year of Array(100).keys()) {
for (let month of Array(12).keys()) {
for (let day of Array(31).keys()) {
let fullYear = year >= 50 ? year + 1900 : year + 2000;
let fullDate = new Date(`${month + 1}/${day + 1}/${fullYear}`);
// mm/dd/yy
let d1 = new Date(`${month + 1}/${day + 1}/${year}`);
assertEq(d1.getTime(), fullDate.getTime())
// yy/mm/dd
let d2 = new Date(`${year}/${month + 1}/${day + 1}`);
if (year > 31) {
assertEq(d2.getTime(), fullDate.getTime())
} else if (year > 12) {
assertEq(d2.getTime(), new Date(NaN).getTime())
}
}
}
}
assertEq(new Date("99/1/99").getTime(), new Date(NaN).getTime());
assertEq(new Date("13/13/13").getTime(), new Date(NaN).getTime());
assertEq(new Date("0/10/0").getTime(), new Date(NaN).getTime());
// Written months.
for (let year of Array(1000).keys()) {
let fullDate = new Date(`5/1/${year}`);
let d1 = new Date(`may ${year} 1`);
let d2 = new Date(`may 1 ${year}`);
let d3 = new Date(`1 may ${year}`);
let d4 = new Date(`${year} may 1`);
let d5 = new Date(`1 ${year} may`);
let d6 = new Date(`${year} 1 may`);
assertEq(d1.getTime(), fullDate.getTime())
assertEq(d2.getTime(), fullDate.getTime())
assertEq(d3.getTime(), fullDate.getTime())
assertEq(d4.getTime(), fullDate.getTime())
assertEq(d5.getTime(), fullDate.getTime())
assertEq(d6.getTime(), fullDate.getTime())
}
assertEq(new Date("may 1999 1999").getTime(), new Date(NaN).getTime());
assertEq(new Date("may 0 0").getTime(), new Date(NaN).getTime());
/******************************************************************************/
if (typeof reportCompare === "function")
reportCompare(true, true);
print("Tests complete");

Просмотреть файл

@ -1,130 +0,0 @@
/* -*- 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/. */
//-----------------------------------------------------------------------------
var BUGNUMBER = 301738;
var summary = 'Date parse compatibilty with MSIE';
var actual = '';
var expect = '';
printBugNumber(BUGNUMBER);
printStatus (summary);
/*
Case 2. The input string is of the form "f/m/l" where f, m and l are
integers, e.g. 7/16/45.
Adjust the mon, mday and year values to achieve 100% MSIE
compatibility.
a. If 0 <= f < 70, f/m/l is interpreted as month/day/year.
i. If year < 100, it is the number of years after 1900
ii. If year >= 100, it is the number of years after 0.
b. If 70 <= f < 100
i. If m < 70, f/m/l is interpreted as
year/month/day where year is the number of years after
1900.
ii. If m >= 70, the date is invalid.
c. If f >= 100
i. If m < 70, f/m/l is interpreted as
year/month/day where year is the number of years after 0.
ii. If m >= 70, the date is invalid.
*/
var f;
var m;
var l;
function newDate(f, m, l)
{
return new Date(f + '/' + m + '/' + l);
}
function newDesc(f, m, l)
{
return f + '/' + m + '/' + l;
}
// 2.a.i
f = 0;
m = 0;
l = 0;
expect = (new Date(l, f-1, m)).toDateString();
actual = newDate(f, m, l).toDateString();
reportCompare(expect, actual, newDesc(f, m, l));
f = 0;
m = 0;
l = 100;
expect = (new Date(l, f-1, m)).toDateString();
actual = newDate(f, m, l).toDateString();
reportCompare(expect, actual, newDesc(f, m, l));
// 2.a.ii
f = 0;
m = 24;
l = 100;
expect = (new Date(l, f-1, m)).toDateString();
actual = newDate(f, m, l).toDateString();
reportCompare(expect, actual, newDesc(f, m, l));
f = 0;
m = 24;
l = 2100;
expect = (new Date(l, f-1, m)).toDateString();
actual = newDate(f, m, l).toDateString();
reportCompare(expect, actual, newDesc(f, m, l));
// 2.b.i
f = 70;
m = 24;
l = 100;
expect = (new Date(f, m-1, l)).toDateString();
actual = newDate(f, m, l).toDateString();
reportCompare(expect, actual, newDesc(f, m, l));
f = 99;
m = 12;
l = 1;
expect = (new Date(f, m-1, l)).toDateString();
actual = newDate(f, m, l).toDateString();
reportCompare(expect, actual, newDesc(f, m, l));
// 2.b.ii.
f = 99;
m = 70;
l = 1;
expect = true;
actual = isNaN(newDate(f, m, l));
reportCompare(expect, actual, newDesc(f, m, l) + ' is an invalid date');
// 2.c.i
f = 100;
m = 12;
l = 1;
expect = (new Date(f, m-1, l)).toDateString();
actual = newDate(f, m, l).toDateString();
reportCompare(expect, actual, newDesc(f, m, l));
// 2.c.ii
f = 100;
m = 70;
l = 1;
expect = true;
actual = isNaN(newDate(f, m, l));
reportCompare(expect, actual, newDesc(f, m, l) + ' is an invalid date');

Просмотреть файл

@ -7,8 +7,8 @@
<window title="datepicker" width="500" height="600"
onload="setTimeout(testtag_datepickers, 0);"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
<hbox onpopupshown="testtag_datepicker_UI_popup()"
onpopuphidden="testtag_finish()">
@ -126,11 +126,6 @@ function testtag_datepicker(dp, type, testid)
setDateField("date", 0, true, 2002, 10, 15);
setDateField("date", 32, true, 2002, 10, 15);
// check that dates overflow properly
setDateField("value", "2002-2-40", false, 2002, 2, 12);
setDateField("value", "2003-03-32", false, 2003, 3, 1);
setDateField("value", "2003-12-32", false, 2004, 0, 1);
// check leap year handling
setDateField("value", "1600-2-29", false, 1600, 1, 29);
setDateField("value", "2000-2-29", false, 2000, 1, 29);