Skip to content

Commit

Permalink
fix: add extra validation for ordinal dates
Browse files Browse the repository at this point in the history
- adds provision for ordinal dates
- checks that ordinal dates are also valid for leap years
- includes regression tests for previous cases with `strict = false`
  • Loading branch information
profnandaa committed Oct 15, 2018
1 parent e4bb296 commit f3bb0cd
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 80 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ Validator | Description
**isISBN(str [, version])** | check if the string is an ISBN (version 10 or 13).
**isISSN(str [, options])** | check if the string is an [ISSN](https://en.wikipedia.org/wiki/International_Standard_Serial_Number).<br/><br/>`options` is an object which defaults to `{ case_sensitive: false, require_hyphen: false }`. If `case_sensitive` is true, ISSNs with a lowercase `'x'` as the check digit are rejected.
**isISIN(str)** | check if the string is an [ISIN][ISIN] (stock/security identifier).
**isISO8601(str)** | check if the string is a valid [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) date; with additional checks for valid dates, e.g. invalidates dates like `2009-02-29`.
**isISO8601(str)** | check if the string is a valid [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) date; for additional checks for valid dates, e.g. invalidates dates like `2009-02-29`, pass `options` object as a second parameter with `options.strict = true`.
**isRFC3339(str)** | check if the string is a valid [RFC 3339](https://tools.ietf.org/html/rfc3339) date.
**isISO31661Alpha2(str)** | check if the string is a valid [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) officially assigned country code.
**isISO31661Alpha3(str)** | check if the string is a valid [ISO 3166-1 alpha-3](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-3) officially assigned country code.
Expand Down
18 changes: 13 additions & 5 deletions lib/isISO8601.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,18 @@ var isValidDate = function isValidDate(str) {
// str must have passed the ISO8601 check
// this check is meant to catch invalid dates
// like 2009-02-31
// note: we choose not to validate the time part
var match = str.match(/(\d{4})-?(\d{0,2})-?(\d{0,2})/).map(Number);
// first check for ordinal dates
var ordinalMatch = str.match(/^(\d{4})-?(\d{3})([ T]{1}\.*|$)/);
if (ordinalMatch) {
var oYear = Number(ordinalMatch[1]);
var oDay = Number(ordinalMatch[2]);
// if is leap year
if (oYear % 4 === 0 && oYear % 100 !== 0) {
return oDay <= 366;
}
return oDay <= 365;
}
var match = str.match(/(\d{4})-?(\d{0,2})-?(\d*)/).map(Number);
var year = match[1];
var month = match[2];
var day = match[3];
Expand All @@ -33,9 +43,7 @@ var isValidDate = function isValidDate(str) {
return true;
};

function isISO8601(str) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : { strict: true };

function isISO8601(str, options) {
(0, _assertString2.default)(str);
var check = iso8601.test(str);
if (!options) return check;
Expand Down
15 changes: 12 additions & 3 deletions src/lib/isISO8601.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,17 @@ const isValidDate = (str) => {
// str must have passed the ISO8601 check
// this check is meant to catch invalid dates
// like 2009-02-31
// note: we choose not to validate the time part
const match = str.match(/(\d{4})-?(\d{0,2})-?(\d{0,2})/).map(Number);
// first check for ordinal dates
const ordinalMatch = str.match(/^(\d{4})-?(\d{3})([ T]{1}\.*|$)/);
if (ordinalMatch) {
const oYear = Number(ordinalMatch[1]);
const oDay = Number(ordinalMatch[2]);
// if is leap year
if (oYear % 4 === 0
&& oYear % 100 !== 0) return oDay <= 366;
return oDay <= 365;
}
const match = str.match(/(\d{4})-?(\d{0,2})-?(\d*)/).map(Number);
const year = match[1];
const month = match[2];
const day = match[3];
Expand All @@ -24,7 +33,7 @@ const isValidDate = (str) => {
return true;
};

export default function isISO8601(str, options = { strict: true }) {
export default function isISO8601(str, options) {
assertString(str);
const check = iso8601.test(str);
if (!options) return check;
Expand Down
162 changes: 97 additions & 65 deletions test/validators.js
Original file line number Diff line number Diff line change
Expand Up @@ -5500,79 +5500,111 @@ describe('Validators', () => {
});
});

const validISO8601 = [
'2009-12T12:34',
'2009',
'2009-05-19',
'2009-05-19',
'20090519',
'2009123',
'2009-05',
'2009-123',
'2009-222',
'2009-001',
'2009-W01-1',
'2009-W51-1',
'2009-W511',
'2009-W33',
'2009W511',
'2009-05-19',
'2009-05-19 00:00',
'2009-05-19 14',
'2009-05-19 14:31',
'2009-05-19 14:39:22',
'2009-05-19T14:39Z',
'2009-W21-2',
'2009-W21-2T01:22',
'2009-139',
'2009-05-19 14:39:22-06:00',
'2009-05-19 14:39:22+0600',
'2009-05-19 14:39:22-01',
'20090621T0545Z',
'2007-04-06T00:00',
'2007-04-05T24:00',
'2010-02-18T16:23:48.5',
'2010-02-18T16:23:48,444',
'2010-02-18T16:23:48,3-06:00',
'2010-02-18T16:23.4',
'2010-02-18T16:23,25',
'2010-02-18T16:23.33+0600',
'2010-02-18T16.23334444',
'2010-02-18T16,2283',
'2009-05-19 143922.500',
'2009-05-19 1439,55',
];

const invalidISO8601 = [
'200905',
'2009367',
'2009-',
'2007-04-05T24:50',
'2009-000',
'2009-M511',
'2009M511',
'2009-05-19T14a39r',
'2009-05-19T14:3924',
'2009-0519',
'2009-05-1914:39',
'2009-05-19 14:',
'2009-05-19r14:39',
'2009-05-19 14a39a22',
'200912-01',
'2009-05-19 14:39:22+06a00',
'2009-05-19 146922.500',
'2010-02-18T16.5:23.35:48',
'2010-02-18T16:23.35:48',
'2010-02-18T16:23.35:48.45',
'2009-05-19 14.5.44',
'2010-02-18T16:23.33.600',
'2010-02-18T16,25:23:48,444',
'2010-13-1',
];

it('should validate ISO 8601 dates', () => {
// from http://www.pelagodesign.com/blog/2009/05/20/iso-8601-date-validation-that-doesnt-suck/
test({
validator: 'isISO8601',
valid: validISO8601,
invalid: invalidISO8601,
});
});

it('should validate ISO 8601 dates, with strict = true (regression)', () => {
test({
validator: 'isISO8601',
args: [
{ strict: true },
],
valid: validISO8601,
invalid: invalidISO8601,
});
});

it('should validate ISO 8601 dates, with strict = true', () => {
test({
validator: 'isISO8601',
args: [
{ strict: true },
],
valid: [
'2009-12T12:34',
'2009',
'2009-05-19',
'2009-05-19',
'20090519',
'2009123',
'2009-05',
'2000-02-29',
'2009-123',
// '2009-222', // invalid test-case, implies 2009-22-2
'2009-001',
'2009-W01-1',
'2009-W51-1',
'2009-W511',
'2009-W33',
'2009W511',
'2009-05-19',
'2009-05-19 00:00',
'2009-05-19 14',
'2009-05-19 14:31',
'2009-05-19 14:39:22',
'2009-05-19T14:39Z',
'2009-W21-2',
'2009-W21-2T01:22',
// '2009-139', // invalid test-case, implies 2009-13-9
'2009-05-19 14:39:22-06:00',
'2009-05-19 14:39:22+0600',
'2009-05-19 14:39:22-01',
'20090621T0545Z',
'2007-04-06T00:00',
'2007-04-05T24:00',
'2010-02-18T16:23:48.5',
'2010-02-18T16:23:48,444',
'2010-02-18T16:23:48,3-06:00',
'2010-02-18T16:23.4',
'2010-02-18T16:23,25',
'2010-02-18T16:23.33+0600',
'2010-02-18T16.23334444',
'2010-02-18T16,2283',
'2009-05-19 143922.500',
'2009-05-19 1439,55',
],
invalid: [
'200905',
'2009367',
'2009-',
'2007-04-05T24:50',
'2009-000',
'2009-M511',
'2009M511',
'2009-05-19T14a39r',
'2009-05-19T14:3924',
'2009-0519',
'2009-05-1914:39',
'2009-05-19 14:',
'2009-05-19r14:39',
'2009-05-19 14a39a22',
'200912-01',
'2009-05-19 14:39:22+06a00',
'2009-05-19 146922.500',
'2010-02-18T16.5:23.35:48',
'2010-02-18T16:23.35:48',
'2010-02-18T16:23.35:48.45',
'2009-05-19 14.5.44',
'2010-02-18T16:23.33.600',
'2010-02-18T16,25:23:48,444',
'2010-13-1',
'2009-222',
],
invalid: [
'2010-02-30',
'2009-02-29',
'2009-366',
],
});
});
Expand Down
18 changes: 13 additions & 5 deletions validator.js
Original file line number Diff line number Diff line change
Expand Up @@ -1311,8 +1311,18 @@ var isValidDate = function isValidDate(str) {
// str must have passed the ISO8601 check
// this check is meant to catch invalid dates
// like 2009-02-31
// note: we choose not to validate the time part
var match = str.match(/(\d{4})-?(\d{0,2})-?(\d{0,2})/).map(Number);
// first check for ordinal dates
var ordinalMatch = str.match(/^(\d{4})-?(\d{3})([ T]{1}\.*|$)/);
if (ordinalMatch) {
var oYear = Number(ordinalMatch[1]);
var oDay = Number(ordinalMatch[2]);
// if is leap year
if (oYear % 4 === 0 && oYear % 100 !== 0) {
return oDay <= 366;
}
return oDay <= 365;
}
var match = str.match(/(\d{4})-?(\d{0,2})-?(\d*)/).map(Number);
var year = match[1];
var month = match[2];
var day = match[3];
Expand All @@ -1325,9 +1335,7 @@ var isValidDate = function isValidDate(str) {
return true;
};

function isISO8601(str) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : { strict: true };

function isISO8601(str, options) {
assertString(str);
var check = iso8601.test(str);
if (!options) return check;
Expand Down
2 changes: 1 addition & 1 deletion validator.min.js

Large diffs are not rendered by default.

0 comments on commit f3bb0cd

Please sign in to comment.