Skip to content
This repository has been archived by the owner on May 29, 2019. It is now read-only.

feat(dateParser): Add support for HH, H, mm, m, ss, s formats #3417

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 29 additions & 2 deletions src/dateparser/dateparser.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
angular.module('ui.bootstrap.dateparser', [])

.service('dateParser', ['$locale', 'orderByFilter', function($locale, orderByFilter) {
// Pulled from https://github.com/mbostock/d3/blob/master/src/format/requote.js
var SPECIAL_CHARACTERS_REGEXP = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g;

this.parsers = {};

Expand Down Expand Up @@ -46,6 +48,30 @@ angular.module('ui.bootstrap.dateparser', [])
},
'EEE': {
regex: $locale.DATETIME_FORMATS.SHORTDAY.join('|')
},
'HH': {
regex: '(?:0|1)[0-9]|2[0-3]',
apply: function(value) { this.hours = +value; }
},
'H': {
regex: '1?[0-9]|2[0-3]',
apply: function(value) { this.hours = +value; }
},
'mm': {
regex: '[0-5][0-9]',
apply: function(value) { this.minutes = +value; }
},
'm': {
regex: '[0-9]|[1-5][0-9]',
apply: function(value) { this.minutes = +value; }
},
'ss': {
regex: '[0-5][0-9]',
apply: function(value) { this.seconds = +value; }
},
's': {
regex: '[0-9]|[1-5][0-9]',
apply: function(value) { this.seconds = +value; }
}
};

Expand Down Expand Up @@ -82,6 +108,7 @@ angular.module('ui.bootstrap.dateparser', [])
}

format = $locale.DATETIME_FORMATS[format] || format;
format = format.replace(SPECIAL_CHARACTERS_REGEXP, '\\$&');
Copy link
Contributor

Choose a reason for hiding this comment

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

