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

fix(input[date]): support years with more than 4 digits #13905

Closed
wants to merge 8 commits into from
10 changes: 5 additions & 5 deletions src/ng/directive/input.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
*/

// Regex code is obtained from SO: https://stackoverflow.com/questions/3143070/javascript-regex-iso-datetime#answer-3143231
var ISO_DATE_REGEXP = /\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)/;
var ISO_DATE_REGEXP = /^\d{4,}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)$/;
// See valid URLs in RFC3987 (http://tools.ietf.org/html/rfc3987)
// Note: We are being more lenient, because browsers are too.
// 1. Scheme
Expand All @@ -26,10 +26,10 @@ var ISO_DATE_REGEXP = /\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-
var URL_REGEXP = /^[a-z][a-z\d.+-]*:\/*(?:[^:@]+(?::[^@]+)?@)?(?:[^\s:/?#]+|\[[a-f\d:]+\])(?::\d+)?(?:\/[^?#]*)?(?:\?[^#]*)?(?:#.*)?$/i;
var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i;
var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))([eE][+-]?\d+)?\s*$/;
var DATE_REGEXP = /^(\d{4})-(\d{2})-(\d{2})$/;
var DATETIMELOCAL_REGEXP = /^(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
var WEEK_REGEXP = /^(\d{4})-W(\d\d)$/;
var MONTH_REGEXP = /^(\d{4})-(\d\d)$/;
var DATE_REGEXP = /^(\d{4,})-(\d{2})-(\d{2})$/;
var DATETIMELOCAL_REGEXP = /^(\d{4,})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
var WEEK_REGEXP = /^(\d{4,})-W(\d\d)$/;
var MONTH_REGEXP = /^(\d{4,})-(\d\d)$/;
var TIME_REGEXP = /^(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;

var inputType = {
Expand Down
141 changes: 141 additions & 0 deletions test/ng/directive/inputSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,18 @@ describe('input', function() {
expect($rootScope.form.alias.$error.month).toBeTruthy();
});

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\'}"/>');

helper.changeInputValueTo('10123-03');
expect(+$rootScope.value).toBe(Date.UTC(10123, 2, 1, 0, 0, 0));

$rootScope.$apply(function() {
$rootScope.value = new Date(Date.UTC(10123, 2, 1, 0, 0, 0));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should use a different value.

});
expect(inputElm.val()).toBe('10123-03');
});


it('should only change the month of a bound date', function() {
var inputElm = helper.compileInput('<input type="month" ng-model="value" ng-model-options="{timezone: \'UTC\'}" />');
Expand Down Expand Up @@ -856,6 +868,17 @@ describe('input', function() {
expect(inputElm).toBeValid();
});

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\'}"/>');

helper.changeInputValueTo('10123-W03');
expect(+$rootScope.value).toBe(Date.UTC(10123, 0, 21));

$rootScope.$apply(function() {
$rootScope.value = new Date(Date.UTC(10321, 0, 21));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should use a different value.

});
expect(inputElm.val()).toBe('10321-W03');
});

it('should use UTC if specified in the options', function() {
var inputElm = helper.compileInput('<input type="week" ng-model="value" ng-model-options="{timezone: \'UTC\'}" />');
Expand Down Expand Up @@ -1734,6 +1757,19 @@ describe('input', function() {
}
);

it('should allow four or more digits in year', function() {
var inputElm = helper.compileInput('<input type="date" ng-model="value" ng-model-options="{timezone: \'UTC\'}" />');

helper.changeInputValueTo('10123-01-01');
expect(+$rootScope.value).toBe(Date.UTC(10123, 0, 1, 0, 0, 0));

$rootScope.$apply(function() {
$rootScope.value = new Date(Date.UTC(10123, 0, 1, 0, 0, 0));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should use a different value.

});
expect(inputElm.val()).toBe('10123-01-01');
}
);


it('should label parse errors as `date`', function() {
var inputElm = helper.compileInput('<input type="date" ng-model="val" name="alias" />', {
Expand Down Expand Up @@ -1941,6 +1977,111 @@ describe('input', function() {

expect(inputElm).toBeValid();
});

describe('ISO_DATE_REGEXP', function() {
var dates = [
// Validate date
['00:00:00.0000+01:01', false], // date must be specified
['2010.06.15T00:00:00.0000+01:01', false], // date must use dash seperator
['x2010-06-15T00:00:00.0000+01:01', false], // invalid leading characters

// Validate year
['2010-06-15T00:00:00.0000+01:01', true],
['20100-06-15T00:00:00.0000+01:01', true],
['-06-15T00:00:00.0000+01:01', false], // year too few digits
['2-06-15T00:00:00.0000+01:01', false], // year too few digits
['20-06-15T00:00:00.0000+01:01', false], // year too few digits
['201-06-15T00:00:00.0000+01:01', false], // year too few digits

// Validate month
['2010-01-15T00:00:00.0000+01:01', true],
['2010--15T00:00:00.0000+01:01', false], // month too few digits
['2010-0-15T00:00:00.0000+01:01', false], // month too few digits
['2010-1-15T00:00:00.0000+01:01', false], // month too few digits
['2010-111-15T00:00:00.0000+01:01', false], // month too many digits
['2010-22-15T00:00:00.0000+01:01', false], // month value too large

// Validate day
['2010-01-01T00:00:00.0000+01:01', true],
['2010-01-T00:00:00.0000+01:01', false], // day too few digits
['2010-01-1T00:00:00.0000+01:01', false], // day too few digits
['2010-01-41T00:00:00.0000+01:01', false], // day value too large
['2010-01-200T00:00:00.0000+01:01', false], // day value too many digits

// Validate time
['2010-01-01', false], // time must be specified
['2010-01-0101:00:00.0000+01:01', false], // missing date time seperator
['2010-01-01V01:00:00.0000+01:01', false], // invalid date time seperator
['2010-01-01T01-00-00.0000+01:01', false], // time must use period seperator
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, it must use colon separator.


// Validate hour
['2010-01-01T01:00:00.0000+01:01', true],
['2010-01-01T:00:00.0000+01:01', false], // hour value must be specified
['2010-01-01T1:00:00.0000+01:01', false], // hour value too few digits
['2010-01-01T-01:00:00.0000+01:01', false], // hour value must be positive
['2010-01-01T32:00:00.0000+01:01', false], // hour value too large
['2010-01-01T220:00:00.0000+01:01', false], // hour value too many digits

// Validate minutes
['2010-01-01T01:00:00.0000+01:01', true],
['2010-01-01T01::00.0000+01:01', false], // minute value must be specified
['2010-01-01T01:0:00.0000+01:01', false], // minute value too few digits
['2010-01-01T01:-00:00.0000+01:01', false], // minute value must be positive
['2010-01-01T01:60:00.0000+01:01', false], // minute value too large
['2010-01-01T01:100:00.0000+01:01', false], // minute value too many digits

// Validate seconds
['2010-01-01T01:00:00.0000+01:01', true],
['2010-01-01T01:00:.0000+01:01', false], // second value must be specified
['2010-01-01T01:00:0.0000+01:01', false], // second value too few digits
['2010-01-01T01:00:-00.0000+01:01', false], // second value must be positive
['2010-01-01T01:00:60.0000+01:01', false], // second value too large
['2010-01-01T01:00:100.0000+01:01', false], // second value too many digits

// Validate milliseconds
['2010-01-01T01:00:00+01:01', false], // millisecond value must be specified
['2010-01-01T01:00:00.+01:01', false], // millisecond value must be specified
['2010-01-01T01:00:00.-0000+01:01', false], // millisecond value must be positive

// Validate timezone
['20123-06-15T00:00:00.0000', false], // timezone must be specified

// Validate timezone offset
['2010-06-15T00:00:00.0000+01:01', true],
['2010-06-15T00:00:00.0000-01:01', true],
['2010-06-15T00:00:00.0000~01:01', false], // timezone must have valid postive/negative indicator
['2010-06-15T00:00:00.000001:01', false], // timezone must have valid postive/negative indicator
['2010-06-15T00:00:00.0000+00:01Z', false], // timezone invalid trailing characters
['2010-06-15T00:00:00.0000+00:01 ', false], // timezone invalid trailing characters
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, according to the standard, the timezone offset can have one of three forms:

+/-HH:mm, +/-HHmm, +/-HH

(Feel free to add suppory for those as well 😃)


// Validate timezone hour offset
['2010-06-15T00:00:00.0000+:01', false], // timezone hour offset must be specified
['2010-06-15T00:00:00.0000+0:01', false], // timezone hour offset too few digits
['2010-06-15T00:00:00.0000+31:01', false], // timezone hour offset value too large
['2010-06-15T00:00:00.0000+211:01', false], // timezone hour offset too many digits

// Validate timezone minute offset
['2010-06-15T00:00:00.0000+00:-01', false], // timezone minute offset must be positive
['2010-06-15T00:00:00.0000+00:', false], // timezone minute offset must be specified
['2010-06-15T00:00:00.0000+00:0', false], // timezone minute offset too few digits
['2010-06-15T00:00:00.0000+00:61', false], // timezone minute offset value too large
['2010-06-15T00:00:00.0000+00:211', false], // timezone minute offset too many digits

// Validate timezone UTC
['20123-06-15T00:00:00.0000Z', true],
['20123-06-15T00:00:00.0000K', false], // UTC timezone indicator is invalid
['20123-06-15T00:00:00.0000ZZ', false], // UTC timezone indicator invalid trailing characters
['20123-06-15T00:00:00.0000Z ', false] // UTC timezone indicator invalid trailing characters
];

they('should validate date: $prop', dates, function(item) {
var date = item[0];
var valid = item[1];

/* global ISO_DATE_REGEXP: false */
expect(ISO_DATE_REGEXP.test(date)).toBe(valid);
});
});
});


Expand Down