From 128841a72ed724fafdbd57a3c9f36cdb1bc6a8a1 Mon Sep 17 00:00:00 2001 From: Ilaria Venturini Date: Mon, 11 May 2020 15:12:28 +0200 Subject: [PATCH 01/13] =?UTF-8?q?=F0=9F=9A=A8=20Add/update=20linter=20rule?= =?UTF-8?q?s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tslint.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tslint.json b/tslint.json index ad9677a..6452cf4 100644 --- a/tslint.json +++ b/tslint.json @@ -25,12 +25,14 @@ "no-class": true, "no-mixed-interface": false, "no-expression-statement": [ - true, + false, { "ignore-prefix": ["console.", "process.exit"] } ], "no-if-statement": false, /* end tslint-immutable rules */ - "ordered-imports": false + "ordered-imports": false, + "curly": false, + "no-shadowed-variable": false } } From 6b072a9b3fa84fa4f9b70aaabbe5da6b91a504f0 Mon Sep 17 00:00:00 2001 From: Ilaria Venturini Date: Mon, 11 May 2020 15:13:21 +0200 Subject: [PATCH 02/13] =?UTF-8?q?=F0=9F=97=93=20Support=20also=20time=20no?= =?UTF-8?q?t=20only=20date?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/dataInference.ts | 7 +++++-- src/lib/test/dataInference.spec.ts | 9 ++++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/lib/dataInference.ts b/src/lib/dataInference.ts index 15322c2..c575f76 100644 --- a/src/lib/dataInference.ts +++ b/src/lib/dataInference.ts @@ -78,8 +78,11 @@ export function isFormatDateValid( ): boolean { if(!inferIfStringIsNumber(value[0])) return false - // this will match yyyy-mm-dd and also yyyy-m-d - const regDate = /^([1-9][0-9]{3})\-(0?[1-9]|1[012])\-(0?[1-9]|[12][0-9]|3[01])$/; + // this will match date (and time) formats: + // date formats: YYYY-MM-DD or YYYY-M-D + // time formats: HH:mm:ss + // separator between date and time can be ` ` or `, ` + const regDate = /^([1-9][0-9]{3})\-(0?[1-9]|1[012])\-(0?[1-9]|[12][0-9]|3[01])(,?[\s]([0-1][0-9]|[2][0-3]):([0-5][0-9])(:([0-5][0-9]))?)?$/; // TODO: add other regex to accept also other date formats const isFormatDateValid = regDate.test(value.toString()); diff --git a/src/lib/test/dataInference.spec.ts b/src/lib/test/dataInference.spec.ts index 9960522..c7f50a8 100644 --- a/src/lib/test/dataInference.spec.ts +++ b/src/lib/test/dataInference.spec.ts @@ -75,10 +75,17 @@ test('isDateValid', t => { t.is(isFormatDateValid('2018-02-29'), true); // this day doesn't exist but we check only the date format t.is(isFormatDateValid('2017-02-30'), true); // this day doesn't exist but we check only the date format t.is(isFormatDateValid('2020-04-31'), true); // this day doesn't exist but we check only the date format + t.is(isFormatDateValid('2019-01-15 13:12:29'), true); + t.is(isFormatDateValid('2019-01-15, 13:12:29'), true); + t.is(isFormatDateValid('2019-01-15, 00:00:00'), true); + t.is(isFormatDateValid('2019-01-15, 23:59:59'), true); t.is(isFormatDateValid('17-02-2019', rightParser), true); t.is(isFormatDateValid('17-02-2019', wrongParser), true); // this shouldn't be right but we assume that if the user has written a parser, then the dates are in the correct format t.is(isFormatDateValid('17-02-2019', defaultParser), true); // this shouldn't be right but we assume that if the user has written a parser, then the dates are in the correct format - + + t.is(isFormatDateValid('2019-01-15, 24:00:00'), false); + t.is(isFormatDateValid('2019-01-15, 23:60:00'), false); + t.is(isFormatDateValid('2019-01-15, 23:59:60'), false); t.is(isFormatDateValid('2019-01-15 13:12:29.0'), false); t.is(isFormatDateValid('17-02-2019'), false); t.is(isFormatDateValid('0000-01-01'), false); From 7a88de41b5f4451fff867965429af586a4b940bc Mon Sep 17 00:00:00 2001 From: Ilaria Venturini Date: Mon, 11 May 2020 16:19:02 +0200 Subject: [PATCH 03/13] =?UTF-8?q?=E2=9A=99=EF=B8=8F=20Add=20tsc=20watch=20?= =?UTF-8?q?script?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 5acc05b..875ac29 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "test": "run-s build test:*", "test:unit": "nyc --silent ava", "watch": "run-s clean build:main && run-p \"build:main -- -w\" \"test:unit -- --watch\"", + "watch-tsc": "tsc --watch", "cov": "run-s build test:unit cov:html && opn coverage/index.html", "cov:html": "nyc report --reporter=html", "cov:send": "nyc report --reporteyarnr=lcov > coverage.lcov && codecov", From 67b04e1c09fdcbc0bcca14942cd2d9137473fa2c Mon Sep 17 00:00:00 2001 From: Ilaria Venturini Date: Tue, 12 May 2020 10:30:12 +0200 Subject: [PATCH 04/13] Do not accept comma as date and time separator --- src/lib/dataInference.ts | 4 ++-- src/lib/test/dataInference.spec.ts | 10 ++++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/lib/dataInference.ts b/src/lib/dataInference.ts index c575f76..dd5fde4 100644 --- a/src/lib/dataInference.ts +++ b/src/lib/dataInference.ts @@ -81,8 +81,8 @@ export function isFormatDateValid( // this will match date (and time) formats: // date formats: YYYY-MM-DD or YYYY-M-D // time formats: HH:mm:ss - // separator between date and time can be ` ` or `, ` - const regDate = /^([1-9][0-9]{3})\-(0?[1-9]|1[012])\-(0?[1-9]|[12][0-9]|3[01])(,?[\s]([0-1][0-9]|[2][0-3]):([0-5][0-9])(:([0-5][0-9]))?)?$/; + // separator between date and time must be ` ` + const regDate = /^([1-9][0-9]{3})\-(0?[1-9]|1[012])\-(0?[1-9]|[12][0-9]|3[01])([\s]([0-1][0-9]|[2][0-3]):([0-5][0-9])(:([0-5][0-9]))?)?$/; // TODO: add other regex to accept also other date formats const isFormatDateValid = regDate.test(value.toString()); diff --git a/src/lib/test/dataInference.spec.ts b/src/lib/test/dataInference.spec.ts index c7f50a8..5081ee2 100644 --- a/src/lib/test/dataInference.spec.ts +++ b/src/lib/test/dataInference.spec.ts @@ -76,16 +76,14 @@ test('isDateValid', t => { t.is(isFormatDateValid('2017-02-30'), true); // this day doesn't exist but we check only the date format t.is(isFormatDateValid('2020-04-31'), true); // this day doesn't exist but we check only the date format t.is(isFormatDateValid('2019-01-15 13:12:29'), true); - t.is(isFormatDateValid('2019-01-15, 13:12:29'), true); - t.is(isFormatDateValid('2019-01-15, 00:00:00'), true); - t.is(isFormatDateValid('2019-01-15, 23:59:59'), true); t.is(isFormatDateValid('17-02-2019', rightParser), true); t.is(isFormatDateValid('17-02-2019', wrongParser), true); // this shouldn't be right but we assume that if the user has written a parser, then the dates are in the correct format t.is(isFormatDateValid('17-02-2019', defaultParser), true); // this shouldn't be right but we assume that if the user has written a parser, then the dates are in the correct format - t.is(isFormatDateValid('2019-01-15, 24:00:00'), false); - t.is(isFormatDateValid('2019-01-15, 23:60:00'), false); - t.is(isFormatDateValid('2019-01-15, 23:59:60'), false); + t.is(isFormatDateValid('2019-01-15 13:12:29'), true); + t.is(isFormatDateValid('2019-01-15 24:00:00'), false); + t.is(isFormatDateValid('2019-01-15 23:60:00'), false); + t.is(isFormatDateValid('2019-01-15 23:59:60'), false); t.is(isFormatDateValid('2019-01-15 13:12:29.0'), false); t.is(isFormatDateValid('17-02-2019'), false); t.is(isFormatDateValid('0000-01-01'), false); From 8725cccfb5c08f7675e3cba2e8596dfb0aa5e15c Mon Sep 17 00:00:00 2001 From: Ilaria Venturini Date: Thu, 14 May 2020 12:10:06 +0200 Subject: [PATCH 05/13] =?UTF-8?q?=F0=9F=97=93=20Use=20dayjs=20to=20check?= =?UTF-8?q?=20if=20a=20date=20is=20valid.=20ISO=208601=20is=20supported?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/dataInference.ts | 38 ++++++++++++++++++-------- src/lib/test/dataInference.spec.ts | 44 +++++++++++++++++++++++------- yarn.lock | 6 ++-- 3 files changed, 64 insertions(+), 24 deletions(-) diff --git a/src/lib/dataInference.ts b/src/lib/dataInference.ts index dd5fde4..d621468 100644 --- a/src/lib/dataInference.ts +++ b/src/lib/dataInference.ts @@ -10,9 +10,8 @@ import { } from '../types/types'; import { fromPairs } from './parseObjects'; import { getAllKeys } from './stats'; - -import CustomParseFormat from 'dayjs/plugin/customParseFormat'; // load on demand -dayjs.extend(CustomParseFormat); // use plugin +import customParseFormat from 'dayjs/plugin/customParseFormat'; +dayjs.extend(customParseFormat); export type GenericDatumValue = number | string | boolean | null; @@ -72,20 +71,37 @@ export function detectValue( } } +// references: +// https://day.js.org/docs/en/parse/string-format +// https://day.js.org/docs/en/display/format +export const DATE_FORMATS = [ + 'YYYY-MM-DD', + 'YYYY-MM-D', + 'YYYY-M-DD', + 'YYYY-M-D', + 'YYYY-MM-DD HH:mm', + 'YYYY-MM-DD HH:mm:ss', + 'YYYY-MM-DD HH:mm:ss.SSS', + 'YYYY-MM-DD HH:mm:ss A', + 'YYYY-MM-DD HH:mm:ss a', + 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]' // ISO8601 +] + +function isValidDate(dateString: string, formats: string[], strictMode = true): boolean { + const results = formats.map(format => { + // @ts-ignore + return dayjs(dateString, format, strictMode).isValid() + }) + return results.some(res => res === true) +} + export function isFormatDateValid( value: string, parser?: ParserFunction ): boolean { if(!inferIfStringIsNumber(value[0])) return false - // this will match date (and time) formats: - // date formats: YYYY-MM-DD or YYYY-M-D - // time formats: HH:mm:ss - // separator between date and time must be ` ` - const regDate = /^([1-9][0-9]{3})\-(0?[1-9]|1[012])\-(0?[1-9]|[12][0-9]|3[01])([\s]([0-1][0-9]|[2][0-3]):([0-5][0-9])(:([0-5][0-9]))?)?$/; - // TODO: add other regex to accept also other date formats - - const isFormatDateValid = regDate.test(value.toString()); + const isFormatDateValid = isValidDate(value, DATE_FORMATS); // NOTE: we assume that if the user has written a parser, then the dates are in the correct format return isFormatDateValid || !isUndefined(parser); diff --git a/src/lib/test/dataInference.spec.ts b/src/lib/test/dataInference.spec.ts index 5081ee2..b9f6e4a 100644 --- a/src/lib/test/dataInference.spec.ts +++ b/src/lib/test/dataInference.spec.ts @@ -1,5 +1,7 @@ import test from 'ava'; import dayjs from 'dayjs'; +import customParseFormat from 'dayjs/plugin/customParseFormat'; +dayjs.extend(customParseFormat); import { autoInferenceType, detectValue, @@ -68,23 +70,32 @@ test('isDateValid', t => { t.is(isFormatDateValid('1900-10-23'), true); t.is(isFormatDateValid('2002-5-5'), true); - t.is(isFormatDateValid('2008-09-31'), true); t.is(isFormatDateValid('1600-12-25'), true); t.is(isFormatDateValid('1942-11-1'), true); t.is(isFormatDateValid('2000-10-10'), true); - t.is(isFormatDateValid('2018-02-29'), true); // this day doesn't exist but we check only the date format - t.is(isFormatDateValid('2017-02-30'), true); // this day doesn't exist but we check only the date format - t.is(isFormatDateValid('2020-04-31'), true); // this day doesn't exist but we check only the date format t.is(isFormatDateValid('2019-01-15 13:12:29'), true); + t.is(isFormatDateValid(new Date().toISOString()), true); + t.is(isFormatDateValid('2020-05-13T08:24:45.701Z'), true); + t.is(isFormatDateValid('2020-05-01'), true); + t.is(isFormatDateValid('2020-05-1'), true); + t.is(isFormatDateValid('2020-5-01'), true); + t.is(isFormatDateValid('2020-5-1'), true); + t.is(isFormatDateValid('2020-05-01 00:00'), true); + t.is(isFormatDateValid('2020-05-01 00:00:00'), true); + t.is(isFormatDateValid('2020-05-01 00:00:00.101'), true); + t.is(isFormatDateValid('2016-01-01 11:31:23 AM'), true); + t.is(isFormatDateValid('2016-01-01 11:31:23 am'), true); + t.is(isFormatDateValid('2016-01-01 23:31:23 pm'), true); t.is(isFormatDateValid('17-02-2019', rightParser), true); t.is(isFormatDateValid('17-02-2019', wrongParser), true); // this shouldn't be right but we assume that if the user has written a parser, then the dates are in the correct format t.is(isFormatDateValid('17-02-2019', defaultParser), true); // this shouldn't be right but we assume that if the user has written a parser, then the dates are in the correct format - t.is(isFormatDateValid('2019-01-15 13:12:29'), true); - t.is(isFormatDateValid('2019-01-15 24:00:00'), false); - t.is(isFormatDateValid('2019-01-15 23:60:00'), false); - t.is(isFormatDateValid('2019-01-15 23:59:60'), false); - t.is(isFormatDateValid('2019-01-15 13:12:29.0'), false); + + t.is(isFormatDateValid('cat-1'), false); + t.is(isFormatDateValid('2017-02-30'), false); + t.is(isFormatDateValid('2020-04-31'), false); + t.is(isFormatDateValid('2018-02-29'), false); + t.is(isFormatDateValid('2008-09-31'), false); t.is(isFormatDateValid('17-02-2019'), false); t.is(isFormatDateValid('0000-01-01'), false); t.is(isFormatDateValid('0100-10-23'), false); @@ -92,7 +103,20 @@ test('isDateValid', t => { t.is(isFormatDateValid('1942-11-0'), false); t.is(isFormatDateValid('1942-00-25'), false); t.is(isFormatDateValid('2000-10-00'), false); - t.is(isFormatDateValid('cat-1'), false); + t.is(isFormatDateValid('2019-01-15 24:00:00'), false); + t.is(isFormatDateValid('2019-01-15 23:60:00'), false); + t.is(isFormatDateValid('2019-01-15 23:59:60'), false); + t.is(isFormatDateValid('2019-01-15 13:12:29.0'), false); + t.is(isFormatDateValid('2020-05-01 01:01:01.12'), false); + t.is(isFormatDateValid('2016-01-01 11:31:23 PM'), false); + t.is(isFormatDateValid('2020-05-01 00'), false); + t.is(isFormatDateValid('2020-02-31'), false); + t.is(isFormatDateValid('2016/01/01'), false); + t.is(isFormatDateValid('2020-05-01 01:60:00'), false); + t.is(isFormatDateValid('2020-05-01 60'), false); + t.is(isFormatDateValid('2020-05-01 '), false); + t.is(isFormatDateValid(new Date().toString()), false); + t.is(isFormatDateValid('Wed May 13 2020 10:25:23 GMT+0200 (Central European Summer Time)'), false); }); // ---------------------------------------------------------- diff --git a/yarn.lock b/yarn.lock index 5ad7d5d..669dd58 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1603,9 +1603,9 @@ dateformat@^3.0.0: integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q== dayjs@^1.8.13: - version "1.8.13" - resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.8.13.tgz#51b5cdad23ba508bcea939a853b492fefb7fdc47" - integrity sha512-JZ01l/PMU8OqwuUs2mOQ/CTekMtoXOUSylfjqjgDzbhRSxpFIrPnHn8Y8a0lfocNgAdBNZb8y0/gbzJ2riQ4WQ== + version "1.8.27" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.8.27.tgz#a8ae63ee990af28c05c430f0e160ae835a0fbbf8" + integrity sha512-Jpa2acjWIeOkg8KURUHICk0EqnEFSSF5eMEscsOgyJ92ZukXwmpmRkPSUka7KHSfbj5eKH30ieosYip+ky9emQ== debug@^2.1.2, debug@^2.2.0, debug@^2.3.3: version "2.6.9" From 8fb9215272802c87855f0a672dd9e022f9ac6ec9 Mon Sep 17 00:00:00 2001 From: Ilaria Venturini Date: Tue, 19 May 2020 10:40:08 +0200 Subject: [PATCH 06/13] =?UTF-8?q?=F0=9F=90=9B=20Date=20could=20be=20also?= =?UTF-8?q?=20a=20Date=20object,=20not=20only=20a=20string?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/dataInference.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/lib/dataInference.ts b/src/lib/dataInference.ts index d621468..9000976 100644 --- a/src/lib/dataInference.ts +++ b/src/lib/dataInference.ts @@ -62,9 +62,21 @@ export function detectValue( return 'unknown'; } + const isDate = (value: any, parser?: ParserFunction) => { + if (typeof value === 'string' && isFormatDateValid(value, parser)) + return true; + if ( + value && + Object.prototype.toString.call(value) === '[object Date]' && + !isNaN(value) + ) + return true; + return false; + }; + if (inferIsNumber(value)) { return 'continuous'; - } else if (typeof value === 'string' && isFormatDateValid(value, parser)) { + } else if (isDate(value, parser)) { return 'date'; } else { return 'categorical'; From 931c392b99e585fd9f6cdd0f6c625e59b035e1b8 Mon Sep 17 00:00:00 2001 From: Ilaria Venturini Date: Tue, 19 May 2020 10:40:30 +0200 Subject: [PATCH 07/13] =?UTF-8?q?=F0=9F=92=85=20Put=20constant=20on=20top?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/dataInference.ts | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/lib/dataInference.ts b/src/lib/dataInference.ts index 9000976..05bf680 100644 --- a/src/lib/dataInference.ts +++ b/src/lib/dataInference.ts @@ -13,6 +13,22 @@ import { getAllKeys } from './stats'; import customParseFormat from 'dayjs/plugin/customParseFormat'; dayjs.extend(customParseFormat); +// references: +// https://day.js.org/docs/en/parse/string-format +// https://day.js.org/docs/en/display/format +export const DATE_FORMATS = [ + 'YYYY-MM-DD', + 'YYYY-MM-D', + 'YYYY-M-DD', + 'YYYY-M-D', + 'YYYY-MM-DD HH:mm', + 'YYYY-MM-DD HH:mm:ss', + 'YYYY-MM-DD HH:mm:ss.SSS', + 'YYYY-MM-DD HH:mm:ss A', + 'YYYY-MM-DD HH:mm:ss a', + 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]' // ISO8601 +] + export type GenericDatumValue = number | string | boolean | null; export type GenericDatum = { @@ -83,22 +99,6 @@ export function detectValue( } } -// references: -// https://day.js.org/docs/en/parse/string-format -// https://day.js.org/docs/en/display/format -export const DATE_FORMATS = [ - 'YYYY-MM-DD', - 'YYYY-MM-D', - 'YYYY-M-DD', - 'YYYY-M-D', - 'YYYY-MM-DD HH:mm', - 'YYYY-MM-DD HH:mm:ss', - 'YYYY-MM-DD HH:mm:ss.SSS', - 'YYYY-MM-DD HH:mm:ss A', - 'YYYY-MM-DD HH:mm:ss a', - 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]' // ISO8601 -] - function isValidDate(dateString: string, formats: string[], strictMode = true): boolean { const results = formats.map(format => { // @ts-ignore From 76b05d68d40f0cb584334858ca8efb1dcc58da93 Mon Sep 17 00:00:00 2001 From: Ilaria Venturini Date: Wed, 20 May 2020 11:20:14 +0200 Subject: [PATCH 08/13] =?UTF-8?q?=F0=9F=95=B0=20Add=20date=20formats?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/dataInference.ts | 23 ++++++++++++++--- src/lib/test/dataInference.spec.ts | 41 ++++++++++++++++++++---------- 2 files changed, 48 insertions(+), 16 deletions(-) diff --git a/src/lib/dataInference.ts b/src/lib/dataInference.ts index 05bf680..9538b81 100644 --- a/src/lib/dataInference.ts +++ b/src/lib/dataInference.ts @@ -21,13 +21,29 @@ export const DATE_FORMATS = [ 'YYYY-MM-D', 'YYYY-M-DD', 'YYYY-M-D', + 'YYYY-MM-DD HH:mm', + 'YYYY-MM-DD HH:mm[Z]', + 'YYYY-MM-DD[T]HH:mm', + 'YYYY-MM-DD[T]HH:mm[Z]', + 'YYYY-MM-DD HH:mm:ss', + 'YYYY-MM-DD HH:mm:ss[Z]', + 'YYYY-MM-DD[T]HH:mm:ss', + 'YYYY-MM-DD[T]HH:mm:ss[Z]', + 'YYYY-MM-DD HH:mm:ss.SSS', + 'YYYY-MM-DD HH:mm:ss.SSS[Z]', + 'YYYY-MM-DD[T]HH:mm:ss.SSS', + 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]', // ISO8601 + 'YYYY-MM-DD HH:mm:ss A', 'YYYY-MM-DD HH:mm:ss a', - 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]' // ISO8601 -] + + // these two formats don't work + // 'YYYY-MM-DD HH:mm:ssZ', // 2013-02-08 09:00:00+07:00 + // 'YYYY-MM-DD HH:mm:ssZZ', // 2013-02-08 09:00:00-0700 +]; export type GenericDatumValue = number | string | boolean | null; @@ -99,7 +115,8 @@ export function detectValue( } } -function isValidDate(dateString: string, formats: string[], strictMode = true): boolean { +function isValidDate(dateString: string, formats: string[]): boolean { + const strictMode = true const results = formats.map(format => { // @ts-ignore return dayjs(dateString, format, strictMode).isValid() diff --git a/src/lib/test/dataInference.spec.ts b/src/lib/test/dataInference.spec.ts index b9f6e4a..68ffd4a 100644 --- a/src/lib/test/dataInference.spec.ts +++ b/src/lib/test/dataInference.spec.ts @@ -69,28 +69,43 @@ test('isDateValid', t => { const defaultParser = (d: string) => dayjs(d, 'YYYY-MM-DD').unix(); t.is(isFormatDateValid('1900-10-23'), true); - t.is(isFormatDateValid('2002-5-5'), true); - t.is(isFormatDateValid('1600-12-25'), true); t.is(isFormatDateValid('1942-11-1'), true); - t.is(isFormatDateValid('2000-10-10'), true); + t.is(isFormatDateValid('2002-5-15'), true); + t.is(isFormatDateValid('2000-01-10'), true); + + t.is(isFormatDateValid('2020-05-01 09:35'), true); + t.is(isFormatDateValid('2020-05-01 09:35Z'), true); + t.is(isFormatDateValid('2020-05-01T09:35'), true); + t.is(isFormatDateValid('2020-05-01T09:35Z'), true); + + t.is(isFormatDateValid('2020-05-01 09:35:20'), true); t.is(isFormatDateValid('2019-01-15 13:12:29'), true); - t.is(isFormatDateValid(new Date().toISOString()), true); + t.is(isFormatDateValid('2020-05-01 09:35:20Z'), true); + t.is(isFormatDateValid('2020-05-01T09:35:20'), true); + t.is(isFormatDateValid('2020-05-01T09:35:20Z'), true); + + t.is(isFormatDateValid('2020-05-01 09:35:20.000'), true); + t.is(isFormatDateValid('2020-05-01 09:35:20.000Z'), true); + t.is(isFormatDateValid('2020-05-01T09:35:20.000'), true); + t.is(isFormatDateValid('2020-05-01T09:35:20.000Z'), true); t.is(isFormatDateValid('2020-05-13T08:24:45.701Z'), true); - t.is(isFormatDateValid('2020-05-01'), true); - t.is(isFormatDateValid('2020-05-1'), true); - t.is(isFormatDateValid('2020-5-01'), true); - t.is(isFormatDateValid('2020-5-1'), true); - t.is(isFormatDateValid('2020-05-01 00:00'), true); - t.is(isFormatDateValid('2020-05-01 00:00:00'), true); - t.is(isFormatDateValid('2020-05-01 00:00:00.101'), true); + t.is(isFormatDateValid(new Date().toISOString()), true); + t.is(isFormatDateValid('2016-01-01 11:31:23 AM'), true); t.is(isFormatDateValid('2016-01-01 11:31:23 am'), true); t.is(isFormatDateValid('2016-01-01 23:31:23 pm'), true); + + t.is(isFormatDateValid('17-02-2019', rightParser), true); t.is(isFormatDateValid('17-02-2019', wrongParser), true); // this shouldn't be right but we assume that if the user has written a parser, then the dates are in the correct format t.is(isFormatDateValid('17-02-2019', defaultParser), true); // this shouldn't be right but we assume that if the user has written a parser, then the dates are in the correct format - t.is(isFormatDateValid('2019-01-15 13:12:29'), true); - + + // t.is(isFormatDateValid('2013-02-08 09:00:00+01:00'), true); + // t.is(isFormatDateValid('2013-02-08 09:00:00+01:30'), true); + // t.is(isFormatDateValid('2013-02-08 09:00:00+0100'), true); + // t.is(isFormatDateValid('2013-02-08 09:00:00-01:00'), true); + // t.is(isFormatDateValid('2013-02-08 09:00:00-0100'), true); + t.is(isFormatDateValid('cat-1'), false); t.is(isFormatDateValid('2017-02-30'), false); t.is(isFormatDateValid('2020-04-31'), false); From 388515c9e2f431351c7059ea57192622cae667c3 Mon Sep 17 00:00:00 2001 From: Ilaria Venturini Date: Wed, 20 May 2020 11:28:13 +0200 Subject: [PATCH 09/13] =?UTF-8?q?=F0=9F=9A=9A=20Small=20refactor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/dataInference.ts | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/src/lib/dataInference.ts b/src/lib/dataInference.ts index 9538b81..fe47607 100644 --- a/src/lib/dataInference.ts +++ b/src/lib/dataInference.ts @@ -1,5 +1,5 @@ import dayjs from 'dayjs'; -import { get, isFinite, isNaN, isNull, isUndefined, keys } from 'lodash'; +import { get, isFinite, isNaN, isNull, isUndefined, keys, isDate, isString } from 'lodash'; import { CategoricalDatum, ContinuousDatum, @@ -93,22 +93,9 @@ export function detectValue( if (!value || isNull(value) || typeof value === 'boolean') { return 'unknown'; } - - const isDate = (value: any, parser?: ParserFunction) => { - if (typeof value === 'string' && isFormatDateValid(value, parser)) - return true; - if ( - value && - Object.prototype.toString.call(value) === '[object Date]' && - !isNaN(value) - ) - return true; - return false; - }; - if (inferIsNumber(value)) { return 'continuous'; - } else if (isDate(value, parser)) { + } else if (isDate(value) || (isString(value) && isFormatDateValid(value, parser))) { return 'date'; } else { return 'categorical'; From 03db198dcc7f5f243567b0e9cb3466eae8e369dd Mon Sep 17 00:00:00 2001 From: Ilaria Venturini Date: Wed, 20 May 2020 11:50:04 +0200 Subject: [PATCH 10/13] Remove nonsense white line --- src/lib/test/dataInference.spec.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib/test/dataInference.spec.ts b/src/lib/test/dataInference.spec.ts index 68ffd4a..2905fdb 100644 --- a/src/lib/test/dataInference.spec.ts +++ b/src/lib/test/dataInference.spec.ts @@ -95,7 +95,6 @@ test('isDateValid', t => { t.is(isFormatDateValid('2016-01-01 11:31:23 am'), true); t.is(isFormatDateValid('2016-01-01 23:31:23 pm'), true); - t.is(isFormatDateValid('17-02-2019', rightParser), true); t.is(isFormatDateValid('17-02-2019', wrongParser), true); // this shouldn't be right but we assume that if the user has written a parser, then the dates are in the correct format t.is(isFormatDateValid('17-02-2019', defaultParser), true); // this shouldn't be right but we assume that if the user has written a parser, then the dates are in the correct format From f6307e3aee8753707df827816e1a4db7808d78e5 Mon Sep 17 00:00:00 2001 From: Ilaria Venturini Date: Wed, 20 May 2020 11:55:26 +0200 Subject: [PATCH 11/13] =?UTF-8?q?=F0=9F=9A=9A=20Refactor=20and=20enhanceme?= =?UTF-8?q?nt:=20remove=20unneeded=20iterations?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/dataInference.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/lib/dataInference.ts b/src/lib/dataInference.ts index fe47607..6556e81 100644 --- a/src/lib/dataInference.ts +++ b/src/lib/dataInference.ts @@ -104,11 +104,8 @@ export function detectValue( function isValidDate(dateString: string, formats: string[]): boolean { const strictMode = true - const results = formats.map(format => { - // @ts-ignore - return dayjs(dateString, format, strictMode).isValid() - }) - return results.some(res => res === true) + // @ts-ignore + return formats.some(format => dayjs(dateString, format, strictMode).isValid()) } export function isFormatDateValid( From 274d01296f6a08bfe380a389f9dbe7deddb1668a Mon Sep 17 00:00:00 2001 From: Ilaria Venturini Date: Wed, 20 May 2020 11:58:04 +0200 Subject: [PATCH 12/13] =?UTF-8?q?=F0=9F=93=9D=20Add=20comment=20about=20ts?= =?UTF-8?q?-ignore?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/dataInference.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/dataInference.ts b/src/lib/dataInference.ts index 6556e81..c9439bd 100644 --- a/src/lib/dataInference.ts +++ b/src/lib/dataInference.ts @@ -104,6 +104,7 @@ export function detectValue( function isValidDate(dateString: string, formats: string[]): boolean { const strictMode = true + // ts-ignore is necessary because of strictMode parameter: `Argument of type 'true' is not assignable to parameter of type 'string | undefined'.` // @ts-ignore return formats.some(format => dayjs(dateString, format, strictMode).isValid()) } From b887843ba0bda5861ac49cbfe95c00d292550b93 Mon Sep 17 00:00:00 2001 From: Ilaria Venturini Date: Wed, 20 May 2020 12:00:00 +0200 Subject: [PATCH 13/13] =?UTF-8?q?=F0=9F=93=9D=20Better=20comment?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/dataInference.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib/dataInference.ts b/src/lib/dataInference.ts index c9439bd..e755dd0 100644 --- a/src/lib/dataInference.ts +++ b/src/lib/dataInference.ts @@ -104,8 +104,7 @@ export function detectValue( function isValidDate(dateString: string, formats: string[]): boolean { const strictMode = true - // ts-ignore is necessary because of strictMode parameter: `Argument of type 'true' is not assignable to parameter of type 'string | undefined'.` - // @ts-ignore + // @ts-ignore: necessary because of strictMode parameter: `Argument of type 'true' is not assignable to parameter of type 'string | undefined'.` return formats.some(format => dayjs(dateString, format, strictMode).isValid()) }