-
Notifications
You must be signed in to change notification settings - Fork 27.4k
fix(input[date]): support years with more than 4 digits #13905
Conversation
Change to regular expressions used to match date formats that increases the number of digits in a year. Previously exactly four digits were required, change allows four or more. Also matches complete string, resolving ambiguity around extra characters at the beginning or end.
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)); |
There was a problem hiding this comment.
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.
There's no test for |
['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 |
There was a problem hiding this comment.
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.
… format Support for parsing additional variations of ISO dates, specifically the minute offset in timezones is now optional, as is the colon delimiter between the offset hour and minute. Enhancements to the tests were made to increase robustness and validate edge-case scenarios.
Thank you for the feedback, I appreciate it. |
// 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)/; | ||
// Regex code was initially obtained from SO prior to modification: 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)$/; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we are not using the groups anywhere, it would be better for performance to make them non-capturing.
(As an added bonus, you'll have the chance to write a RegExp that includes ?::?
- not somethng you do everyday 😁)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW, I know I proposed this change, but there is currently an issue with IE/Edge (they can't parse a timezone offset when there is no colon), so additional steps might be needed. That said, I'm not sure when/if ISO_DATE_REGEXP
is used after all, so let me look into it some more :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Likely to be a problem if the input model is populated directly with an ISO formatted text string, instead of from the browser native picker.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I took a look at Edge in Saucelabs and found the same result when using the Date constructor for parsing both '2010-06-15T00:00:00.0000+01:30' as well as '2010-06-15T00:00:00.0000+0130'.
Is there a bug report for the Edge issue you referenced?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know if there is a bug report - it just came up a few days ago and I added a workaround to fix a similar issue in #13887.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Likely to be a problem if the input model is populated directly with an ISO formatted text string
The ISO_DATE_REGEXP
is only used in an ngModelController
parser, meaning it will only be applied when parsing the $viewValue
to transform it to a $modelValue
. The only case where the $viewValue
can be an ISO-8601 date string, is on browsers that do not natively support input[date]
and the users enter it by hand (which is a rather unlikely interaction imo).
Anyway, assuming we still need ISO_DATE_REGEXP
, what needs to be done in order to properly support all valid timezone offsets on all supported browsers, is "fixing up" the date string before passing it to new Date()
. That would include adding a colon if missing and add 00
minutes if omitted.
Thinking about it again, this is totally unrelated to the initial intent of this PR, so it's not a good idea to mix them. I suggest, leaving only changes to add support for >4-digit years in this PR and if you fancy feel free to submit another one with the required changes to properly support all valid timezone offset formats.
Sorry, I had you make those changes and now telling they don't belong here 😞
@gkalpak Can you take another look at this? |
@Narretz, will do. Thx for the heads-up ! (I hadn't notice the updates.) |
expect(ISO_DATE_REGEXP.test(date)).toBe(valid); | ||
}); | ||
|
||
it('should be non-capturing', function() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test is not needed. Capturing vs Non-capturing is just an implementation detail.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Happy to make this change, but would point out that if having the regex be non-capturing is important for performance, we should have a test that validates it. The regex was originally capturing, but that mistake wasn't noticed until this unit test was written. It's not unlikely that the next person that modifies it after us will unintentionally make it capturing again, unless there is a test enforces this style of implementation for performance gains.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is still an implementation detail. E.g. if we decide to add support for all timezone formats, this will change: we'll need some capturing groups. Unless it is identified as a performance issue (which it won't - it's more of a theoretical performance gain, unlikely to be noticable), it remains an implementation detail.
So, while it's nice to avoid capturing groups if you don't need them, having a test for it will only make it more difficult to add functionality later. Unit tests should assert the functionality/behavior, not the performance characteristics, imo.
LGTM (expect for one minor comment). |
Thanks for the feedback. The implementation test has been removed. |
Previously, the date-related regular expressions only matched years with no more than 4 digits. This commit adds support for years with more than 4 digits. It also resolves an ambiguity in `ISO_DATE_REGEXP` by matching the whole string (when it previosuly allowed extra characters around the date string). Fixes #13735 Closes #13905
Backported to |
Change to regular expressions used for matching ISO date strings. Increases the number of digits allowed in a year from exactly four to instead be four or more. Also matches on the entire string, resolving ambiguity around extra characters at the start of the year, or after the timezone.
Closes #13735