From 52dfb13a6b84f0a753cc5761192b92416f440961 Mon Sep 17 00:00:00 2001 From: Zero no Overture Date: Thu, 30 Apr 2020 16:01:05 +0800 Subject: [PATCH 1/7] fix: Add plugin objectSupport (#887) --- src/plugin/objectSupport/index.js | 63 ++++++ test/plugin/objectSupport.test.js | 344 ++++++++++++++++++++++++++++++ types/plugin/objectSupport.d.ts | 12 ++ 3 files changed, 419 insertions(+) create mode 100644 src/plugin/objectSupport/index.js create mode 100755 test/plugin/objectSupport.test.js create mode 100755 types/plugin/objectSupport.d.ts diff --git a/src/plugin/objectSupport/index.js b/src/plugin/objectSupport/index.js new file mode 100644 index 000000000..9eab4acd5 --- /dev/null +++ b/src/plugin/objectSupport/index.js @@ -0,0 +1,63 @@ +export default (o, c) => { + const proto = c.prototype + const isObject = obj => !(obj instanceof Date) && !(obj instanceof Array) && obj instanceof Object + const prettyUnit = (u) => { + const unit = proto.$utils().p(u) + return unit === 'date' ? 'day' : unit + } + const parseDate = (cfg) => { + const { date, utc } = cfg + const $d = {} + if (isObject(date)) { + Object.keys(date).forEach((k) => { + $d[prettyUnit(k)] = date[k] + }) + const y = $d.year || 1970 + const M = $d.month - 1 || 0 + const d = $d.day || 1 + const h = $d.hour || 0 + const m = $d.minute || 0 + const s = $d.second || 0 + const ms = $d.millisecond || 0 + if (utc) { + return new Date(Date.UTC(y, M, d, h, m, s, ms)) + } + return new Date(y, M, d, h, m, s, ms) + } + return date + } + + const oldParse = proto.parse + proto.parse = function (cfg) { + cfg.date = parseDate.bind(this)(cfg) + oldParse.bind(this)(cfg) + } + + const oldSet = proto.set + const oldAdd = proto.add + + const callObject = function (call, argument, string, offset = 1) { + if (argument instanceof Object) { + const keys = Object.keys(argument) + let chain = this + keys.forEach((key) => { + chain = call.bind(chain)(argument[key] * offset, key) + }) + return chain + } + return call.bind(this)(argument * offset, string) + } + + proto.set = function (string, int) { + int = int === undefined ? string : int + return callObject.bind(this)(function (i, s) { + return oldSet.bind(this)(s, i) + }, int, string) + } + proto.add = function (number, string) { + return callObject.bind(this)(oldAdd, number, string) + } + proto.subtract = function (number, string) { + return callObject.bind(this)(oldAdd, number, string, -1) + } +} diff --git a/test/plugin/objectSupport.test.js b/test/plugin/objectSupport.test.js new file mode 100755 index 000000000..078ff192a --- /dev/null +++ b/test/plugin/objectSupport.test.js @@ -0,0 +1,344 @@ +import moment from 'moment' +import MockDate from 'mockdate' +import dayjs from '../../src' +import objectSupport from '../../src/plugin/objectSupport' +import quarterOfYear from '../../src/plugin/quarterOfYear' +import utc from '../../src/plugin/utc' + +dayjs.extend(utc) +dayjs.extend(quarterOfYear) +dayjs.extend(objectSupport) + +beforeEach(() => { + MockDate.set(new Date()) +}) + +afterEach(() => { + MockDate.reset() +}) +const now = new Date() +const fmt = 'YYYY-MM-DD HH:mm:ss.SSS' +const tests = [ + [{ year: 2010 }, '2010-01-01 00:00:00.000'], + [{ year: 2010, month: 1 }, '2010-01-01 00:00:00.000'], + [{ year: 2010, month: 1, day: 12 }, '2010-01-12 00:00:00.000'], + [{ year: 2010, month: 1, date: 12 }, '2010-01-12 00:00:00.000'], + [ + { + hour: 15, minute: 25, second: 50, millisecond: 125 + }, + '1970-01-01 15:25:50.125'], + [ + { + year: 2010, month: 1, day: 12, hours: 1 + }, + '2010-01-12 01:00:00.000' + ], + [ + { + year: 2010, month: 1, date: 12, hours: 1 + }, + '2010-01-12 01:00:00.000' + ], + [ + { + year: 2010, month: 1, day: 12, hours: 1, minutes: 1 + }, + '2010-01-12 01:01:00.000' + ], + [ + { + year: 2010, month: 1, date: 12, hours: 1, minutes: 1 + }, + '2010-01-12 01:01:00.000' + ], + [ + { + year: 2010, + month: 1, + day: 12, + hours: 1, + minutes: 1, + seconds: 1 + }, + '2010-01-12 01:01:01.000' + ], + [ + { + year: 2010, + month: 1, + day: 12, + hours: 1, + minutes: 1, + seconds: 1, + milliseconds: 1 + }, + '2010-01-12 01:01:01.001' + ], + [ + { + years: 2010, + months: 1, + days: 14, + hours: 15, + minutes: 25, + seconds: 50, + milliseconds: 125 + }, + '2010-01-14 15:25:50.125' + ], + [ + { + year: 2010, + month: 1, + day: 14, + hour: 15, + minute: 25, + second: 50, + millisecond: 125 + }, + '2010-01-14 15:25:50.125' + ], + [ + { + y: 2010, M: 1, d: 14, h: 15, m: 25, s: 50, ms: 125 + }, + '2010-01-14 15:25:50.125' + ] +] +it('Constructor from Object', () => { + for (let i = 0; i < tests.length; i += 1) { + expect(dayjs(tests[i][0]).format(fmt)).toBe(tests[i][1]) + } +}) + +it('Constructor from Object UTC', () => { + for (let i = 0; i < tests.length; i += 1) { + expect(dayjs.utc(tests[i][0]).format(fmt)).toBe(tests[i][1]) + } +}) +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)) + } +}) + +it('add short reverse args', () => { + const a = dayjs({ + year: 2011, + month: 9, + date: 12, + hour: 6, + minute: 7, + second: 8, + millisecond: 500 + }) + expect(a.add({ ms: 50 }).millisecond()).toBe(550) + expect(a.add({ s: 1 }).second()).toBe(9) + expect(a.add({ m: 1 }).minute()).toBe(8) + expect(a.add({ h: 1 }).hour()).toBe(7) + expect(a.add({ d: 1 }).date()).toBe(13) + expect(a.add({ w: 1 }).date()).toBe(19) + expect(a.add({ M: 1 }).month()).toBe(9) + expect(a.add({ y: 1 }).year()).toBe(2012) + expect(a.add({ Q: 1 }).month()).toBe(11) + + const b = dayjs([2010, 1, 31]).add({ M: 1 }) + const c = dayjs([2010, 2, 28]).subtract({ M: 1 }) + const d = dayjs([2010, 2, 28]).subtract({ Q: 1 }) + + expect(b.month()).toBe(1) + expect(b.date()).toBe(28) + expect(c.month()).toBe(0) + expect(c.date()).toBe(28) + expect(d.month()).toBe(10) + expect(d.date()).toBe(28) + expect(d.year()).toBe(2009) +}) + +it('add long reverse args', () => { + const a = dayjs({ + year: 2011, + month: 9, + date: 12, + hour: 6, + minute: 7, + second: 8, + millisecond: 500 + }) + + expect(a.add({ milliseconds: 50 }).millisecond()).toBe(550) + expect(a.add({ seconds: 1 }).second()).toBe(9) + expect(a.add({ minutes: 1 }).minute()).toBe(8) + expect(a.add({ hours: 1 }).hour()).toBe(7) + expect(a.add({ days: 1 }).date()).toBe(13) + expect(a.add({ weeks: 1 }).date()).toBe(19) + expect(a.add({ months: 1 }).month()).toBe(9) + expect(a.add({ years: 1 }).year()).toBe(2012) + expect(a.add({ quarters: 1 }).month()).toBe(11) +}) + +it('add long singular reverse args', () => { + const a = dayjs({ + year: 2011, + month: 9, + date: 12, + hour: 6, + minute: 7, + second: 8, + millisecond: 500 + }) + + expect(a.add({ millisecond: 50 }).millisecond()).toBe(550) + expect(a.add({ second: 1 }).second()).toBe(9) + expect(a.add({ minute: 1 }).minute()).toBe(8) + expect(a.add({ hour: 1 }).hour()).toBe(7) + expect(a.add({ day: 1 }).date()).toBe(13) + expect(a.add({ week: 1 }).date()).toBe(19) + expect(a.add({ month: 1 }).month()).toBe(9) + expect(a.add({ year: 1 }).year()).toBe(2012) + expect(a.add({ quarter: 1 }).month()).toBe(11) +}) + +it('add string long', () => { + const a = dayjs({ + year: 2011, + month: 9, + date: 12, + hour: 6, + minute: 7, + second: 8, + millisecond: 500 + }) + + expect(a.add(50, 'millisecond').millisecond()).toBe(550) + expect(a.add(1, 'second').second()).toBe(9) + expect(a.add(1, 'minute').minute()).toBe(8) + expect(a.add(1, 'hour').hour()).toBe(7) + expect(a.add(1, 'day').date()).toBe(13) + expect(a.add(1, 'week').date()).toBe(19) + expect(a.add(1, 'month').month()).toBe(9) + expect(a.add(1, 'year').year()).toBe(2012) + expect(a.add(1, 'quarter').month()).toBe(11) +}) + +it('add string long singular', () => { + const a = dayjs({ + year: 2011, + month: 9, + date: 12, + hour: 6, + minute: 7, + second: 8, + millisecond: 500 + }) + + expect(a.add(50, 'milliseconds').millisecond()).toBe(550) + expect(a.add(1, 'seconds').second()).toBe(9) + expect(a.add(1, 'minutes').minute()).toBe(8) + expect(a.add(1, 'hours').hour()).toBe(7) + expect(a.add(1, 'days').date()).toBe(13) + expect(a.add(1, 'weeks').date()).toBe(19) + expect(a.add(1, 'months').month()).toBe(9) + expect(a.add(1, 'years').year()).toBe(2012) + expect(a.add(1, 'quarters').month()).toBe(11) +}) + +it('add string short', () => { + const a = dayjs({ + year: 2011, + month: 9, + date: 12, + hour: 6, + minute: 7, + second: 8, + millisecond: 500 + }) + + expect(a.add(50, 'ms').millisecond()).toBe(550) + expect(a.add(1, 's').second()).toBe(9) + expect(a.add(1, 'm').minute()).toBe(8) + expect(a.add(1, 'h').hour()).toBe(7) + expect(a.add(1, 'd').date()).toBe(13) + expect(a.add(1, 'w').date()).toBe(19) + expect(a.add(1, 'M').month()).toBe(9) + expect(a.add(1, 'y').year()).toBe(2012) + expect(a.add(1, 'Q').month()).toBe(11) +}) + +it('add strings string short', () => { + const a = dayjs({ + year: 2011, + month: 9, + date: 12, + hour: 6, + minute: 7, + second: 8, + millisecond: 500 + }) + + expect(a.add('50', 'ms').millisecond()).toBe(550) + expect(a.add('1', 's').second()).toBe(9) + expect(a.add('1', 'm').minute()).toBe(8) + expect(a.add('1', 'h').hour()).toBe(7) + expect(a.add('1', 'd').date()).toBe(13) + expect(a.add('1', 'w').date()).toBe(19) + expect(a.add('1', 'M').month()).toBe(9) + expect(a.add('1', 'y').year()).toBe(2012) + expect(a.add('1', 'Q').month()).toBe(11) +}) + +it('add no string with milliseconds default', () => { + const a = dayjs({ + year: 2011, + month: 9, + date: 12, + hour: 6, + minute: 7, + second: 8, + millisecond: 500 + }) + + expect(a.add(50).millisecond()).toBe(550) +}) + +it('subtract strings string short', () => { + const a = dayjs({ + year: 2011, + month: 9, + date: 12, + hour: 6, + minute: 7, + second: 8, + millisecond: 500 + }) + expect(a.subtract('50', 'ms').millisecond()).toBe(450) + expect(a.subtract('1', 's').second()).toBe(7) + expect(a.subtract('1', 'm').minute()).toBe(6) + expect(a.subtract('1', 'h').hour()).toBe(5) + expect(a.subtract('1', 'd').date()).toBe(11) + expect(a.subtract('1', 'w').date()).toBe(5) + expect(a.subtract('1', 'M').month()).toBe(7) + expect(a.subtract('1', 'y').year()).toBe(2010) + expect(a.subtract('1', 'Q').month()).toBe(5) +}) + +it('add decimal values of days and months', () => { + expect(dayjs([2016, 4, 3]).add(1.6, 'days').date()).toBe(5) + expect(dayjs([2016, 4, 3]).add(-1.6, 'days').date()).toBe(1) + expect(dayjs([2016, 4, 1]).add(-1.6, 'days').date()).toBe(30) + expect(dayjs([2016, 4, 3]).add(1.6, 'months').month()).toBe(4) + expect(dayjs([2016, 4, 3]).add(-1.6, 'months').month()).toBe(1) + expect(dayjs([2016, 1, 3]).add(-1.6, 'months').month()).toBe(11) + expect(dayjs([2016, 4, 3]).subtract(1.6, 'days').date()).toBe(1) + expect(dayjs([2016, 4, 2]).subtract(1.6, 'days').date()).toBe(31) + expect(dayjs([2016, 2, 1]).subtract(1.1, 'days').date()).toBe(31) + expect(dayjs([2016, 4, 3]).subtract(-1.6, 'days').date()).toBe(5) + expect(dayjs([2016, 4, 30]).subtract(-1.6, 'days').date()).toBe(2) + expect(dayjs([2016, 4, 3]).subtract(1.6, 'months').month()).toBe(1) + expect(dayjs([2016, 4, 3]).subtract(-1.6, 'months').month()).toBe(4) + expect(dayjs([2016, 12, 31]).subtract(-1.6, 'months').month()).toBe(0) + expect(dayjs([2016, 1, 1]).add(1.6, 'years').format('YYYY-MM-DD')).toBe('2017-01-01') + 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') +}) diff --git a/types/plugin/objectSupport.d.ts b/types/plugin/objectSupport.d.ts new file mode 100755 index 000000000..0d3cf05b4 --- /dev/null +++ b/types/plugin/objectSupport.d.ts @@ -0,0 +1,12 @@ +import { PluginFunc } from 'dayjs' + +declare const plugin: PluginFunc +export = plugin + +declare module 'dayjs' { + interface Dayjs { + set(argument: object): Dayjs + add(argument: object): Dayjs + subtract(argument: object): Dayjs + } +} From a9ca8dcbbd0964c5b9abb4e8a2d620c983cf091a Mon Sep 17 00:00:00 2001 From: Guvanch Nurgeldiyev <16291863+gnurgeldiyev@users.noreply.github.com> Date: Sun, 3 May 2020 16:05:26 +0300 Subject: [PATCH 2/7] fix: Add Turkmen (tk) locale (#893) Co-authored-by: Guvanch Nurgeldiyev --- src/locale/tk.js | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 src/locale/tk.js diff --git a/src/locale/tk.js b/src/locale/tk.js new file mode 100644 index 000000000..268cc8bb0 --- /dev/null +++ b/src/locale/tk.js @@ -0,0 +1,40 @@ +// Turkmen [tk] +import dayjs from 'dayjs' + +const locale = { + name: 'tk', + weekdays: 'Ýekşenbe_Duşenbe_Sişenbe_Çarşenbe_Penşenbe_Anna_Şenbe'.split('_'), + weekdaysShort: 'Ýek_Duş_Siş_Çar_Pen_Ann_Şen'.split('_'), + weekdaysMin: 'Ýk_Dş_Sş_Çr_Pn_An_Şn'.split('_'), + months: 'Ýanwar_Fewral_Mart_Aprel_Maý_Iýun_Iýul_Awgust_Sentýabr_Oktýabr_Noýabr_Dekabr'.split('_'), + monthsShort: 'Ýan_Few_Mar_Apr_Maý_Iýn_Iýl_Awg_Sen_Okt_Noý_Dek'.split('_'), + weekStart: 1, + formats: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD.MM.YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd, D MMMM YYYY HH:mm' + }, + relativeTime: { + future: '%s soň', + past: '%s öň', + s: 'birnäçe sekunt', + m: 'bir minut', + mm: '%d minut', + h: 'bir sagat', + hh: '%d sagat', + d: 'bir gün', + dd: '%d gün', + M: 'bir aý', + MM: '%d aý', + y: 'bir ýyl', + yy: '%d ýyl' + }, + ordinal: n => `${n}.` +} + +dayjs.locale(locale, null, true) + +export default locale From 8035c8a760549b631252252718db3cdc4ab2f68f Mon Sep 17 00:00:00 2001 From: iamkun Date: Wed, 6 May 2020 15:21:24 +0800 Subject: [PATCH 3/7] fix: Fix CustomParseFormat plugin set locale error (#896) --- src/plugin/customParseFormat/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugin/customParseFormat/index.js b/src/plugin/customParseFormat/index.js index 850c0483c..044f62fd6 100644 --- a/src/plugin/customParseFormat/index.js +++ b/src/plugin/customParseFormat/index.js @@ -200,7 +200,7 @@ export default (o, C, d) => { if (isStrict && date !== this.format(format)) { this.$d = new Date('') } - if (pl && pl !== true) this.$L = pl + if (pl && pl !== true) this.$L = this.locale(pl).$L } else { oldParse.call(this, cfg) } From f355235a836540d77880959fb1b614c87e9f7b3e Mon Sep 17 00:00:00 2001 From: David Furlong Date: Wed, 13 May 2020 04:52:25 +0200 Subject: [PATCH 4/7] fix: Add Kinyarwanda (rw) locale (#903) --- src/locale/rw.js | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/locale/rw.js diff --git a/src/locale/rw.js b/src/locale/rw.js new file mode 100644 index 000000000..316037e08 --- /dev/null +++ b/src/locale/rw.js @@ -0,0 +1,36 @@ +// Kinyarwanda (Rwanda) [rw] +import dayjs from 'dayjs' + +const locale = { + name: 'rw', + weekdays: 'Ku Cyumweru_Kuwa Mbere_Kuwa Kabiri_Kuwa Gatatu_Kuwa Kane_Kuwa Gatanu_Kuwa Gatandatu'.split('_'), + months: 'Mutarama_Gashyantare_Werurwe_Mata_Gicurasi_Kamena_Nyakanga_Kanama_Nzeri_Ukwakira_Ugushyingo_Ukuboza'.split('_'), + relativeTime: { + future: 'mu %s', + past: '%s', + s: 'amasegonda', + m: 'Umunota', + mm: '%d iminota', + h: 'isaha', + hh: '%d amasaha', + d: 'Umunsi', + dd: '%d iminsi', + M: 'ukwezi', + MM: '%d amezi', + y: 'umwaka', + yy: '%d imyaka' + }, + formats: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd, D MMMM YYYY HH:mm' + }, + ordinal: n => n +} + +dayjs.locale(locale, null, true) + +export default locale From 97856c603ef5fbbeb1cf8a42387479e56a77dbe8 Mon Sep 17 00:00:00 2001 From: iamkun Date: Thu, 14 May 2020 15:31:38 +0800 Subject: [PATCH 5/7] fix: Update CustomParseFormat plugin to support Array formats (#906) --- src/plugin/customParseFormat/index.js | 17 +++++++++++++++-- test/plugin/customParseFormat.test.js | 19 +++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/plugin/customParseFormat/index.js b/src/plugin/customParseFormat/index.js index 044f62fd6..5077a14b4 100644 --- a/src/plugin/customParseFormat/index.js +++ b/src/plugin/customParseFormat/index.js @@ -196,11 +196,24 @@ export default (o, C, d) => { locale = pl ? d.Ls[pl] : this.$locale() } this.$d = parseFormattedInput(date, format, utc) - this.init(cfg) + this.init() + if (pl && pl !== true) this.$L = this.locale(pl).$L if (isStrict && date !== this.format(format)) { this.$d = new Date('') } - if (pl && pl !== true) this.$L = this.locale(pl).$L + } else if (format instanceof Array) { + const len = format.length + for (let i = 1; i <= len; i += 1) { + args[1] = format[i - 1] + const result = d.apply(this, args) + if (result.isValid()) { + this.$d = result.$d + this.$L = result.$L + this.init() + break + } + if (i === len) this.$d = new Date('') + } } else { oldParse.call(this, cfg) } diff --git a/test/plugin/customParseFormat.test.js b/test/plugin/customParseFormat.test.js index 0e0260315..a326c688c 100644 --- a/test/plugin/customParseFormat.test.js +++ b/test/plugin/customParseFormat.test.js @@ -248,3 +248,22 @@ describe('Strict mode', () => { expect(dayjs(input, format, 'zh-cn', true).isValid()).toBe(false) }) }) + +describe('Array format support', () => { + it('second ok', () => { + const input = '2012-05-28' + const format = ['YYYY', 'YYYY-MM-DD'] + expect(dayjs(input, format).isValid()).toBe(true) + expect(dayjs(input, format, true).format('YYYY-MM-DD')).toBe('2012-05-28') + }) + it('all invalid', () => { + const input = '2012-05-28' + const format = ['DD', 'MM-DD'] + expect(dayjs(input, format, true).isValid()).toBe(false) + }) + it('with locale', () => { + const input = '2018 三月 12' + const format = ['YYYY', 'MM', 'YYYY MMMM DD'] + expect(dayjs(input, format, 'zh-cn', true).format('YYYY MMMM DD')).toBe(input) + }) +}) From bf347c36e401f50727fb5afcc537497b54b90d6b Mon Sep 17 00:00:00 2001 From: iamkun Date: Thu, 14 May 2020 15:40:42 +0800 Subject: [PATCH 6/7] fix: Fix locale month function bug (#908) --- src/index.js | 2 +- src/locale/ru.js | 31 ++++++++++++++++----------- src/plugin/customParseFormat/index.js | 22 ++++++++++++------- src/plugin/localeData/index.js | 10 ++++----- test/locale/keys.test.js | 4 ++++ test/plugin/customParseFormat.test.js | 13 +++++++++++ test/plugin/localeData.test.js | 12 +++++++++++ 7 files changed, 68 insertions(+), 26 deletions(-) diff --git a/src/index.js b/src/index.js index ebfad144c..001f9ecca 100644 --- a/src/index.js +++ b/src/index.js @@ -305,7 +305,7 @@ class Dayjs { M: $M + 1, MM: Utils.s($M + 1, 2, '0'), MMM: getShort(locale.monthsShort, $M, months, 3), - MMMM: months[$M] || months(this, str), + MMMM: getShort(months, $M), D: this.$D, DD: Utils.s(this.$D, 2, '0'), d: String(this.$W), diff --git a/src/locale/ru.js b/src/locale/ru.js index 8a6533b64..225cd69bf 100644 --- a/src/locale/ru.js +++ b/src/locale/ru.js @@ -27,24 +27,31 @@ function relativeTimeWithPlural(number, withoutSuffix, key) { return `${number} ${plural(format[key], +number)}` } +const months = (dayjsInstance, format) => { + if (MONTHS_IN_FORMAT.test(format)) { + return monthFormat[dayjsInstance.month()] + } + return monthStandalone[dayjsInstance.month()] +} +months.s = monthStandalone +months.f = monthFormat + +const monthsShort = (dayjsInstance, format) => { + if (MONTHS_IN_FORMAT.test(format)) { + return monthShortFormat[dayjsInstance.month()] + } + return monthShortStandalone[dayjsInstance.month()] +} +monthsShort.s = monthShortStandalone +monthsShort.f = monthShortFormat const locale = { name: 'ru', weekdays: 'воскресенье_понедельник_вторник_среда_четверг_пятница_суббота'.split('_'), weekdaysShort: 'вск_пнд_втр_срд_чтв_птн_сбт'.split('_'), weekdaysMin: 'вс_пн_вт_ср_чт_пт_сб'.split('_'), - months: (dayjsInstance, format) => { - if (MONTHS_IN_FORMAT.test(format)) { - return monthFormat[dayjsInstance.month()] - } - return monthStandalone[dayjsInstance.month()] - }, - monthsShort: (dayjsInstance, format) => { - if (MONTHS_IN_FORMAT.test(format)) { - return monthShortFormat[dayjsInstance.month()] - } - return monthShortStandalone[dayjsInstance.month()] - }, + months, + monthsShort, weekStart: 1, formats: { LT: 'H:mm', diff --git a/src/plugin/customParseFormat/index.js b/src/plugin/customParseFormat/index.js index 5077a14b4..b8426e7dd 100644 --- a/src/plugin/customParseFormat/index.js +++ b/src/plugin/customParseFormat/index.js @@ -9,7 +9,7 @@ const matchUpperCaseAMPM = /[AP]M/ const matchLowerCaseAMPM = /[ap]m/ const matchSigned = /[+-]?\d+/ // -inf - inf const matchOffset = /[+-]\d\d:?\d\d/ // +00:00 -00:00 +0000 or -0000 -const matchWord = /\d*[^\s\d-:/.()]+/ // Word +const matchWord = /\d*[^\s\d-:/()]+/ // Word let locale @@ -30,6 +30,13 @@ const zoneExpressions = [matchOffset, function (input) { zone.offset = offsetFromString(input) }] +const getLocalePart = (name) => { + const part = locale[name] + return part && ( + part.indexOf ? part : part.s.concat(part.f) + ) +} + const expressions = { A: [matchUpperCaseAMPM, function (input) { this.afternoon = input === 'PM' @@ -69,22 +76,21 @@ const expressions = { M: [match1to2, addInput('month')], MM: [match2, addInput('month')], MMM: [matchWord, function (input) { - const { months, monthsShort } = locale - const matchIndex = monthsShort - ? monthsShort.findIndex(month => month === input) - : months.findIndex(month => month.substr(0, 3) === input) + const months = getLocalePart('months') + const monthsShort = getLocalePart('monthsShort') + const matchIndex = (monthsShort || months.map(_ => _.substr(0, 3))).indexOf(input) if (matchIndex < 0) { throw new Error() } - this.month = matchIndex + 1 + this.month = (matchIndex + 1) % 12 }], MMMM: [matchWord, function (input) { - const { months } = locale + const months = getLocalePart('months') const matchIndex = months.indexOf(input) if (matchIndex < 0) { throw new Error() } - this.month = matchIndex + 1 + this.month = (matchIndex + 1) % 12 }], Y: [matchSigned, addInput('year')], YY: [match2, function (input) { diff --git a/src/plugin/localeData/index.js b/src/plugin/localeData/index.js index b6da1ca78..f478d5a41 100644 --- a/src/plugin/localeData/index.js +++ b/src/plugin/localeData/index.js @@ -1,11 +1,11 @@ export default (o, c, dayjs) => { // locale needed later const proto = c.prototype + const getLocalePart = part => (part && (part.indexOf ? part : part.s)) const getShort = (ins, target, full, num) => { const locale = ins.name ? ins : ins.$locale() - if (!locale[target]) { - return locale[full].map(f => f.substr(0, num)) - } - return locale[target] + const targetLocale = getLocalePart(locale[target]) + const fullLocale = getLocalePart(locale[full]) + return targetLocale || fullLocale.map(f => f.substr(0, num)) } const getDayjsLocaleObject = () => dayjs.Ls[dayjs.locale()] const localeData = function () { @@ -38,7 +38,7 @@ export default (o, c, dayjs) => { // locale needed later } } - dayjs.months = () => getDayjsLocaleObject().months + dayjs.months = () => getShort(getDayjsLocaleObject(), 'months') dayjs.monthsShort = () => getShort(getDayjsLocaleObject(), 'monthsShort', 'months', 3) diff --git a/test/locale/keys.test.js b/test/locale/keys.test.js index 5def0014e..876d6b338 100644 --- a/test/locale/keys.test.js +++ b/test/locale/keys.test.js @@ -45,6 +45,8 @@ Locale.forEach((locale) => { expect(months).toEqual(expect.any(Array)) } else { expect(months(dayjs(), 'str')).toEqual(expect.any(String)) + expect(months.f).toEqual(expect.any(Array)) + expect(months.s).toEqual(expect.any(Array)) } // monthsShort could be a function or array if (monthsShort) { @@ -52,6 +54,8 @@ Locale.forEach((locale) => { expect(monthsShort).toEqual(expect.any(Array)) } else { expect(monthsShort(dayjs(), 'str')).toEqual(expect.any(String)) + expect(monthsShort.f).toEqual(expect.any(Array)) + expect(monthsShort.s).toEqual(expect.any(Array)) } } // function pass date return string or number or null diff --git a/test/plugin/customParseFormat.test.js b/test/plugin/customParseFormat.test.js index a326c688c..b031e8885 100644 --- a/test/plugin/customParseFormat.test.js +++ b/test/plugin/customParseFormat.test.js @@ -4,6 +4,7 @@ import dayjs from '../../src' import customParseFormat from '../../src/plugin/customParseFormat' import uk from '../../src/locale/uk' import '../../src/locale/zh-cn' +import '../../src/locale/ru' dayjs.extend(customParseFormat) @@ -233,6 +234,18 @@ it('correctly parse ordinal', () => { .toBe(momentCN.locale()) }) +describe('month function locale', () => { + it('MMMM', () => { + const input = '08 мая 2020' + const format = 'DD MMMM YYYY' + expect(dayjs(input, format, 'ru').valueOf()).toBe(moment(input, format, 'ru').valueOf()) + }) + it('MMM', () => { + const input = '08 февр. 2020' + const format = 'DD MMM YYYY' + expect(dayjs(input, format, 'ru').valueOf()).toBe(moment(input, format, 'ru').valueOf()) + }) +}) describe('Strict mode', () => { it('without locale', () => { diff --git a/test/plugin/localeData.test.js b/test/plugin/localeData.test.js index 288c133fd..6dac0a97a 100644 --- a/test/plugin/localeData.test.js +++ b/test/plugin/localeData.test.js @@ -5,6 +5,7 @@ import localeData from '../../src/plugin/localeData' import localizedFormat from '../../src/plugin/localizedFormat' import '../../src/locale/fr' import '../../src/locale/zh-cn' +import '../../src/locale/ru' dayjs.extend(localizedFormat) dayjs.extend(localeData) @@ -65,3 +66,14 @@ it('Listing the months and weekdays', () => { expect(dayjs.weekdaysMin()).toEqual(moment.weekdaysMin()) }) }) + +it('Month function', () => { + const dayjsLocaleData = dayjs().locale('ru').localeData() + const momentLocaleData = moment().locale('ru').localeData() + expect(dayjsLocaleData.months()).toEqual(momentLocaleData.months()) + expect(dayjsLocaleData.monthsShort()).toEqual(momentLocaleData.monthsShort()) + dayjs.locale('ru') + moment.locale('ru') + expect(dayjs.months()).toEqual(moment.months()) + expect(dayjs.monthsShort()).toEqual(moment.monthsShort()) +}) From fba621d78461f967d46e752343441e284942f7f8 Mon Sep 17 00:00:00 2001 From: iamkun Date: Thu, 14 May 2020 15:42:42 +0800 Subject: [PATCH 7/7] test: Add customParseFormat plugin month function locale test --- test/plugin/customParseFormat.test.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/plugin/customParseFormat.test.js b/test/plugin/customParseFormat.test.js index b031e8885..2f315063c 100644 --- a/test/plugin/customParseFormat.test.js +++ b/test/plugin/customParseFormat.test.js @@ -237,8 +237,10 @@ it('correctly parse ordinal', () => { describe('month function locale', () => { it('MMMM', () => { const input = '08 мая 2020' + const input2 = '08 май 2020' const format = 'DD MMMM YYYY' expect(dayjs(input, format, 'ru').valueOf()).toBe(moment(input, format, 'ru').valueOf()) + expect(dayjs(input2, format, 'ru').valueOf()).toBe(moment(input2, format, 'ru').valueOf()) }) it('MMM', () => { const input = '08 февр. 2020'