This repository has been archived by the owner on May 29, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 6.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(dateParser): add
dateParser
service
Closes #1874
- Loading branch information
Showing
2 changed files
with
222 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
angular.module('ui.bootstrap.dateparser', []) | ||
|
||
.service('dateParser', ['$locale', 'orderByFilter', function($locale, orderByFilter) { | ||
|
||
this.parsers = {}; | ||
|
||
var formatCodeToRegex = { | ||
'yyyy': { | ||
regex: '\\d{4}', | ||
apply: function(value) { this.year = +value; } | ||
}, | ||
'yy': { | ||
regex: '\\d{2}', | ||
apply: function(value) { this.year = +value + 2000; } | ||
}, | ||
'y': { | ||
regex: '\\d{1,4}', | ||
apply: function(value) { this.year = +value; } | ||
}, | ||
'MMMM': { | ||
regex: $locale.DATETIME_FORMATS.MONTH.join('|'), | ||
apply: function(value) { this.month = $locale.DATETIME_FORMATS.MONTH.indexOf(value); } | ||
}, | ||
'MMM': { | ||
regex: $locale.DATETIME_FORMATS.SHORTMONTH.join('|'), | ||
apply: function(value) { this.month = $locale.DATETIME_FORMATS.SHORTMONTH.indexOf(value); } | ||
}, | ||
'MM': { | ||
regex: '0[1-9]|1[0-2]', | ||
apply: function(value) { this.month = value - 1; } | ||
}, | ||
'M': { | ||
regex: '[1-9]|1[0-2]', | ||
apply: function(value) { this.month = value - 1; } | ||
}, | ||
'dd': { | ||
regex: '[0-2][0-9]{1}|3[0-1]{1}', | ||
apply: function(value) { this.date = +value; } | ||
}, | ||
'd': { | ||
regex: '[1-2]?[0-9]{1}|3[0-1]{1}', | ||
apply: function(value) { this.date = +value; } | ||
}, | ||
'EEEE': { | ||
regex: $locale.DATETIME_FORMATS.DAY.join('|') | ||
}, | ||
'EEE': { | ||
regex: $locale.DATETIME_FORMATS.SHORTDAY.join('|') | ||
} | ||
}; | ||
|
||
this.createParser = function(format) { | ||
var map = [], regex = format.split(''); | ||
|
||
angular.forEach(formatCodeToRegex, function(data, code) { | ||
var index = format.indexOf(code); | ||
|
||
if (index > -1) { | ||
format = format.split(''); | ||
|
||
regex[index] = '(' + data.regex + ')'; | ||
format[index] = '$'; // Custom symbol to define consumed part of format | ||
for (var i = index + 1, n = index + code.length; i < n; i++) { | ||
regex[i] = ''; | ||
format[i] = '$'; | ||
} | ||
format = format.join(''); | ||
|
||
map.push({ index: index, apply: data.apply }); | ||
} | ||
}); | ||
|
||
return { | ||
regex: new RegExp('^' + regex.join('') + '$'), | ||
map: orderByFilter(map, 'index') | ||
}; | ||
}; | ||
|
||
this.parse = function(input, format) { | ||
if ( !angular.isString(input) ) { | ||
return input; | ||
} | ||
|
||
format = $locale.DATETIME_FORMATS[format] || format; | ||
|
||
if ( !this.parsers[format] ) { | ||
this.parsers[format] = this.createParser(format); | ||
} | ||
|
||
var parser = this.parsers[format], | ||
regex = parser.regex, | ||
map = parser.map, | ||
results = input.match(regex); | ||
|
||
if ( results && results.length ) { | ||
var fields = { year: 1900, month: 0, date: 1, hours: 0 }, dt; | ||
|
||
for( var i = 1, n = results.length; i < n; i++ ) { | ||
var mapper = map[i-1]; | ||
if ( mapper.apply ) { | ||
mapper.apply.call(fields, results[i]); | ||
} | ||
} | ||
|
||
if ( isValid(fields.year, fields.month, fields.date) ) { | ||
dt = new Date( fields.year, fields.month, fields.date, fields.hours); | ||
} | ||
|
||
return dt; | ||
} | ||
}; | ||
|
||
// Check if date is valid for specific month (and year for February). | ||
// Month: 0 = Jan, 1 = Feb, etc | ||
function isValid(year, month, date) { | ||
if ( month === 1 && date > 28) { | ||
return date === 29 && ((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0); | ||
} | ||
|
||
if ( month === 3 || month === 5 || month === 8 || month === 10) { | ||
return date < 31; | ||
} | ||
|
||
return true; | ||
} | ||
}]); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
describe('date parser', function () { | ||
var dateParser; | ||
|
||
beforeEach(module('ui.bootstrap.dateparser')); | ||
beforeEach(inject(function (_dateParser_) { | ||
dateParser = _dateParser_; | ||
})); | ||
|
||
function expectParse(input, format, date) { | ||
expect(dateParser.parse(input, format)).toEqual(date); | ||
} | ||
|
||
describe('wih 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)); | ||
expectParse('08-03-1991', 'dd-MM-yyyy', new Date(1991, 2, 8, 0)); | ||
expectParse('03/05/1980', 'MM/dd/yyyy', new Date(1980, 2, 5, 0)); | ||
expectParse('10.01/1983', 'dd.MM/yyyy', new Date(1983, 0, 10, 0)); | ||
expectParse('11-09-1980', 'MM-dd-yyyy', new Date(1980, 10, 9, 0)); | ||
expectParse('2011/02/05', 'yyyy/MM/dd', new Date(2011, 1, 5, 0)); | ||
}); | ||
|
||
it('should work correctly for `yy`', function() { | ||
expectParse('17.11.13', 'dd.MM.yy', new Date(2013, 10, 17, 0)); | ||
expectParse('02-05-11', 'dd-MM-yy', new Date(2011, 4, 2, 0)); | ||
expectParse('02/05/80', 'MM/dd/yy', new Date(2080, 1, 5, 0)); | ||
expectParse('55/02/05', 'yy/MM/dd', new Date(2055, 1, 5, 0)); | ||
expectParse('11-08-13', 'dd-MM-yy', new Date(2013, 7, 11, 0)); | ||
}); | ||
|
||
it('should work correctly for `M`', function() { | ||
expectParse('8/11/2013', 'M/dd/yyyy', new Date(2013, 7, 11, 0)); | ||
expectParse('07.11.05', 'dd.M.yy', new Date(2005, 10, 7, 0)); | ||
expectParse('02-5-11', 'dd-M-yy', new Date(2011, 4, 2, 0)); | ||
expectParse('2/05/1980', 'M/dd/yyyy', new Date(1980, 1, 5, 0)); | ||
expectParse('1955/2/05', 'yyyy/M/dd', new Date(1955, 1, 5, 0)); | ||
expectParse('02-5-11', 'dd-M-yy', new Date(2011, 4, 2, 0)); | ||
}); | ||
|
||
it('should work correctly for `MMM`', function() { | ||
expectParse('30.Sep.10', 'dd.MMM.yy', new Date(2010, 8, 30, 0)); | ||
expectParse('02-May-11', 'dd-MMM-yy', new Date(2011, 4, 2, 0)); | ||
expectParse('Feb/05/1980', 'MMM/dd/yyyy', new Date(1980, 1, 5, 0)); | ||
expectParse('1955/Feb/05', 'yyyy/MMM/dd', new Date(1955, 1, 5, 0)); | ||
}); | ||
|
||
it('should work correctly for `MMMM`', function() { | ||
expectParse('17.November.13', 'dd.MMMM.yy', new Date(2013, 10, 17, 0)); | ||
expectParse('05-March-1980', 'dd-MMMM-yyyy', new Date(1980, 2, 5, 0)); | ||
expectParse('February/05/1980', 'MMMM/dd/yyyy', new Date(1980, 1, 5, 0)); | ||
expectParse('1949/December/20', 'yyyy/MMMM/dd', new Date(1949, 11, 20, 0)); | ||
}); | ||
|
||
it('should work correctly for `d`', function() { | ||
expectParse('17.November.13', 'd.MMMM.yy', new Date(2013, 10, 17, 0)); | ||
expectParse('8-March-1991', 'd-MMMM-yyyy', new Date(1991, 2, 8, 0)); | ||
expectParse('February/5/1980', 'MMMM/d/yyyy', new Date(1980, 1, 5, 0)); | ||
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)); | ||
}); | ||
}); | ||
|
||
describe('wih predefined formats', function() { | ||
it('should work correctly for `shortDate`', function() { | ||
expectParse('9/3/10', 'shortDate', new Date(2010, 8, 3, 0)); | ||
}); | ||
|
||
it('should work correctly for `mediumDate`', function() { | ||
expectParse('Sep 3, 2010', 'mediumDate', new Date(2010, 8, 3, 0)); | ||
}); | ||
|
||
it('should work correctly for `longDate`', function() { | ||
expectParse('September 3, 2010', 'longDate', new Date(2010, 8, 3, 0)); | ||
}); | ||
|
||
it('should work correctly for `fullDate`', function() { | ||
expectParse('Friday, September 3, 2010', 'fullDate', new Date(2010, 8, 3, 0)); | ||
}); | ||
}); | ||
|
||
describe('with edge case', function() { | ||
it('should not work for invalid number of days in February', function() { | ||
expect(dateParser.parse('29.02.2013', 'dd.MM.yyyy')).toBeUndefined(); | ||
}); | ||
|
||
it('should work for 29 days in February for leap years', function() { | ||
expectParse('29.02.2000', 'dd.MM.yyyy', new Date(2000, 1, 29, 0)); | ||
}); | ||
|
||
it('should not work for 31 days for some months', function() { | ||
expect(dateParser.parse('31-04-2013', 'dd-MM-yyyy')).toBeUndefined(); | ||
expect(dateParser.parse('November 31, 2013', 'MMMM d, yyyy')).toBeUndefined(); | ||
}); | ||
}); | ||
}); |