Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit 0ae0887

Browse files
committed
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
1 parent 2549313 commit 0ae0887

File tree

2 files changed

+66
-18
lines changed

2 files changed

+66
-18
lines changed

src/ng/directive/input.js

+18-10
Original file line numberDiff line numberDiff line change
@@ -1411,7 +1411,7 @@ function weekParser(isoWeek, existingDate) {
14111411
}
14121412

14131413
function createDateParser(regexp, mapping) {
1414-
return function(iso, date) {
1414+
return function(iso, previousDate) {
14151415
var parts, map;
14161416

14171417
if (isDate(iso)) {
@@ -1433,15 +1433,15 @@ function createDateParser(regexp, mapping) {
14331433

14341434
if (parts) {
14351435
parts.shift();
1436-
if (date) {
1436+
if (previousDate) {
14371437
map = {
1438-
yyyy: date.getFullYear(),
1439-
MM: date.getMonth() + 1,
1440-
dd: date.getDate(),
1441-
HH: date.getHours(),
1442-
mm: date.getMinutes(),
1443-
ss: date.getSeconds(),
1444-
sss: date.getMilliseconds() / 1000
1438+
yyyy: previousDate.getFullYear(),
1439+
MM: previousDate.getMonth() + 1,
1440+
dd: previousDate.getDate(),
1441+
HH: previousDate.getHours(),
1442+
mm: previousDate.getMinutes(),
1443+
ss: previousDate.getSeconds(),
1444+
sss: previousDate.getMilliseconds() / 1000
14451445
};
14461446
} else {
14471447
map = { yyyy: 1970, MM: 1, dd: 1, HH: 0, mm: 0, ss: 0, sss: 0 };
@@ -1452,7 +1452,15 @@ function createDateParser(regexp, mapping) {
14521452
map[mapping[index]] = +part;
14531453
}
14541454
});
1455-
return new Date(map.yyyy, map.MM - 1, map.dd, map.HH, map.mm, map.ss || 0, map.sss * 1000 || 0);
1455+
1456+
var date = new Date(map.yyyy, map.MM - 1, map.dd, map.HH, map.mm, map.ss || 0, map.sss * 1000 || 0);
1457+
if (map.yyyy < 100) {
1458+
// In the constructor, 2-digit years map to 1900-1999.
1459+
// Use `setFullYear()` to set the correct year.
1460+
date.setFullYear(map.yyyy);
1461+
}
1462+
1463+
return date;
14561464
}
14571465
}
14581466

test/ng/directive/inputSpec.js

+48-8
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,18 @@
33
/* globals generateInputCompilerHelper: false */
44

55
describe('input', function() {
6-
var helper = {}, $compile, $rootScope, $browser, $sniffer, $timeout, $q;
6+
var helper = {}, $compile, $rootScope, $browser, $sniffer;
77

88
// UA sniffing to exclude Edge from some date input tests
99
var isEdge = /\bEdge\//.test(window.navigator.userAgent);
1010

1111
generateInputCompilerHelper(helper);
1212

13-
beforeEach(inject(function(_$compile_, _$rootScope_, _$browser_, _$sniffer_, _$timeout_, _$q_) {
13+
beforeEach(inject(function(_$compile_, _$rootScope_, _$browser_, _$sniffer_) {
1414
$compile = _$compile_;
1515
$rootScope = _$rootScope_;
1616
$browser = _$browser_;
1717
$sniffer = _$sniffer_;
18-
$timeout = _$timeout_;
19-
$q = _$q_;
2018
}));
2119

2220

@@ -733,6 +731,8 @@ describe('input', function() {
733731
});
734732

735733

734+
// Support: Edge 16
735+
// Edge does not support years with any number of digits other than 4.
736736
if (!isEdge) {
737737
it('should allow four or more digits in year', function() {
738738
var inputElm = helper.compileInput('<input type="month" ng-model="value" ng-model-options="{timezone: \'UTC\'}"/>');
@@ -965,6 +965,8 @@ describe('input', function() {
965965
expect(inputElm).toBeValid();
966966
});
967967

968+
// Support: Edge 16
969+
// Edge does not support years with any number of digits other than 4.
968970
if (!isEdge) {
969971
it('should allow four or more digits in year', function() {
970972
var inputElm = helper.compileInput('<input type="week" ng-model="value" ng-model-options="{timezone: \'UTC\'}"/>');
@@ -1329,6 +1331,8 @@ describe('input', function() {
13291331
});
13301332

13311333

1334+
// Support: Edge 16
1335+
// Edge does not support years with any number of digits other than 4.
13321336
if (!isEdge) {
13331337
it('should allow four or more digits in year', function() {
13341338
var inputElm = helper.compileInput('<input type="datetime-local" ng-model="value" />');
@@ -1535,6 +1539,24 @@ describe('input', function() {
15351539

15361540
expect(inputElm).toBeValid();
15371541
});
1542+
1543+
1544+
// Support: Edge 16
1545+
// Edge does not support years with any number of digits other than 4.
1546+
if (!isEdge) {
1547+
it('should correctly handle 2-digit years', function() {
1548+
helper.compileInput('<input type="datetime-local" ng-model="value" name="alias" />');
1549+
1550+
helper.changeInputValueTo('0001-01-01T12:34:00');
1551+
expect($rootScope.value.getFullYear()).toBe(1);
1552+
1553+
helper.changeInputValueTo('0099-01-01T12:34:00');
1554+
expect($rootScope.value.getFullYear()).toBe(99);
1555+
1556+
helper.changeInputValueTo('0100-01-01T12:34:00');
1557+
expect($rootScope.value.getFullYear()).toBe(100);
1558+
});
1559+
}
15381560
});
15391561

15401562

@@ -2305,9 +2327,9 @@ describe('input', function() {
23052327

23062328
it('should allow Date objects as valid ng-max values', function() {
23072329
$rootScope.max = new Date(2012, 1, 1, 1, 2, 0);
2308-
var inputElm = helper.compileInput('<input type="datetime-local" ng-model="value" name="alias" ng-max="max" />');
2330+
var inputElm = helper.compileInput('<input type="date" ng-model="value" name="alias" ng-max="max" />');
23092331

2310-
helper.changeInputValueTo('2014-01-01T12:34:00');
2332+
helper.changeInputValueTo('2014-01-01');
23112333
expect(inputElm).toBeInvalid();
23122334

23132335
$rootScope.max = new Date(2013, 1, 1, 1, 2, 0);
@@ -2324,9 +2346,9 @@ describe('input', function() {
23242346

23252347
it('should allow Date objects as valid ng-min values', function() {
23262348
$rootScope.min = new Date(2013, 1, 1, 1, 2, 0);
2327-
var inputElm = helper.compileInput('<input type="datetime-local" ng-model="value" name="alias" ng-min="min" />');
2349+
var inputElm = helper.compileInput('<input type="date" ng-model="value" name="alias" ng-min="min" />');
23282350

2329-
helper.changeInputValueTo('2010-01-01T12:34:00');
2351+
helper.changeInputValueTo('2010-01-01');
23302352
expect(inputElm).toBeInvalid();
23312353

23322354
$rootScope.min = new Date(2014, 1, 1, 1, 2, 0);
@@ -2340,6 +2362,24 @@ describe('input', function() {
23402362
expect(inputElm).toBeValid();
23412363
});
23422364

2365+
// Support: Edge 16
2366+
// Edge does not support years with any number of digits other than 4.
2367+
if (!isEdge) {
2368+
it('should correctly handle 2-digit years', function() {
2369+
helper.compileInput('<input type="date" ng-model="value" name="alias" />');
2370+
2371+
helper.changeInputValueTo('0001-01-01');
2372+
expect($rootScope.value.getFullYear()).toBe(1);
2373+
2374+
helper.changeInputValueTo('0099-01-01');
2375+
expect($rootScope.value.getFullYear()).toBe(99);
2376+
2377+
helper.changeInputValueTo('0100-01-01');
2378+
expect($rootScope.value.getFullYear()).toBe(100);
2379+
});
2380+
}
2381+
2382+
23432383
describe('ISO_DATE_REGEXP', function() {
23442384
var dates = [
23452385
// Validate date

0 commit comments

Comments
 (0)