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

Replaced ISO8601 with new code #2009

Closed
wants to merge 2 commits 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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ Validator | Description
**isISBN(str [, version])** | check if the string is an ISBN (version 10 or 13).
**isISIN(str)** | check if the string is an [ISIN][ISIN] (stock/security identifier).
**isISO6391(str)** | check if the string is a valid [ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) language code.
**isISO8601(str [, options])** | check if the string is a valid [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) date. <br/>`options` is an object which defaults to `{ strict: false, strictSeparator: false }`. If `strict` is true, date strings with invalid dates like `2009-02-29` will be invalid. If `strictSeparator` is true, date strings with date and time separated by anything other than a T will be invalid.
**isISO8601(str)** | check if the string is a valid [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) 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.
**isISO4217(str)** | check if the string is a valid [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) officially assigned currency code.
Expand Down
41 changes: 3 additions & 38 deletions src/lib/isISO8601.js
Original file line number Diff line number Diff line change
@@ -1,44 +1,9 @@
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-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)?)?)?)?$/;
// same as above, except with a strict 'T' separator between date and time
const iso8601StrictSeparator = /^([\+-]?\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]((([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) || oYear % 400 === 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];
const monthString = month ? `0${month}`.slice(-2) : month;
const dayString = day ? `0${day}`.slice(-2) : day;
const iso8601 = /^(?:[-+]\d{2})?(?:\d{4}(?!\d{2}\b))(?:(-?)(?:(?:0[1-9]|1[0-2])(?:\1(?:[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]$|[T][\d]+Z$)(?:[T\s](?:(?:(?:[01]\d|2[0-3])(?:(:?)[0-5]\d)?|24\:?00)(?:[.,]\d+(?!:))?)(?:\2[0-5]\d(?:[.,]\d+)?)?(?:[Z]|(?:[+-])(?:[01]\d|2[0-3])(?::?[0-5]\d)?)?)?)?$/;

// create a date object and compare
const d = new Date(`${year}-${monthString || '01'}-${dayString || '01'}`);
if (month && day) {
return d.getUTCFullYear() === year
&& (d.getUTCMonth() + 1) === month
&& d.getUTCDate() === day;
}
return true;
};

export default function isISO8601(str, options = {}) {
export default function isISO8601(str) {
assertString(str);
const check = options.strictSeparator ? iso8601StrictSeparator.test(str) : iso8601.test(str);
if (check && options.strict) return isValidDate(str);
return check;
return !!(!isNaN(Date.parse(str)) && iso8601.test(str));
}
167 changes: 0 additions & 167 deletions test/validators.js
Original file line number Diff line number Diff line change
Expand Up @@ -10323,45 +10323,19 @@ describe('Validators', () => {
'2009',
'2009-05-19',
'2009-05-19',
'20090519',
'2009123',
Comment on lines -10326 to -10327
Copy link
Contributor

Choose a reason for hiding this comment

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

These are valid ISO dates. Separators (hyphens) can be omitted

The ISO 8601 standard allows these separators to be omitted (e.g., 19980512 for a date), but expressions are much easier to read when separators are used.

'2009-05',
'2009-123',
'2009-222',
Copy link
Contributor

Choose a reason for hiding this comment

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

This is a valid ordinal date.

'2009-001',
'2009-W01-1',
'2009-W51-1',
Copy link
Contributor

Choose a reason for hiding this comment

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

This is a valid Week with weekday

'2009-W511',
'2009-W33',
'2009W511',
Copy link
Contributor

Choose a reason for hiding this comment

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

This is a valid week with weekday without separators

'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',
Copy link
Contributor

Choose a reason for hiding this comment

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

Valid ISO8601 without separators

'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',
Comment on lines -10353 to -10361
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't have the actual spec on hand, but the article @WikiRik linked includes these examples as valid, so I can only assume that this is some obscure syntax that is still a part of the spec. As the article says, If we are invoking the name ISO8601 we ought to respect the spec, even though it includes some wacky things.

'2009-10-10',
'2020-366',
'2000-366',
];

const invalidISO8601 = [
Expand Down Expand Up @@ -10394,154 +10368,13 @@ describe('Validators', () => {
];

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: [
'2000-02-29',
'2009-123',
'2009-222',
'2020-366',
'2400-366',
],
invalid: [
'2010-02-30',
'2009-02-29',
'2009-366',
'2019-02-31',
],
});
});

it('should validate ISO 8601 dates, with strictSeparator = true', () => {
test({
validator: 'isISO8601',
args: [
{ strictSeparator: true },
],
valid: [
'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-19T14:39Z',
'2009-W21-2',
'2009-W21-2T01:22',
'2009-139',
'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-10-10',
'2020-366',
'2000-366',
],
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-05-19 00:00',
// Previously valid cases
'2009-05-19 14',
'2009-05-19 14:31',
'2009-05-19 14:39:22',
'2009-05-19 14:39:22-06:00',
'2009-05-19 14:39:22+0600',
'2009-05-19 14:39:22-01',
],
});
});

it('should validate ISO 8601 dates, with strict = true and strictSeparator = true (regression)', () => {
test({
validator: 'isISO8601',
args: [
{ strict: true, strictSeparator: true },
],
valid: [
'2000-02-29',
'2009-123',
'2009-222',
'2020-366',
'2400-366',
],
invalid: [
'2010-02-30',
'2009-02-29',
'2009-366',
'2019-02-31',
'2009-05-19 14',
'2009-05-19 14:31',
'2009-05-19 14:39:22',
'2009-05-19 14:39:22-06:00',
'2009-05-19 14:39:22+0600',
'2009-05-19 14:39:22-01',
],
});
});

it('should validate RFC 3339 dates', () => {
test({
validator: 'isRFC3339',
Expand Down