Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: extra validation for dates #910

Merged
merged 2 commits into from
Oct 15, 2018
Merged
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
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.
**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
36 changes: 33 additions & 3 deletions lib/isISO8601.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,41 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de

/* eslint-disable max-len */
// from http://goo.gl/0ejHHW
var iso8601 = /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/;
var iso8601 = /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/;
/* eslint-enable max-len */
var isValidDate = function isValidDate(str) {
// str must have passed the ISO8601 check
// this check is meant to catch invalid dates
// like 2009-02-31
// 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];
// create a date object and compare
var d = new Date(year + '-' + (month || 1) + '-' + (day || 1));
if (isNaN(d.getFullYear())) return false;
if (month && day) {
return d.getFullYear() === year && d.getMonth() + 1 === month && d.getDate() === day;
}
return true;
};

function isISO8601(str) {
function isISO8601(str, options) {
(0, _assertString2.default)(str);
return iso8601.test(str);
var check = iso8601.test(str);
if (!options) return check;
if (check && options.strict) return isValidDate(str);
return check;
}
module.exports = exports['default'];
37 changes: 34 additions & 3 deletions src/lib/isISO8601.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,41 @@ import assertString from './util/assertString';

/* eslint-disable max-len */
// from http://goo.gl/0ejHHW
const iso8601 = /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/;
const iso8601 = /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/;
/* eslint-enable max-len */
const isValidDate = (str) => {
// str must have passed the ISO8601 check
// this check is meant to catch invalid dates
// like 2009-02-31
// 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];
// create a date object and compare
const d = new Date(`${year}-${month || 1}-${day || 1}`);
if (isNaN(d.getFullYear())) return false;
if (month && day) {
return d.getFullYear() === year
&& (d.getMonth() + 1) === month
&& d.getDate() === day;
}
return true;
};

export default function isISO8601(str) {
export default function isISO8601(str, options) {
assertString(str);
return iso8601.test(str);
const check = iso8601.test(str);
if (!options) return check;
if (check && options.strict) return isValidDate(str);
return check;
}
161 changes: 98 additions & 63 deletions test/validators.js
Original file line number Diff line number Diff line change
Expand Up @@ -5500,76 +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',
'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',
],
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',
],
invalid: [
'2010-02-30',
'2009-02-29',
'2009-366',
],
});
});
Expand Down
36 changes: 33 additions & 3 deletions validator.js
Original file line number Diff line number Diff line change
Expand Up @@ -1305,12 +1305,42 @@ function isCurrency(str, options) {

/* eslint-disable max-len */
// from http://goo.gl/0ejHHW
var iso8601 = /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/;
var iso8601 = /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/;
/* eslint-enable max-len */
var isValidDate = function isValidDate(str) {
// str must have passed the ISO8601 check
// this check is meant to catch invalid dates
// like 2009-02-31
// 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];
// create a date object and compare
var d = new Date(year + '-' + (month || 1) + '-' + (day || 1));
if (isNaN(d.getFullYear())) return false;
if (month && day) {
return d.getFullYear() === year && d.getMonth() + 1 === month && d.getDate() === day;
}
return true;
};

function isISO8601(str) {
function isISO8601(str, options) {
assertString(str);
return iso8601.test(str);
var check = iso8601.test(str);
if (!options) return check;
if (check && options.strict) return isValidDate(str);
return check;
}

/* Based on https://tools.ietf.org/html/rfc3339#section-5.6 */
Expand Down
2 changes: 1 addition & 1 deletion validator.min.js

Large diffs are not rendered by default.