From d4d85c3206db8183ea88642ef3f069c3bb0af732 Mon Sep 17 00:00:00 2001 From: George Kalpakas Date: Wed, 25 Apr 2018 02:21:15 +0300 Subject: [PATCH 1/2] 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 --- src/ng/directive/input.js | 28 ++++++++++++++-------- test/ng/directive/inputSpec.js | 43 +++++++++++++++++++++++++++------- 2 files changed, 53 insertions(+), 18 deletions(-) diff --git a/src/ng/directive/input.js b/src/ng/directive/input.js index 93119d305d42..b314a36f3d84 100644 --- a/src/ng/directive/input.js +++ b/src/ng/directive/input.js @@ -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; } } diff --git a/test/ng/directive/inputSpec.js b/test/ng/directive/inputSpec.js index 658ce6adf955..11fc5219ab3f 100644 --- a/test/ng/directive/inputSpec.js +++ b/test/ng/directive/inputSpec.js @@ -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_; })); @@ -1556,6 +1554,20 @@ describe('input', function() { expect(inputElm).toBeValid(); }); + + + it('should correctly handle 2-digit years', function() { + helper.compileInput(''); + + 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 +2335,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(''); + var inputElm = helper.compileInput(''); - 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 +2354,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(''); + var inputElm = helper.compileInput(''); - 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 +2370,21 @@ describe('input', function() { expect(inputElm).toBeValid(); }); + + it('should correctly handle 2-digit years', function() { + helper.compileInput(''); + + 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 From 3a80cefbd8fea27c22c0ad4e58cfbd5a8208ea44 Mon Sep 17 00:00:00 2001 From: George Kalpakas Date: Fri, 27 Apr 2018 14:00:19 +0300 Subject: [PATCH 2/2] fixup! fix(input[date]): correctly parse 2-digit years --- test/ng/directive/inputSpec.js | 51 +++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/test/ng/directive/inputSpec.js b/test/ng/directive/inputSpec.js index 11fc5219ab3f..fdb5af255624 100644 --- a/test/ng/directive/inputSpec.js +++ b/test/ng/directive/inputSpec.js @@ -761,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(''); @@ -990,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(''); @@ -1351,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(''); @@ -1556,18 +1562,22 @@ describe('input', function() { }); - it('should correctly handle 2-digit years', function() { - helper.compileInput(''); + // 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(''); - helper.changeInputValueTo('0001-01-01T12:34:00'); - expect($rootScope.value.getFullYear()).toBe(1); + 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('0099-01-01T12:34:00'); + expect($rootScope.value.getFullYear()).toBe(99); - helper.changeInputValueTo('0100-01-01T12:34:00'); - expect($rootScope.value.getFullYear()).toBe(100); - }); + helper.changeInputValueTo('0100-01-01T12:34:00'); + expect($rootScope.value.getFullYear()).toBe(100); + }); + } }); @@ -2370,19 +2380,22 @@ 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(''); - it('should correctly handle 2-digit years', function() { - helper.compileInput(''); - - helper.changeInputValueTo('0001-01-01'); - expect($rootScope.value.getFullYear()).toBe(1); + helper.changeInputValueTo('0001-01-01'); + expect($rootScope.value.getFullYear()).toBe(1); - helper.changeInputValueTo('0099-01-01'); - expect($rootScope.value.getFullYear()).toBe(99); + helper.changeInputValueTo('0099-01-01'); + expect($rootScope.value.getFullYear()).toBe(99); - helper.changeInputValueTo('0100-01-01'); - expect($rootScope.value.getFullYear()).toBe(100); - }); + helper.changeInputValueTo('0100-01-01'); + expect($rootScope.value.getFullYear()).toBe(100); + }); + } describe('ISO_DATE_REGEXP', function() {