fix(input[date]): correctly parse 2-digit years

When parsing a date string value, AngularJS uses `new Date(year, ...)`
to create a Date object and assign it to the model. In the constructor,
2-digit years map to 1900-1999, so the created Date object has the wrong
value for year.
This commit fixes it, by explicitly using `setFullYear()` to set the
year to the correct value, when necessary.

Fixes #16537

Closes #16539
This commit is contained in:
George Kalpakas
2018-04-25 02:21:15 +03:00
parent 841feb0a05
commit 627180fb71
2 changed files with 66 additions and 18 deletions
+18 -10
View File
@@ -1415,7 +1415,7 @@ function weekParser(isoWeek, existingDate) {
}
function createDateParser(regexp, mapping) {
return function(iso, date) {
return function(iso, previousDate) {
var parts, map;
if (isDate(iso)) {
@@ -1437,15 +1437,15 @@ function createDateParser(regexp, mapping) {
if (parts) {
parts.shift();
if (date) {
if (previousDate) {
map = {
yyyy: date.getFullYear(),
MM: date.getMonth() + 1,
dd: date.getDate(),
HH: date.getHours(),
mm: date.getMinutes(),
ss: date.getSeconds(),
sss: date.getMilliseconds() / 1000
yyyy: previousDate.getFullYear(),
MM: previousDate.getMonth() + 1,
dd: previousDate.getDate(),
HH: previousDate.getHours(),
mm: previousDate.getMinutes(),
ss: previousDate.getSeconds(),
sss: previousDate.getMilliseconds() / 1000
};
} else {
map = { yyyy: 1970, MM: 1, dd: 1, HH: 0, mm: 0, ss: 0, sss: 0 };
@@ -1456,7 +1456,15 @@ function createDateParser(regexp, mapping) {
map[mapping[index]] = +part;
}
});
return new Date(map.yyyy, map.MM - 1, map.dd, map.HH, map.mm, map.ss || 0, map.sss * 1000 || 0);
var date = new Date(map.yyyy, map.MM - 1, map.dd, map.HH, map.mm, map.ss || 0, map.sss * 1000 || 0);
if (map.yyyy < 100) {
// In the constructor, 2-digit years map to 1900-1999.
// Use `setFullYear()` to set the correct year.
date.setFullYear(map.yyyy);
}
return date;
}
}
+48 -8
View File
@@ -3,20 +3,18 @@
/* globals generateInputCompilerHelper: false */
describe('input', function() {
var helper = {}, $compile, $rootScope, $browser, $sniffer, $timeout, $q;
var helper = {}, $compile, $rootScope, $browser, $sniffer;
// UA sniffing to exclude Edge from some date input tests
var isEdge = /\bEdge\//.test(window.navigator.userAgent);
generateInputCompilerHelper(helper);
beforeEach(inject(function(_$compile_, _$rootScope_, _$browser_, _$sniffer_, _$timeout_, _$q_) {
beforeEach(inject(function(_$compile_, _$rootScope_, _$browser_, _$sniffer_) {
$compile = _$compile_;
$rootScope = _$rootScope_;
$browser = _$browser_;
$sniffer = _$sniffer_;
$timeout = _$timeout_;
$q = _$q_;
}));
@@ -763,6 +761,8 @@ describe('input', function() {
});
// Support: Edge 16
// Edge does not support years with any number of digits other than 4.
if (!isEdge) {
it('should allow four or more digits in year', function() {
var inputElm = helper.compileInput('<input type="month" ng-model="value" ng-model-options="{timezone: \'UTC\'}"/>');
@@ -992,6 +992,8 @@ describe('input', function() {
expect(inputElm).toBeValid();
});
// Support: Edge 16
// Edge does not support years with any number of digits other than 4.
if (!isEdge) {
it('should allow four or more digits in year', function() {
var inputElm = helper.compileInput('<input type="week" ng-model="value" ng-model-options="{timezone: \'UTC\'}"/>');
@@ -1353,6 +1355,8 @@ describe('input', function() {
});
// Support: Edge 16
// Edge does not support years with any number of digits other than 4.
if (!isEdge) {
it('should allow four or more digits in year', function() {
var inputElm = helper.compileInput('<input type="datetime-local" ng-model="value" />');
@@ -1556,6 +1560,24 @@ describe('input', function() {
expect(inputElm).toBeValid();
});
// Support: Edge 16
// Edge does not support years with any number of digits other than 4.
if (!isEdge) {
it('should correctly handle 2-digit years', function() {
helper.compileInput('<input type="datetime-local" ng-model="value" name="alias" />');
helper.changeInputValueTo('0001-01-01T12:34:00');
expect($rootScope.value.getFullYear()).toBe(1);
helper.changeInputValueTo('0099-01-01T12:34:00');
expect($rootScope.value.getFullYear()).toBe(99);
helper.changeInputValueTo('0100-01-01T12:34:00');
expect($rootScope.value.getFullYear()).toBe(100);
});
}
});
@@ -2323,9 +2345,9 @@ describe('input', function() {
it('should allow Date objects as valid ng-max values', function() {
$rootScope.max = new Date(2012, 1, 1, 1, 2, 0);
var inputElm = helper.compileInput('<input type="datetime-local" ng-model="value" name="alias" ng-max="max" />');
var inputElm = helper.compileInput('<input type="date" ng-model="value" name="alias" ng-max="max" />');
helper.changeInputValueTo('2014-01-01T12:34:00');
helper.changeInputValueTo('2014-01-01');
expect(inputElm).toBeInvalid();
$rootScope.max = new Date(2013, 1, 1, 1, 2, 0);
@@ -2342,9 +2364,9 @@ describe('input', function() {
it('should allow Date objects as valid ng-min values', function() {
$rootScope.min = new Date(2013, 1, 1, 1, 2, 0);
var inputElm = helper.compileInput('<input type="datetime-local" ng-model="value" name="alias" ng-min="min" />');
var inputElm = helper.compileInput('<input type="date" ng-model="value" name="alias" ng-min="min" />');
helper.changeInputValueTo('2010-01-01T12:34:00');
helper.changeInputValueTo('2010-01-01');
expect(inputElm).toBeInvalid();
$rootScope.min = new Date(2014, 1, 1, 1, 2, 0);
@@ -2358,6 +2380,24 @@ describe('input', function() {
expect(inputElm).toBeValid();
});
// Support: Edge 16
// Edge does not support years with any number of digits other than 4.
if (!isEdge) {
it('should correctly handle 2-digit years', function() {
helper.compileInput('<input type="date" ng-model="value" name="alias" />');
helper.changeInputValueTo('0001-01-01');
expect($rootScope.value.getFullYear()).toBe(1);
helper.changeInputValueTo('0099-01-01');
expect($rootScope.value.getFullYear()).toBe(99);
helper.changeInputValueTo('0100-01-01');
expect($rootScope.value.getFullYear()).toBe(100);
});
}
describe('ISO_DATE_REGEXP', function() {
var dates = [
// Validate date