diff --git a/.editorconfig b/.editorconfig index 14c1d8c19..d4d73cf57 100644 --- a/.editorconfig +++ b/.editorconfig @@ -4,3 +4,4 @@ root = true charset = utf-8 end_of_line = lf insert_final_newline = true +indent_size = 2 diff --git a/README.md b/README.md index ca0443f1e..3a855a9c3 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -English | [简体中文](./docs/zh-cn/README.zh-CN.md) | [日本語](./docs/ja/README-ja.md) | [Português Brasileiro](./docs/pt-br/README-pt-br.md) | [한국어](./docs/ko/README-ko.md) | [Español (España)](./docs/es-es/README-es-es.md) | [Русский](./docs/ru/README-ru.md) | [Türkçe](./docs/tr/README-tr.md) | [සිංහල](./docs/si/README-si.md) +English | [简体中文](./docs/zh-cn/README.zh-CN.md) | [日本語](./docs/ja/README-ja.md) | [Português Brasileiro](./docs/pt-br/README-pt-br.md) | [한국어](./docs/ko/README-ko.md) | [Español (España)](./docs/es-es/README-es-es.md) | [Русский](./docs/ru/README-ru.md) | [Türkçe](./docs/tr/README-tr.md) | [සිංහල](./docs/si/README-si.md) | [עברית](./docs/he/README-he.md)
+
+עברית | [English](../../README.md) | [简体中文](./docs/zh-cn/README.zh-CN.md) | [日本語](./docs/ja/README-ja.md) | [Português Brasileiro](./docs/pt-br/README-pt-br.md) | [한국어](./docs/ko/README-ko.md) | [Español (España)](./docs/es-es/README-es-es.md) | [Русский](./docs/ru/README-ru.md) | [Türkçe](./docs/tr/README-tr.md) | [සිංහල](./docs/si/README-si.md)
+
+
+ אלטרנטיבה מהירה ל-Moment.js ששוקלת רק 2kB עם אותן יכולות מודרניות
+
+
+
+
+
+
+
+
+
+
+
+
+## רישיון
+
+Day.js מורשה לשימוש עם [רישיון MIT](./LICENSE).
+
diff --git a/docs/ja/README-ja.md b/docs/ja/README-ja.md
index b40ceeb4b..a708a03bb 100644
--- a/docs/ja/README-ja.md
+++ b/docs/ja/README-ja.md
@@ -1,4 +1,4 @@
-日本語 | [English](../../README.md) | [简体中文](../zh-cn/README.zh-CN.md) | [Português Brasileiro](../pt-br/README-pt-br.md) | [한국어](../ko/README-ko.md) | [Español (España)](../es-es/README-es-es.md) | [Русский](../ru/README-ru.md)
+日本語 | [English](../../README.md) | [简体中文](../zh-cn/README.zh-CN.md) | [Português Brasileiro](../pt-br/README-pt-br.md) | [한국어](../ko/README-ko.md) | [Español (España)](../es-es/README-es-es.md) | [Русский](../ru/README-ru.md)| [עברית](./docs/he/README-he.md)
{ + switch (match) { + case 'YY': + return String(this.$y).slice(-2) + case 'YYYY': + return Utils.s(this.$y, 4, '0') + case 'M': + return $M + 1 + case 'MM': + return Utils.s($M + 1, 2, '0') + case 'MMM': + return getShort(locale.monthsShort, $M, months, 3) + case 'MMMM': + return getShort(months, $M) + case 'D': + return this.$D + case 'DD': + return Utils.s(this.$D, 2, '0') + case 'd': + return String(this.$W) + case 'dd': + return getShort(locale.weekdaysMin, this.$W, weekdays, 2) + case 'ddd': + return getShort(locale.weekdaysShort, this.$W, weekdays, 3) + case 'dddd': + return weekdays[this.$W] + case 'H': + return String($H) + case 'HH': + return Utils.s($H, 2, '0') + case 'h': + return get$H(1) + case 'hh': + return get$H(2) + case 'a': + return meridiemFunc($H, $m, true) + case 'A': + return meridiemFunc($H, $m, false) + case 'm': + return String($m) + case 'mm': + return Utils.s($m, 2, '0') + case 's': + return String(this.$s) + case 'ss': + return Utils.s(this.$s, 2, '0') + case 'SSS': + return Utils.s(this.$ms, 3, '0') + case 'Z': + return zoneStr // 'ZZ' logic below + default: + break + } + return null } - return str.replace(C.REGEX_FORMAT, (match, $1) => $1 || matches[match] || zoneStr.replace(':', '')) // 'ZZ' + return str.replace(C.REGEX_FORMAT, (match, $1) => $1 || matches(match) || zoneStr.replace(':', '')) // 'ZZ' } utcOffset() { @@ -319,18 +348,38 @@ class Dayjs { const that = dayjs(input) const zoneDelta = (that.utcOffset() - this.utcOffset()) * C.MILLISECONDS_A_MINUTE const diff = this - that - let result = Utils.m(this, that) - - result = { - [C.Y]: result / 12, - [C.M]: result, - [C.Q]: result / 3, - [C.W]: (diff - zoneDelta) / C.MILLISECONDS_A_WEEK, - [C.D]: (diff - zoneDelta) / C.MILLISECONDS_A_DAY, - [C.H]: diff / C.MILLISECONDS_A_HOUR, - [C.MIN]: diff / C.MILLISECONDS_A_MINUTE, - [C.S]: diff / C.MILLISECONDS_A_SECOND - }[unit] || diff // milliseconds + const getMonth = () => Utils.m(this, that) + + let result + switch (unit) { + case C.Y: + result = getMonth() / 12 + break + case C.M: + result = getMonth() + break + case C.Q: + result = getMonth() / 3 + break + case C.W: + result = (diff - zoneDelta) / C.MILLISECONDS_A_WEEK + break + case C.D: + result = (diff - zoneDelta) / C.MILLISECONDS_A_DAY + break + case C.H: + result = diff / C.MILLISECONDS_A_HOUR + break + case C.MIN: + result = diff / C.MILLISECONDS_A_MINUTE + break + case C.S: + result = diff / C.MILLISECONDS_A_SECOND + break + default: + result = diff // milliseconds + break + } return float ? result : Utils.a(result) } diff --git a/src/plugin/duration/index.js b/src/plugin/duration/index.js index 5d4cc6aa8..26bc75e34 100644 --- a/src/plugin/duration/index.js +++ b/src/plugin/duration/index.js @@ -257,6 +257,15 @@ class Duration { asYears() { return this.as('years') } } +const manipulateDuration = (date, duration, k) => + date.add(duration.years() * k, 'y') + .add(duration.months() * k, 'M') + .add(duration.days() * k, 'd') + .add(duration.hours() * k, 'h') + .add(duration.minutes() * k, 'm') + .add(duration.seconds() * k, 's') + .add(duration.milliseconds() * k, 'ms') + export default (option, Dayjs, dayjs) => { $d = dayjs $u = dayjs().$utils() @@ -268,12 +277,20 @@ export default (option, Dayjs, dayjs) => { const oldAdd = Dayjs.prototype.add const oldSubtract = Dayjs.prototype.subtract + Dayjs.prototype.add = function (value, unit) { - if (isDuration(value)) value = value.asMilliseconds() + if (isDuration(value)) { + return manipulateDuration(this, value, 1) + } + return oldAdd.bind(this)(value, unit) } + Dayjs.prototype.subtract = function (value, unit) { - if (isDuration(value)) value = value.asMilliseconds() + if (isDuration(value)) { + return manipulateDuration(this, value, -1) + } + return oldSubtract.bind(this)(value, unit) } } diff --git a/src/plugin/minMax/index.js b/src/plugin/minMax/index.js index f515c60d9..8b3e2d3fe 100644 --- a/src/plugin/minMax/index.js +++ b/src/plugin/minMax/index.js @@ -1,12 +1,18 @@ export default (o, c, d) => { const sortBy = (method, dates) => { - if (!dates || !dates.length || !dates[0] || (dates.length === 1 && !dates[0].length)) { + if ( + !dates || + !dates.length || + (dates.length === 1 && !dates[0]) || + (dates.length === 1 && Array.isArray(dates[0]) && !dates[0].length) + ) { return null } if (dates.length === 1 && dates[0].length > 0) { [dates] = dates } - let result + dates = dates.filter(date => date) + let result; [result] = dates for (let i = 1; i < dates.length; i += 1) { if (!dates[i].isValid() || dates[i][method](result)) { diff --git a/src/plugin/objectSupport/index.js b/src/plugin/objectSupport/index.js index 650166606..bd32358e9 100644 --- a/src/plugin/objectSupport/index.js +++ b/src/plugin/objectSupport/index.js @@ -1,6 +1,6 @@ export default (o, c, dayjs) => { const proto = c.prototype - const isObject = obj => !(obj instanceof Date) && !(obj instanceof Array) + const isObject = obj => obj !== null && !(obj instanceof Date) && !(obj instanceof Array) && !proto.$utils().u(obj) && (obj.constructor.name === 'Object') const prettyUnit = (u) => { const unit = proto.$utils().p(u) diff --git a/test/display.test.js b/test/display.test.js index 86a978dfc..ce1f47893 100644 --- a/test/display.test.js +++ b/test/display.test.js @@ -264,11 +264,7 @@ it('As ISO 8601 String -> toISOString e.g. 2013-02-04T22:44:30.652Z', () => { it('Year 1 formatted with YYYY should pad with zeroes', () => { const date = new Date(1, 0, 1) date.setUTCFullYear(1) // Required because 0-99 are parsed as 19xx in JS: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date#year - expect(dayjs(date).format('YYYY')).toBe('0001') -}) - -it('Year 1 formatting matches moment format', () => { - const date = new Date(1, 0, 1) - date.setUTCFullYear(1) - expect(dayjs(date).format('YYYY')).toBe(moment(date).format('YYYY')) + const res = dayjs(date).format('YYYY') + expect(res.slice(0, 3)).toBe('000') // because of timezone, the result might be 0000 0001 or 0002 + expect(res).toBe(moment(date).format('YYYY')) }) diff --git a/test/plugin/duration.test.js b/test/plugin/duration.test.js index 8a7e0e6cd..4a4753931 100644 --- a/test/plugin/duration.test.js +++ b/test/plugin/duration.test.js @@ -182,6 +182,10 @@ test('Add duration', () => { const a = dayjs('2020-10-01') const days = dayjs.duration(2, 'days') expect(a.add(days).format('YYYY-MM-DD')).toBe('2020-10-03') + + const b = dayjs('2023-02-01 00:00:00') + const p = dayjs.duration('P1Y1M1DT1H1M1S') + expect(b.add(p).format('YYYY-MM-DD HH:mm:ss')).toBe('2024-03-02 01:01:01') }) describe('Subtract', () => { @@ -194,6 +198,10 @@ test('Subtract duration', () => { const a = dayjs('2020-10-20') const days = dayjs.duration(2, 'days') expect(a.subtract(days).format('YYYY-MM-DD')).toBe('2020-10-18') + + const b = dayjs('2023-03-02 02:02:02') + const p = dayjs.duration('P1Y1M1DT1H1M1S') + expect(b.subtract(p).format('YYYY-MM-DD HH:mm:ss')).toBe('2022-02-01 01:01:01') }) describe('Seconds', () => { diff --git a/test/plugin/minMax.test.js b/test/plugin/minMax.test.js index eeef92063..f8a508001 100644 --- a/test/plugin/minMax.test.js +++ b/test/plugin/minMax.test.js @@ -55,3 +55,17 @@ it('If Invalid Date return Invalid Date', () => { expect(dayjs.min([arg1, arg2, arg3, arg4]).format()) .toBe(arg4.format()) }) + +it('Ignore if exists an "null" argument', () => { + expect(dayjs.max(null, null, arg1, arg2, null, arg3).format()) + .toBe(arg1.format()) + expect(dayjs.min([null, null, arg1, arg2, null, arg3]).format()) + .toBe(arg3.format()) +}) + +it('Return the only date if just provided one argument', () => { + expect(dayjs.max(arg1).format()) + .toBe(arg1.format()) + expect(dayjs.min([arg1]).format()) + .toBe(arg1.format()) +}) diff --git a/test/plugin/objectSupport.test.js b/test/plugin/objectSupport.test.js index 06b10f9dc..abf046d34 100755 --- a/test/plugin/objectSupport.test.js +++ b/test/plugin/objectSupport.test.js @@ -140,6 +140,12 @@ it('Constructor from Object UTC', () => { expect(moment.utc(tests[i][0]).format(fmt)).toBe(result) } }) + +it('Constructor from null should return Invalid Date', () => { + expect(dayjs(null).isValid()).toBe(false) + expect(moment(null).isValid()).toBe(false) +}) + it('Set from Object', () => { for (let i = 0; i < tests.length; i += 1) { expect(dayjs(now).set(tests[i][0]).format(fmt)).toBe(moment(now).set(tests[i][0]).format(fmt)) @@ -384,3 +390,11 @@ it('add decimal values of days and months', () => { expect(dayjs([2016, 7, 1]).add(1.6, 'years').format('YYYY-MM-DD')).toBe('2017-07-01') expect(dayjs([2016, 1, 1]).add(1.1, 'quarters').format('YYYY-MM-DD')).toBe('2016-04-01') }) + +it('returns valid date on undefined', () => { + expect(dayjs().isValid()).toBe(true) +}) + +it('returns invalid date on null', () => { + expect(dayjs(null).isValid()).toBe(false) +}) diff --git a/types/plugin/minMax.d.ts b/types/plugin/minMax.d.ts index f1673500c..4c5f6dcd7 100644 --- a/types/plugin/minMax.d.ts +++ b/types/plugin/minMax.d.ts @@ -4,8 +4,8 @@ declare const plugin: PluginFunc export = plugin declare module 'dayjs' { - export function max(dayjs: Dayjs[]): Dayjs - export function max(...dayjs: Dayjs[]): Dayjs - export function min(dayjs: Dayjs[]): Dayjs - export function min(...dayjs: Dayjs[]): Dayjs + export function max(dayjs: Dayjs[]): Dayjs | null + export function max(...dayjs: Dayjs[]): Dayjs | null + export function min(dayjs: Dayjs[]): Dayjs | null + export function min(...dayjs: Dayjs[]): Dayjs | null }