// parsing token regexes
parseTokenOneOrTwoDigits = /\d\d?/, // 0 - 99
parseTokenOneToThreeDigits = /\d{1,3}/, // 0 - 999
- parseTokenThreeDigits = /\d{3}/, // 000 - 999
- parseTokenFourDigits = /\d{1,4}/, // 0 - 9999
- parseTokenSixDigits = /[+\-]?\d{1,6}/, // -999,999 - 999,999
+ parseTokenOneToFourDigits = /\d{1,4}/, // 0 - 9999
+ parseTokenOneToSixDigits = /[+\-]?\d{1,6}/, // -999,999 - 999,999
parseTokenDigits = /\d+/, // nonzero number of digits
parseTokenWord = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i, // any word (or two) characters or numbers including two/three word month in arabic.
parseTokenTimezone = /Z|[\+\-]\d\d:?\d\d/i, // +00:00 -00:00 +0000 -0000 or Z
parseTokenT = /T/i, // T (ISO separator)
parseTokenTimestampMs = /[\+\-]?\d+(\.\d{1,3})?/, // 123456789 123456789.123
+ //strict parsing regexes
+ parseTokenOneDigit = /\d/, // 0 - 9
+ parseTokenTwoDigits = /\d\d/, // 00 - 99
+ parseTokenThreeDigits = /\d{3}/, // 000 - 999
+ parseTokenFourDigits = /\d{4}/, // 0000 - 9999
+ parseTokenSixDigits = /[+\-]?\d{6}/, // -999,999 - 999,999
+
// preliminary iso regex
// 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000)
isoRegex = /^\s*\d{4}-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d:?\d\d|\s*Z)?)?$/,
// get the regex to find the next token
function getParseRegexForToken(token, config) {
- var a;
+ var a, strict = config._strict;
switch (token) {
case 'DDDD':
return parseTokenThreeDigits;
case 'YYYY':
case 'GGGG':
case 'gggg':
- return parseTokenFourDigits;
+ return strict ? parseTokenFourDigits : parseTokenOneToFourDigits;
case 'YYYYY':
case 'GGGGG':
case 'ggggg':
- return parseTokenSixDigits;
+ return strict ? parseTokenSixDigits : parseTokenOneToSixDigits;
case 'S':
+ if (strict) { return parseTokenOneDigit;}
+ /* falls through */
case 'SS':
+ if (strict) { return parseTokenTwoDigits;}
+ /* falls through */
case 'SSS':
+ if (strict) { return parseTokenThreeDigits;}
+ /* falls through */
case 'DDD':
- return parseTokenOneToThreeDigits;
+ return strict ? parseTokenThreeDigits : parseTokenOneToThreeDigits;
case 'MMM':
case 'MMMM':
case 'dd':
case 'hh':
case 'mm':
case 'ss':
+ case 'ww':
+ case 'WW':
+ return strict ? parseTokenTwoDigits : parseTokenOneOrTwoDigits;
case 'M':
case 'D':
case 'd':
case 'm':
case 's':
case 'w':
- case 'ww':
case 'W':
- case 'WW':
case 'e':
case 'E':
- return parseTokenOneOrTwoDigits;
+ return strict ? parseTokenOneDigit : parseTokenOneOrTwoDigits;
default :
a = new RegExp(regexpEscape(unescapeFormat(token.replace('\\', '')), "i"));
return a;
},
"strict parsing" : function (test) {
- test.expect(11);
test.equal(moment("2012-05", "YYYY-MM", true).format("YYYY-MM"), "2012-05", "parse correct string");
test.equal(moment(" 2012-05", "YYYY-MM", true).isValid(), false, "fail on extra whitespace");
test.equal(moment("foo 2012-05", "[foo] YYYY-MM", true).format('YYYY-MM'), "2012-05", "handle fixed text");
test.equal(moment("2010.*", "YYYY.*", true).year(), 2010, "valid format with regex chars");
test.equal(moment(".*2010.*", ".*YYYY.*", true).year(), 2010, "valid format with regex chars on both sides");
+ //strict tokens
+ test.equal(moment("2-05-25", 'YYYY-MM-DD', true).isValid(), false, "invalid one-digit year");
+ test.equal(moment("20-05-25", 'YYYY-MM-DD', true).isValid(), false, "invalid two-digit year");
+ test.equal(moment("201-05-25", 'YYYY-MM-DD', true).isValid(), false, "invalid three-digit year");
+
+ test.equal(moment("12-05-25", 'YY-MM-DD', true).isValid(), true, "valid two-digit year");
+ test.equal(moment("2012-05-25", 'YY-MM-DD', true).isValid(), false, "invalid four-digit year");
+
+ test.equal(moment("2012-5-25", 'YYYY-MM-DD', true).isValid(), false, "invalid one-digit month");
+
+ test.equal(moment("2012-05-2", 'YYYY-MM-DD', true).isValid(), false, "invalid one-digit day");
+
+ test.equal(moment("+002012-05-25", 'YYYYY-MM-DD', true).isValid(), true, "valid six-digit year");
+ test.equal(moment("+2012-05-25", 'YYYYY-MM-DD', true).isValid(), false, "invalid four-digit year");
+
+ //thse are kinda pointless, but they should work as expected
+ test.equal(moment("1", 'S', true).isValid(), true, "valid one-digit milisecond");
+ test.equal(moment("12", 'S', true).isValid(), false, "invalid two-digit milisecond");
+ test.equal(moment("123", 'S', true).isValid(), false, "invalid three-digit milisecond");
+
+ test.equal(moment("1", 'SS', true).isValid(), false, "invalid one-digit milisecond");
+ test.equal(moment("12", 'SS', true).isValid(), true, "valid two-digit milisecond");
+ test.equal(moment("123", 'SS', true).isValid(), false, "invalid three-digit milisecond");
+
+ test.equal(moment("1", 'SSS', true).isValid(), false, "invalid one-digit milisecond");
+ test.equal(moment("12", 'SSS', true).isValid(), false, "invalid two-digit milisecond");
+ test.equal(moment("123", 'SSS', true).isValid(), true, "valid three-digit milisecond");
+
test.done();
},