From bf347c36e401f50727fb5afcc537497b54b90d6b Mon Sep 17 00:00:00 2001 From: iamkun Date: Thu, 14 May 2020 15:40:42 +0800 Subject: [PATCH] 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()) +})