From 3dbd14c86556379858d41686b43e39bd13c4921d Mon Sep 17 00:00:00 2001 From: iamkun Date: Sun, 27 Dec 2020 11:51:26 +0800 Subject: [PATCH 1/8] chore: update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3e9d6b7e6..d5939702a 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ English | [简体中文](./docs/zh-cn/README.zh-CN.md) | [日本語](./docs/ja/R alt="Day.js">

Fast 2kB alternative to Moment.js with the same modern API

-多会

+多会

Date: Sun, 27 Dec 2020 20:50:31 +0900 Subject: [PATCH 2/8] fix: add type support for plural forms of units (#1289) --- types/index.d.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/types/index.d.ts b/types/index.d.ts index fcc9f4c45..91a842345 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -14,10 +14,14 @@ declare namespace dayjs { export type OptionType = { locale?: string, format?: string, utc?: boolean } | string | string[] type UnitTypeShort = 'd' | 'M' | 'y' | 'h' | 'm' | 's' | 'ms' - export type UnitType = 'millisecond' | 'second' | 'minute' | 'hour' | 'day' | 'month' | 'year' | 'date' | UnitTypeShort; - export type OpUnitType = UnitType | "week" | 'w'; - export type QUnitType = UnitType | "quarter" | 'Q'; + type UnitTypeLong = 'millisecond' | 'second' | 'minute' | 'hour' | 'day' | 'month' | 'year' | 'date' + + type UnitTypeLongPlural = `${UnitTypeLong}s` + export type UnitType = UnitTypeLong | UnitTypeLongPlural | UnitTypeShort; + + export type OpUnitType = UnitType | "week" | "weeks" | 'w'; + export type QUnitType = UnitType | "quarter" | "quarters" | 'Q'; class Dayjs { constructor (config?: ConfigType) From f2e479006a9a49bc0917f8620101d40ac645f7f2 Mon Sep 17 00:00:00 2001 From: Moshe Jonathan Gordon Radian Date: Sat, 2 Jan 2021 13:03:16 +0200 Subject: [PATCH 3/8] fix: add preParsePostFormat plugin & update Arabic [ar] locale (#1255) --- src/locale/ar.js | 38 ++++++ src/plugin/preParsePostFormat/index.js | 47 +++++++ src/plugin/relativeTime/index.js | 12 +- test/locale/ar.test.js | 52 ++++++++ test/plugin/preParsePostFormat.test.js | 169 +++++++++++++++++++++++++ types/plugin/preParsePostFormat.d.ts | 4 + 6 files changed, 320 insertions(+), 2 deletions(-) create mode 100644 src/plugin/preParsePostFormat/index.js create mode 100644 test/locale/ar.test.js create mode 100755 test/plugin/preParsePostFormat.test.js create mode 100644 types/plugin/preParsePostFormat.d.ts diff --git a/src/locale/ar.js b/src/locale/ar.js index 3a7bb3851..a7025c442 100644 --- a/src/locale/ar.js +++ b/src/locale/ar.js @@ -2,6 +2,31 @@ import dayjs from 'dayjs' const months = 'يناير_فبراير_مارس_أبريل_مايو_يونيو_يوليو_أغسطس_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split('_') +const symbolMap = { + 1: '١', + 2: '٢', + 3: '٣', + 4: '٤', + 5: '٥', + 6: '٦', + 7: '٧', + 8: '٨', + 9: '٩', + 0: '٠' +} + +const numberMap = { + '١': '1', + '٢': '2', + '٣': '3', + '٤': '4', + '٥': '5', + '٦': '6', + '٧': '7', + '٨': '8', + '٩': '9', + '٠': '0' +} const locale = { name: 'ar', @@ -26,6 +51,19 @@ const locale = { y: 'عام واحد', yy: '%d أعوام' }, + preparse(string) { + return string + .replace( + /[١٢٣٤٥٦٧٨٩٠]/g, + match => numberMap[match] + ) + .replace(/،/g, ',') + }, + postformat(string) { + return string + .replace(/\d/g, match => symbolMap[match]) + .replace(/,/g, '،') + }, ordinal: n => n, formats: { LT: 'HH:mm', diff --git a/src/plugin/preParsePostFormat/index.js b/src/plugin/preParsePostFormat/index.js new file mode 100644 index 000000000..f8e96d586 --- /dev/null +++ b/src/plugin/preParsePostFormat/index.js @@ -0,0 +1,47 @@ +// Plugin template from https://day.js.org/docs/en/plugin/plugin +export default (option, dayjsClass) => { + const oldParse = dayjsClass.prototype.parse + dayjsClass.prototype.parse = function (cfg) { + if (typeof cfg.date === 'string') { + const locale = this.$locale() + cfg.date = + locale && locale.preparse ? locale.preparse(cfg.date) : cfg.date + } + // original parse result + return oldParse.bind(this)(cfg) + } + + // // overriding existing API + // // e.g. extend dayjs().format() + const oldFormat = dayjsClass.prototype.format + dayjsClass.prototype.format = function (...args) { + // original format result + const result = oldFormat.call(this, ...args) + // return modified result + const locale = this.$locale() + return locale && locale.postformat ? locale.postformat(result) : result + } + + const oldFromTo = dayjsClass.prototype.fromToBase + + if (oldFromTo) { + dayjsClass.prototype.fromToBase = function ( + input, + withoutSuffix, + instance, + isFrom + ) { + const locale = this.$locale() || instance.$locale() + + // original format result + return oldFromTo.call( + this, + input, + withoutSuffix, + instance, + isFrom, + locale && locale.postformat + ) + } + } +} diff --git a/src/plugin/relativeTime/index.js b/src/plugin/relativeTime/index.js index e11b67a8e..8d61c45b0 100644 --- a/src/plugin/relativeTime/index.js +++ b/src/plugin/relativeTime/index.js @@ -19,7 +19,7 @@ export default (o, c, d) => { yy: '%d years' } d.en.relativeTime = relObj - const fromTo = (input, withoutSuffix, instance, isFrom) => { + proto.fromToBase = (input, withoutSuffix, instance, isFrom, postFormat) => { const loc = instance.$locale().relativeTime || relObj const T = o.thresholds || [ { l: 's', r: 44, d: C.S }, @@ -46,11 +46,14 @@ export default (o, c, d) => { ? d(input).diff(instance, t.d, true) : instance.diff(input, t.d, true) } - const abs = (o.rounding || Math.round)(Math.abs(result)) + let abs = (o.rounding || Math.round)(Math.abs(result)) isFuture = result > 0 if (abs <= t.r || !t.r) { if (abs <= 1 && i > 0) t = T[i - 1] // 1 minutes -> a minute, 0 seconds -> 0 second const format = loc[t.l] + if (postFormat) { + abs = postFormat(`${abs}`) + } if (typeof format === 'string') { out = format.replace('%d', abs) } else { @@ -66,6 +69,11 @@ export default (o, c, d) => { } return pastOrFuture.replace('%s', out) } + + function fromTo(input, withoutSuffix, instance, isFrom) { + return proto.fromToBase(input, withoutSuffix, instance, isFrom) + } + proto.to = function (input, withoutSuffix) { return fromTo(input, withoutSuffix, this, true) } diff --git a/test/locale/ar.test.js b/test/locale/ar.test.js new file mode 100644 index 000000000..3f9f60f0c --- /dev/null +++ b/test/locale/ar.test.js @@ -0,0 +1,52 @@ +import moment from 'moment' +import MockDate from 'mockdate' +import dayjs from '../../src' +import relativeTime from '../../src/plugin/relativeTime' +import preParsePostFormat from '../../src/plugin/preParsePostFormat' +import localeData from '../../src/plugin/localeData' +import '../../src/locale/ar' + +dayjs.extend(localeData) +dayjs.extend(relativeTime) +dayjs.extend(preParsePostFormat) + +beforeEach(() => { + MockDate.set(new Date()) +}) + +afterEach(() => { + MockDate.reset() +}) + +it('Format Month with locale function', () => { + for (let i = 0; i <= 7; i += 1) { + const dayjsAR = dayjs().locale('ar').add(i, 'day') + const momentAR = moment().locale('ar').add(i, 'day') + const testFormat1 = 'DD MMMM YYYY MMM' + const testFormat2 = 'MMMM' + const testFormat3 = 'MMM' + expect(dayjsAR.format(testFormat1)).toEqual(momentAR.format(testFormat1)) + expect(dayjsAR.format(testFormat2)).toEqual(momentAR.format(testFormat2)) + expect(dayjsAR.format(testFormat3)).toEqual(momentAR.format(testFormat3)) + } +}) + +it('Preparse with locale function', () => { + for (let i = 0; i <= 7; i += 1) { + dayjs.locale('ar') + const momentAR = moment().locale('ar').add(i, 'day') + expect(dayjs(momentAR.format()).format()).toEqual(momentAR.format()) + } +}) + +it('RelativeTime: Time from X gets formatted', () => { + const T = [ + [44.4, 'second', 'منذ ثانية واحدة'] + ] + + T.forEach((t) => { + dayjs.locale('ar') + expect(dayjs().from(dayjs().add(t[0], t[1]))) + .toBe(t[2]) + }) +}) diff --git a/test/plugin/preParsePostFormat.test.js b/test/plugin/preParsePostFormat.test.js new file mode 100755 index 000000000..685ac8d1d --- /dev/null +++ b/test/plugin/preParsePostFormat.test.js @@ -0,0 +1,169 @@ +import MockDate from 'mockdate' +// import moment from 'moment' +import dayjs from '../../src' +import preParsePostFormat from '../../src/plugin/preParsePostFormat' +import localeData from '../../src/plugin/localeData' +import duration from '../../src/plugin/duration' +import calendar from '../../src/plugin/calendar' +import objectSupport from '../../src/plugin/objectSupport' +import customParseFormat from '../../src/plugin/customParseFormat' +import relativeTime from '../../src/plugin/relativeTime' +import utc from '../../src/plugin/utc' +import arraySupport from '../../src/plugin/arraySupport' +import en from '../../src/locale/en' + +dayjs.extend(utc) +dayjs.extend(localeData) +dayjs.extend(customParseFormat) +dayjs.extend(arraySupport) +dayjs.extend(objectSupport) +dayjs.extend(calendar) +dayjs.extend(duration) +dayjs.extend(relativeTime) +dayjs.extend(preParsePostFormat) + +const symbolMap = { + 1: '!', + 2: '@', + 3: '#', + 4: '$', + 5: '%', + 6: '^', + 7: '&', + 8: '*', + 9: '(', + 0: ')' +} +const numberMap = { + '!': '1', + '@': '2', + '#': '3', + $: '4', + '%': '5', + '^': '6', + '&': '7', + '*': '8', + '(': '9', + ')': '0' +} + +const localeCustomizations = { + ...en, + preparse(string) { + if (typeof string !== 'string') { + // console.error('preparse - Expected string, got', { + // string + // }) + throw new Error(`preparse - Expected string, got ${typeof string}`) + } + try { + const res = string.replace(/[!@#$%^&*()]/g, match => numberMap[match]) + // console.log('Called custom preparse', { string, res }) + return res + } catch (error) { + const errorMsg = `Unexpected error during preparse of '${string}' - ${error}` + // console.error(errorMsg) + throw new Error(errorMsg) + } + }, + postformat(string) { + if (typeof string !== 'string') { + // console.error('postformat - Expected string, got', { + // string + // }) + throw new Error(`postformat - Expected string, got ${typeof string}`) + } + try { + const res = string.replace(/\d/g, match => symbolMap[match]) + // console.log('Called custom postformat', { string, res }) + return res + } catch (error) { + const errorMsg = `Unexpected error during postFormat of '${string}' - ${error}` + // console.error(errorMsg) + throw new Error(errorMsg) + } + } +} + +beforeEach(() => { + MockDate.set(new Date()) + dayjs.locale('symbol', localeCustomizations) +}) + +afterEach(() => { + MockDate.reset() + dayjs.locale('symbol', null) +}) + +describe('preparse and postformat', () => { + describe('transform', () => { + const TEST_DATE = '@)!@-)*-@&' + const TEST_NUM = 1346025600 + it('preparse string + format', () => + expect(dayjs.utc(TEST_DATE, 'YYYY-MM-DD').unix()).toBe(TEST_NUM)) + it('preparse ISO8601 string', () => + expect(dayjs.utc(TEST_DATE).unix()).toBe(TEST_NUM)) + it('postformat', () => + expect(dayjs + .unix(TEST_NUM) + .utc() + .format('YYYY-MM-DD')) + .toBe(TEST_DATE)) + }) + + describe('transform from', () => { + dayjs.locale('symbol', localeCustomizations) + const start = dayjs([2007, 1, 28]) + + const t1 = dayjs([2007, 1, 28]).add({ s: 90 }) + it('postformat should work on dayjs.fn.from', () => + expect(start.from(t1, true)).toBe('@ minutes')) + + const t2 = dayjs().add(6, 'd') + it('postformat should work on dayjs.fn.fromNow', () => + expect(t2.fromNow(true)).toBe('^ days')) + + it('postformat should work on dayjs.duration.fn.humanize', () => + expect(dayjs.duration(10, 'h').humanize()).toBe('!) hours')) + }) +}) + +describe('calendar day', () => { + const a = dayjs() + .hour(12) + .minute(0) + .second(0) + + it('today at the same time', () => + expect(dayjs(a).calendar()).toBe('Today at !@:)) PM')) + + it('Now plus 25 min', () => + expect(dayjs(a) + .add({ m: 25 }) + .calendar()) + .toBe('Today at !@:@% PM')) + + it('Now plus 1 hour', () => + expect(dayjs(a) + .add({ h: 1 }) + .calendar()) + .toBe('Today at !:)) PM')) + + it('tomorrow at the same time', () => + expect(dayjs(a) + .add({ d: 1 }) + .calendar()) + .toBe('Tomorrow at !@:)) PM')) + + it('Now minus 1 hour', () => + expect(dayjs(a) + .subtract({ h: 1 }) + .calendar()) + .toBe('Today at !!:)) AM')) + + it('yesterday at the same time', () => + expect(dayjs(a) + .subtract({ d: 1 }) + .calendar()) + .toBe('Yesterday at !@:)) PM')) +}) diff --git a/types/plugin/preParsePostFormat.d.ts b/types/plugin/preParsePostFormat.d.ts new file mode 100644 index 000000000..30ec75e5d --- /dev/null +++ b/types/plugin/preParsePostFormat.d.ts @@ -0,0 +1,4 @@ +import { PluginFunc } from 'dayjs' + +declare const plugin: PluginFunc +export = plugin From f9d79d5d21fc3958fb90232865acce2b21e4ff8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=91=E5=8F=B8=E3=83=B6=E8=B0=B7?= Date: Sun, 3 Jan 2021 16:08:33 +0900 Subject: [PATCH 4/8] test: add Japanese locale unit tests (#1280) --- test/locale/ja.test.js | 45 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 test/locale/ja.test.js diff --git a/test/locale/ja.test.js b/test/locale/ja.test.js new file mode 100644 index 000000000..a4d2b6f48 --- /dev/null +++ b/test/locale/ja.test.js @@ -0,0 +1,45 @@ +import MockDate from 'mockdate' +import moment from 'moment' +import dayjs from '../../src' +import relativeTime from '../../src/plugin/relativeTime' +import '../../src/locale/ja' + +dayjs.extend(relativeTime) + +beforeEach(() => { + MockDate.set(new Date()) +}) + +afterEach(() => { + MockDate.reset() +}) + +it('Finnish locale relative time in past and future', () => { + const cases = [ + [1, 'd', '1日後'], + [-1, 'd', '1日前'], + [2, 'd', '2日後'], + [-2, 'd', '2日前'], + [10, 'd', '10日後'], + [-10, 'd', '10日前'], + [6, 'm', '6分後'], + [-6, 'm', '6分前'], + [5, 'h', '5時間後'], + [-5, 'h', '5時間前'], + [3, 'M', '3ヶ月後'], + [-3, 'M', '3ヶ月前'], + [4, 'y', '4年後'], + [-4, 'y', '4年前'] + ] + cases.forEach((c) => { + expect(dayjs().add(c[0], c[1]).locale('ja').fromNow()) + .toBe(c[2]) + expect(dayjs().add(c[0], c[1]).locale('ja').fromNow()) + .toBe(moment().add(c[0], c[1]).locale('ja').fromNow()) + }) + expect(dayjs().add(-10, 'd').locale('ja').fromNow(true)) + .toBe('10日') + expect(dayjs().add(-10, 'd').locale('ja').fromNow(true)) + .toBe(moment().add(-10, 'd').locale('ja').fromNow(true)) +}) + From fd229fa5bd26bcba810e2535eb937ea8d99106c2 Mon Sep 17 00:00:00 2001 From: Tan Zhen Yong Date: Sun, 3 Jan 2021 15:45:40 +0800 Subject: [PATCH 5/8] fix: add ordinal to localeData plugin (#1266) --- src/plugin/localeData/index.js | 6 ++++-- test/plugin/localeData.test.js | 7 +++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/plugin/localeData/index.js b/src/plugin/localeData/index.js index 579c0ec36..034dbea13 100644 --- a/src/plugin/localeData/index.js +++ b/src/plugin/localeData/index.js @@ -29,7 +29,8 @@ export default (o, c, dayjs) => { // locale needed later weekdaysShort: instance => (instance ? instance.format('ddd') : getShort(this, 'weekdaysShort', 'weekdays', 3)), longDateFormat: format => getLongDateFormat(this.$locale(), format), - meridiem: this.$locale().meridiem + meridiem: this.$locale().meridiem, + ordinal: this.$locale().ordinal } } proto.localeData = function () { @@ -46,7 +47,8 @@ export default (o, c, dayjs) => { // locale needed later months: () => dayjs.months(), monthsShort: () => dayjs.monthsShort(), longDateFormat: format => getLongDateFormat(localeObject, format), - meridiem: localeObject.meridiem + meridiem: localeObject.meridiem, + ordinal: localeObject.ordinal } } diff --git a/test/plugin/localeData.test.js b/test/plugin/localeData.test.js index 6aa9637b6..51171268a 100644 --- a/test/plugin/localeData.test.js +++ b/test/plugin/localeData.test.js @@ -110,3 +110,10 @@ it('meridiem', () => { expect(typeof dayjs().localeData().meridiem).toEqual('function') dayjs.locale('en') }) + +it('ordinal', () => { + dayjs.locale('zh-cn') + expect(typeof dayjs.localeData().ordinal).toEqual('function') + expect(typeof dayjs().localeData().ordinal).toEqual('function') + dayjs.locale('en') +}) From f63375dea89becbd3bb2bb8ea7289c58c752bfed Mon Sep 17 00:00:00 2001 From: iamkun Date: Sun, 3 Jan 2021 15:46:48 +0800 Subject: [PATCH 6/8] feat: add ES6 Module Support, package.json module point to "esm/index.js" (#1298) fix #598, fix #313 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 37bf16612..fb7d94ae9 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "2KB immutable date time library alternative to Moment.js with the same modern API ", "main": "dayjs.min.js", "types": "index.d.ts", - "module": "dayjs.min.js", + "module": "esm/index.js", "scripts": { "test": "TZ=Pacific/Auckland npm run test-tz && TZ=Europe/London npm run test-tz && TZ=America/Whitehorse npm run test-tz && npm run test-tz && jest", "test-tz": "date && jest test/timezone.test --coverage=false", From 64037e6a8cf303dcfd2b954f309bd9691f87fffc Mon Sep 17 00:00:00 2001 From: bcurtin144 <32525780+bcurtin144@users.noreply.github.com> Date: Sun, 3 Jan 2021 01:59:54 -0600 Subject: [PATCH 7/8] fix: escape last period to match only milliseconds (#1239) (#1295) --- src/constant.js | 2 +- test/parse.test.js | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/constant.js b/src/constant.js index 22c1319e0..875ef02b4 100644 --- a/src/constant.js +++ b/src/constant.js @@ -26,5 +26,5 @@ export const FORMAT_DEFAULT = 'YYYY-MM-DDTHH:mm:ssZ' export const INVALID_DATE_STRING = 'Invalid Date' // regex -export const REGEX_PARSE = /^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[^0-9]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?.?(\d+)?$/ +export const REGEX_PARSE = /^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[^0-9]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?\.?(\d+)?$/ export const REGEX_FORMAT = /\[([^\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g diff --git a/test/parse.test.js b/test/parse.test.js index aecbaa898..501e213df 100644 --- a/test/parse.test.js +++ b/test/parse.test.js @@ -148,4 +148,34 @@ describe('REGEX_PARSE', () => { expect(dayjs(date).valueOf()).toBe(moment(date).valueOf()) expect(d.join('-')).toBe('2019-03-25T06:41:00.999999999-2019-03-25-06-41-00-999999999') }) + it('20210102T012345', () => { + const date = '20210102T012345' + const d = date.match(REGEX_PARSE) + expect(dayjs(date).valueOf()).toBe(moment(date).valueOf()) + expect(d.join('-')).toBe('20210102T012345-2021-01-02-01-23-45-') + }) + it('2021-01-02T01:23', () => { + const date = '2021-01-02T01:23' + const d = date.match(REGEX_PARSE) + expect(dayjs(date).valueOf()).toBe(moment(date).valueOf()) + expect(d.join('-')).toBe('2021-01-02T01:23-2021-01-02-01-23--') + }) + it('2021-01-02T01:23:45', () => { + const date = '2021-01-02T01:23:45' + const d = date.match(REGEX_PARSE) + expect(dayjs(date).valueOf()).toBe(moment(date).valueOf()) + expect(d.join('-')).toBe('2021-01-02T01:23:45-2021-01-02-01-23-45-') + }) + it('2021-01-02T01:23:45-0500 (no regex match)', () => { + const date = '2021-01-02T01:23:45-0500' + const d = date.match(REGEX_PARSE) + expect(dayjs(date).valueOf()).toBe(moment(date).valueOf()) + expect(d).toBe(null) + }) + it('2021-01-02T01:23:45Z (no regex match)', () => { + const date = '2021-01-02T01:23:45Z' + const d = date.match(REGEX_PARSE) + expect(dayjs(date).valueOf()).toBe(moment(date).valueOf()) + expect(d).toBe(null) + }) }) From bc53b53561f223b5efe7c4fbb76587f083ec8230 Mon Sep 17 00:00:00 2001 From: iamkun Date: Sun, 3 Jan 2021 16:05:14 +0800 Subject: [PATCH 8/8] test: add test --- test/parse.test.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/parse.test.js b/test/parse.test.js index 501e213df..1941b7335 100644 --- a/test/parse.test.js +++ b/test/parse.test.js @@ -166,6 +166,21 @@ describe('REGEX_PARSE', () => { expect(dayjs(date).valueOf()).toBe(moment(date).valueOf()) expect(d.join('-')).toBe('2021-01-02T01:23:45-2021-01-02-01-23-45-') }) + + it('2020-12-31T18:00:00.000-0500 (no regex match)', () => { + const date = '2020-12-31T18:00:00.000-0500' + const d = date.match(REGEX_PARSE) + expect(dayjs(date).valueOf()).toBe(moment(date).valueOf()) + expect(d).toBe(null) + }) + + it('2020-12-31T18:00:00-05:00 (no regex match)', () => { + const date = '2020-12-31T18:00:00-05:00' + const d = date.match(REGEX_PARSE) + expect(dayjs(date).valueOf()).toBe(moment(date).valueOf()) + expect(d).toBe(null) + }) + it('2021-01-02T01:23:45-0500 (no regex match)', () => { const date = '2021-01-02T01:23:45-0500' const d = date.match(REGEX_PARSE)