Should instead do this right before the new RegExp() call inside createParser as that shows why this character replacement is needed (it's to be fed into the RegExp constructor).

There's also less weird characters to process in the createParser's formatCodeToRegex loop.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Can you explain the less weird characters part? Just moving this inside the createParser function isn't enough, there seems to be some specificity required as to when the parsing happens since the regex gets some additional characters through the iteration over formatCodeToRegex. The loop adds an open and closed set of parentheses to the regex. This means that it would be too late to modify the format string at that stage.

Copy link
Contributor

Choose a reason for hiding this comment

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

Hm yea, I'm referring to replacing the characters right before the parentheses are added.

With the less weird characters, I'm referring to that if given a format of hh:mm, the createParser will now receive hh\:mmas the format when you do this here. It doesn't need that extra \ when looking for hh or mm (in the angular.forEach(formatCodeToRegex… block), it only needs the extra \ right before creating the regex property when feeding it into the RegExp constructor with the parentheses.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As per discussion between @chrisirhc and I on Slack, this turns out to be the best spot for modifying the format given how the iteration in formatCodeToRegex is implemented.


if ( !this.parsers[format] ) {
this.parsers[format] = createParser(format);
Expand All @@ -93,7 +120,7 @@ angular.module('ui.bootstrap.dateparser', [])
results = input.match(regex);

if ( results && results.length ) {
var fields = { year: 1900, month: 0, date: 1, hours: 0 }, dt;
var fields = { year: 1900, month: 0, date: 1, hours: 0, minutes: 0, seconds: 0 }, dt;

for( var i = 1, n = results.length; i < n; i++ ) {
var mapper = map[i-1];
Expand All @@ -103,7 +130,7 @@ angular.module('ui.bootstrap.dateparser', [])
}

if ( isValid(fields.year, fields.month, fields.date) ) {
dt = new Date( fields.year, fields.month, fields.date, fields.hours);
dt = new Date(fields.year, fields.month, fields.date, fields.hours, fields.minutes, fields.seconds);
}

return dt;
Expand Down
60 changes: 58 additions & 2 deletions src/dateparser/test/dateparser.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ describe('date parser', function () {
expect(dateParser.parse(input, format)).toEqual(date);
}

describe('wih custom formats', function() {
describe('with custom formats', function() {
it('should work correctly for `dd`, `MM`, `yyyy`', function() {
expectParse('17.11.2013', 'dd.MM.yyyy', new Date(2013, 10, 17, 0));
expectParse('31.12.2013', 'dd.MM.yyyy', new Date(2013, 11, 31, 0));
Expand Down Expand Up @@ -59,9 +59,65 @@ describe('date parser', function () {
expectParse('1955/February/5', 'yyyy/MMMM/d', new Date(1955, 1, 5, 0));
expectParse('11-08-13', 'd-MM-yy', new Date(2013, 7, 11, 0));
});

it('should work correctly for `HH`', function() {
expectParse('22.March.15.22', 'd.MMMM.yy.HH', new Date(2015, 2, 22, 22));
expectParse('8-March-1991-11', 'd-MMMM-yyyy-HH', new Date(1991, 2, 8, 11));
expectParse('February/5/1980/00', 'MMMM/d/yyyy/HH', new Date(1980, 1, 5, 0));
expectParse('1955/February/5 03', 'yyyy/MMMM/d HH', new Date(1955, 1, 5, 3));
expectParse('11-08-13 23', 'd-MM-yy HH', new Date(2013, 7, 11, 23));
});

it('should work correctly for `H`', function() {
expectParse('22.March.15.22', 'd.MMMM.yy.H', new Date(2015, 2, 22, 22));
expectParse('8-March-1991-11', 'd-MMMM-yyyy-H', new Date(1991, 2, 8, 11));
expectParse('February/5/1980/0', 'MMMM/d/yyyy/H', new Date(1980, 1, 5, 0));
expectParse('1955/February/5 3', 'yyyy/MMMM/d H', new Date(1955, 1, 5, 3));
expectParse('11-08-13 23', 'd-MM-yy H', new Date(2013, 7, 11, 23));
});

it('should work correctly for `mm`', function() {
expectParse('22.March.15.22', 'd.MMMM.yy.mm', new Date(2015, 2, 22, 0, 22));
expectParse('8-March-1991-59', 'd-MMMM-yyyy-mm', new Date(1991, 2, 8, 0, 59));
expectParse('February/5/1980/00', 'MMMM/d/yyyy/mm', new Date(1980, 1, 5, 0, 0));
expectParse('1955/February/5 03', 'yyyy/MMMM/d mm', new Date(1955, 1, 5, 0, 3));
expectParse('11-08-13 46', 'd-MM-yy mm', new Date(2013, 7, 11, 0, 46));
expectParse('22.March.15.22:33', 'd.MMMM.yy.HH:mm', new Date(2015, 2, 22, 22, 33));
expectParse('22.March.15.2:01', 'd.MMMM.yy.H:mm', new Date(2015, 2, 22, 2, 1));
});

it('should work correctly for `m`', function() {
expectParse('22.March.15.22', 'd.MMMM.yy.m', new Date(2015, 2, 22, 0, 22));
expectParse('8-March-1991-59', 'd-MMMM-yyyy-m', new Date(1991, 2, 8, 0, 59));
expectParse('February/5/1980/0', 'MMMM/d/yyyy/m', new Date(1980, 1, 5, 0, 0));
expectParse('1955/February/5 3', 'yyyy/MMMM/d m', new Date(1955, 1, 5, 0, 3));
expectParse('11-08-13 46', 'd-MM-yy m', new Date(2013, 7, 11, 0, 46));
expectParse('22.March.15.22:3', 'd.MMMM.yy.HH:m', new Date(2015, 2, 22, 22, 3));
expectParse('22.March.15.2:1', 'd.MMMM.yy.H:m', new Date(2015, 2, 22, 2, 1));
});

it('should work correctly for `ss`', function() {
expectParse('22.March.15.22', 'd.MMMM.yy.ss', new Date(2015, 2, 22, 0, 0, 22));
expectParse('8-March-1991-59', 'd-MMMM-yyyy-ss', new Date(1991, 2, 8, 0, 0, 59));
expectParse('February/5/1980/00', 'MMMM/d/yyyy/ss', new Date(1980, 1, 5, 0, 0, 0));
expectParse('1955/February/5 03', 'yyyy/MMMM/d ss', new Date(1955, 1, 5, 0, 0, 3));
expectParse('11-08-13 46', 'd-MM-yy ss', new Date(2013, 7, 11, 0, 0, 46));
expectParse('22.March.15.22:33:44', 'd.MMMM.yy.HH:mm:ss', new Date(2015, 2, 22, 22, 33, 44));
expectParse('22.March.15.0:0:01', 'd.MMMM.yy.H:m:ss', new Date(2015, 2, 22, 0, 0, 1));
});

it('should work correctly for `s`', function() {
expectParse('22.March.15.22', 'd.MMMM.yy.s', new Date(2015, 2, 22, 0, 0, 22));
expectParse('8-March-1991-59', 'd-MMMM-yyyy-s', new Date(1991, 2, 8, 0, 0, 59));
expectParse('February/5/1980/0', 'MMMM/d/yyyy/s', new Date(1980, 1, 5, 0, 0, 0));
expectParse('1955/February/5 3', 'yyyy/MMMM/d s', new Date(1955, 1, 5, 0, 0, 3));
expectParse('11-08-13 46', 'd-MM-yy s', new Date(2013, 7, 11, 0, 0, 46));
expectParse('22.March.15.22:33:4', 'd.MMMM.yy.HH:mm:s', new Date(2015, 2, 22, 22, 33, 4));
expectParse('22.March.15.22:3:4', 'd.MMMM.yy.HH:m:s', new Date(2015, 2, 22, 22, 3, 4));
});
});

describe('wih predefined formats', function() {
describe('with predefined formats', function() {
it('should work correctly for `shortDate`', function() {
expectParse('9/3/10', 'shortDate', new Date(2010, 8, 3, 0));
});
Expand Down