Skip to content

Commit

Permalink
Merge pull request #1568 from iamkun/dev
Browse files Browse the repository at this point in the history
D2M
  • Loading branch information
iamkun committed Jul 6, 2021
2 parents aa5b524 + eb087f5 commit ae87b5d
Show file tree
Hide file tree
Showing 19 changed files with 287 additions and 28 deletions.
5 changes: 4 additions & 1 deletion docs/en/Plugin.md
Expand Up @@ -87,13 +87,16 @@ dayjs
.local()
.format() //2019-03-06T17:11:55+08:00
dayjs.utc('2018-01-01', 'YYYY-MM-DD') // with CustomParseFormat plugin
dayjs.utc('2018-01-01', 'YYYY-MM-DD', true) // with CustomParseFormat plugin & Using strict parsing
```

By default, Day.js parses and displays in local time.

If you want to parse or display in UTC, you can use `dayjs.utc()` instead of `dayjs()`.

#### dayjs.utc `dayjs.utc(dateType?: string | number | Date | Dayjs, format? string)`
You may specify a boolean for the last argument to use `strict parsing`. Strict parsing requires that the format and input match exactly, including delimiters.

#### dayjs.utc `dayjs.utc(dateType?: string | number | Date | Dayjs, format? string, strict?: boolean)`

Returns a `Dayjs` object in UTC mode.

Expand Down
19 changes: 19 additions & 0 deletions docs/ru/LICENSE-ru
@@ -0,0 +1,19 @@
Лицензия MIT

Авторское право (c) с 2018 года по настоящее время, iamkun

Данная лицензия разрешает лицам, получившим копию
данного программного обеспечения и сопутствующей документации (в дальнейшем именуемыми «Программное обеспечение»), безвозмездно
использовать Программное обеспечение без ограничений, включая неограниченное право
на использование, копирование, изменение, слияние, публикацию, распространение, сублицензирование и/или продажу
копий Программного обеспечения, а также лицам, которым предоставляется данное Программное обеспечение,
при соблюдении следующих условий:

Указанное выше уведомление об авторском праве и данные условия должны быть включены во все
копии или значимые части данного Программного обеспечения.

ДАННОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ПРЕДОСТАВЛЯЕТСЯ «КАК ЕСТЬ», БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ, ЯВНО ВЫРАЖЕННЫХ ИЛИ
ПОДРАЗУМЕВАЕМЫХ, ВКЛЮЧАЯ ГАРАНТИИ ТОВАРНОЙ ПРИГОДНОСТИ, СООТВЕТСТВИЯ ПО ЕГО КОНКРЕТНОМУ НАЗНАЧЕНИЮ
И ОТСУТСТВИЯ НАРУШЕНИЙ, НО НЕ ОГРАНИЧИВАЯСЬ ИМИ. НИ В КАКОМ СЛУЧАЕ АВТОРЫ ИЛИ ПРАВООБЛАДАТЕЛИ НЕ НЕСУТ ОТВЕТСТВЕННОСТИ
ПО КАКИМ-ЛИБО ИСКАМ, ЗА УЩЕРБ ИЛИ ПО ИНЫМ ТРЕБОВАНИЯМ, В ТОМ ЧИСЛЕ, ПРИ ДЕЙСТВИИ КОНТРАКТА, ДЕЛИКТЕ ИЛИ ИНОЙ СИТУАЦИИ,
ВОЗНИКШИМ ИЗ-ЗА ИСПОЛЬЗОВАНИЯ ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ ИЛИ ИНЫХ ДЕЙСТВИЙ С ПРОГРАММНЫМ ОБЕСПЕЧЕНИЕМ.
16 changes: 8 additions & 8 deletions docs/ru/README-ru.md
Expand Up @@ -48,11 +48,11 @@ dayjs().startOf('month').add(1, 'day').set('year', 2018).format('YYYY-MM-DD HH:m
npm install dayjs --save
```

📚[Инструкция по установке](https://day.js.org/docs/en/installation/installation)
📚[Инструкция по установке](https://day.js.org/docs/ru/installation/installation)

### API

API Day.js легко использовать для парсинга, валидации, управления, и отображения дат и времен.
API Day.js легко использовать для парсинга, валидации, управления, и отображения дат и времени.

```javascript
dayjs('2018-08-08') // парсинг
Expand All @@ -66,21 +66,21 @@ dayjs().add(1, 'year') // управление
dayjs().isBefore(dayjs()) // осведомление
```

📚[Ссылка на API](https://day.js.org/docs/en/parse/parse)
📚[Ссылка на API](https://day.js.org/docs/ru/parse/parse)

### I18n

Day.js обладает великолепной поддержкой интернационализации.

Но ни одна из локализаций не будет включена в вашу сборку до тех пор, пока вы не начнете ее использовать.
Но ни одна из локализаций не будет включена в вашу сборку до тех пор, пока вы не начнёте её использовать.
```javascript
import 'dayjs/locale/es' // загрузка по требованию

dayjs.locale('es') // глобальное использование Испанской локали

dayjs('2018-05-05').locale('zh-cn').format() // использование упрощенной Китайской локали в конкретном случае
dayjs('2018-05-05').locale('zh-cn').format() // использование упрощённой Китайской локали в конкретном случае
```
📚[Интернационализация](https://day.js.org/docs/en/i18n/i18n)
📚[Интернационализация](https://day.js.org/docs/ru/i18n/i18n)

### Плагин

Expand All @@ -94,7 +94,7 @@ dayjs.extend(advancedFormat) // использование плагина
dayjs().format('Q Do k kk X x') // больше доступных форматов
```

📚[Список плагинов](https://day.js.org/docs/en/plugin/plugin)
📚[Список плагинов](https://day.js.org/docs/ru/plugin/plugin)

## Спонсоры

Expand All @@ -121,4 +121,4 @@ dayjs().format('Q Do k kk X x') // больше доступных формат

## Лицензия

Day.js распространяется под [лицензией MIT](./LICENSE).
Day.js распространяется под [лицензией MIT](./LICENSE-ru).
2 changes: 1 addition & 1 deletion src/constant.js
Expand Up @@ -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})[Tt\s]*(\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
5 changes: 3 additions & 2 deletions src/index.js
Expand Up @@ -251,11 +251,12 @@ class Dayjs {
}

format(formatStr) {
if (!this.isValid()) return C.INVALID_DATE_STRING
const locale = this.$locale()

if (!this.isValid()) return locale.invalidDate || C.INVALID_DATE_STRING

const str = formatStr || C.FORMAT_DEFAULT
const zoneStr = Utils.z(this)
const locale = this.$locale()
const { $H, $m, $M } = this
const {
weekdays, months, meridiem
Expand Down
26 changes: 21 additions & 5 deletions src/locale/bg.js
Expand Up @@ -3,13 +3,29 @@ import dayjs from 'dayjs'

const locale = {
name: 'bg',
weekdays: 'Неделя_Понеделник_Вторник_Сряда_Четвъртък_Петък_Събота'.split('_'),
weekdays: 'неделя_понеделник_вторник_сряда_четвъртък_петък_събота'.split('_'),
weekdaysShort: 'нед_пон_вто_сря_чет_пет_съб'.split('_'),
weekdaysMin: 'нд_пн_вт_ср_чт_пт_сб'.split('_'),
months: 'Януари_Февруари_Март_Април_Май_Юни_Юли_Август_Септември_Октомври_Ноември_Декември'.split('_'),
monthsShort: 'Янр_Фев_Мар_Апр_Май_Юни_Юли_Авг_Сеп_Окт_Ное_Дек'.split('_'),
months: 'януари_февруари_март_април_май_юни_юли_август_септември_октомври_ноември_декември'.split('_'),
monthsShort: 'янр_фев_мар_апр_май_юни_юли_авг_сеп_окт_ное_дек'.split('_'),
weekStart: 1,
ordinal: n => `${n}.`,
ordinal: (n) => {
const last2Digits = n % 100
if (last2Digits > 10 && last2Digits < 20) {
return `${n}-ти`
}

const lastDigit = n % 10
if (lastDigit === 1) {
return `${n}-ви`
} else if (lastDigit === 2) {
return `${n}-ри`
} else if (lastDigit === 7 || lastDigit === 8) {
return `${n}-ми`
}

return `${n}-ти`
},
formats: {
LT: 'H:mm',
LTS: 'H:mm:ss',
Expand All @@ -27,7 +43,7 @@ const locale = {
h: 'час',
hh: '%d часа',
d: 'ден',
dd: '%d дни',
dd: '%d дена',
M: 'месец',
MM: '%d месеца',
y: 'година',
Expand Down
50 changes: 50 additions & 0 deletions src/locale/sv-fi.js
@@ -0,0 +1,50 @@
// Finland Swedish [sv-fi]
import dayjs from 'dayjs'

const locale = {
name: 'sv-fi',
weekdays: 'söndag_måndag_tisdag_onsdag_torsdag_fredag_lördag'.split('_'),
weekdaysShort: 'sön_mån_tis_ons_tor_fre_lör'.split('_'),
weekdaysMin: 'sö_må_ti_on_to_fr_lö'.split('_'),
months: 'januari_februari_mars_april_maj_juni_juli_augusti_september_oktober_november_december'.split('_'),
monthsShort: 'jan_feb_mar_apr_maj_jun_jul_aug_sep_okt_nov_dec'.split('_'),
weekStart: 1,
yearStart: 4,
ordinal: (n) => {
const b = n % 10
const o = (b === 1) || (b === 2) ? 'a' : 'e'
return `[${n}${o}]`
},
formats: {
LT: 'HH.mm',
LTS: 'HH.mm.ss',
L: 'DD.MM.YYYY',
LL: 'D. MMMM YYYY',
LLL: 'D. MMMM YYYY, [kl.] HH.mm',
LLLL: 'dddd, D. MMMM YYYY, [kl.] HH.mm',
l: 'D.M.YYYY',
ll: 'D. MMM YYYY',
lll: 'D. MMM YYYY, [kl.] HH.mm',
llll: 'ddd, D. MMM YYYY, [kl.] HH.mm'
},
relativeTime: {
future: 'om %s',
past: 'för %s sedan',
s: 'några sekunder',
m: 'en minut',
mm: '%d minuter',
h: 'en timme',
hh: '%d timmar',
d: 'en dag',
dd: '%d dagar',
M: 'en månad',
MM: '%d månader',
y: 'ett år',
yy: '%d år'
}
}

dayjs.locale(locale, null, true)

export default locale

12 changes: 10 additions & 2 deletions src/plugin/customParseFormat/index.js
Expand Up @@ -13,6 +13,11 @@ const matchWord = /\d*[^\s\d-_:/()]+/ // Word

let locale = {}

let parseTwoDigitYear = function (input) {
input = +input
return input + (input > 68 ? 1900 : 2000)
}

function offsetFromString(string) {
if (!string) return 0
if (string === 'Z') return 0
Expand Down Expand Up @@ -111,8 +116,7 @@ const expressions = {
}],
Y: [matchSigned, addInput('year')],
YY: [match2, function (input) {
input = +input
this.year = input + (input > 68 ? 1900 : 2000)
this.year = parseTwoDigitYear(input)
}],
YYYY: [match4, addInput('year')],
Z: zoneExpressions,
Expand Down Expand Up @@ -171,6 +175,7 @@ function makeParser(format) {

const parseFormattedInput = (input, format, utc) => {
try {
if (['x', 'X'].indexOf(format) > -1) return new Date((format === 'X' ? 1000 : 1) * input)
const parser = makeParser(format)
const {
year, month, day, hours, minutes, seconds, milliseconds, zone
Expand Down Expand Up @@ -201,6 +206,9 @@ const parseFormattedInput = (input, format, utc) => {

export default (o, C, d) => {
d.p.customParseFormat = true
if (o && o.parseTwoDigitYear) {
({ parseTwoDigitYear } = o)
}
const proto = C.prototype
const oldParse = proto.parse
proto.parse = function (cfg) {
Expand Down
5 changes: 3 additions & 2 deletions src/plugin/dayOfYear/index.js
@@ -1,7 +1,8 @@
export default (o, c) => {
export default (o, c, d) => {
const proto = c.prototype
proto.dayOfYear = function (input) {
const dayOfYear = Math.round((this.startOf('day') - this.startOf('year')) / 864e5) + 1
// d(this) is for badMutable
const dayOfYear = Math.round((d(this).startOf('day') - d(this).startOf('year')) / 864e5) + 1
return input == null ? dayOfYear : this.add(input - dayOfYear, 'day')
}
}
67 changes: 67 additions & 0 deletions test/locale/bg.test.js
@@ -0,0 +1,67 @@
import moment from 'moment'
import MockDate from 'mockdate'
import dayjs from '../../src'
import relativeTime from '../../src/plugin/relativeTime'
import advancedFormat from '../../src/plugin/advancedFormat'
import '../../src/locale/bg'

dayjs.extend(relativeTime)
dayjs.extend(advancedFormat)

beforeEach(() => {
MockDate.set(new Date())
})

afterEach(() => {
MockDate.reset()
})

it('Format Month with locale function', () => {
for (let i = 0; i <= 7; i += 1) {
const dayjsBG = dayjs().locale('bg').add(i, 'day')
const momentBG = moment().locale('bg').add(i, 'day')
const testFormat1 = 'DD MMMM YYYY MMM'
const testFormat2 = 'MMMM'
const testFormat3 = 'MMM'
expect(dayjsBG.format(testFormat1)).toEqual(momentBG.format(testFormat1))
expect(dayjsBG.format(testFormat2)).toEqual(momentBG.format(testFormat2))
expect(dayjsBG.format(testFormat3)).toEqual(momentBG.format(testFormat3))
}
})

it('RelativeTime: Time from X', () => {
const T = [
[44.4, 'second'], // a few seconds
[89.5, 'second'], // a minute
[130, 'second'], // two minutes
[43, 'minute'], // 44 minutes
[1, 'hour'], // 1 hour
[21, 'hour'], // 21 hours
[2, 'day'], // 2 days
[25, 'day'], // 25 days
[2, 'month'], // 2 months
[10, 'month'], // 10 months
[18, 'month'], // 2 years
[15, 'year'] // 15 years
]

T.forEach((t) => {
dayjs.locale('bg')
moment.locale('bg')
expect(dayjs().from(dayjs().add(t[0], t[1])))
.toBe(moment().from(moment().add(t[0], t[1])))
expect(dayjs().from(dayjs().add(t[0], t[1]), true))
.toBe(moment().from(moment().add(t[0], t[1]), true))
})
})

it('Ordinal', () => {
dayjs.locale('bg')
moment.locale('bg')

for (let d = 1; d <= 31; d += 1) {
const day = d < 10 ? `0${d}` : d
const date = `2021-01-${day}`
expect(dayjs(date).format('Do')).toBe(moment(date).format('Do'))
}
})
35 changes: 35 additions & 0 deletions test/locale/sv-fi.test.js
@@ -0,0 +1,35 @@
import dayjs from '../../src'
import localizedFormat from '../../src/plugin/localizedFormat'
import '../../src/locale/sv-fi'

dayjs.extend(localizedFormat)

it('Finland Swedish locale', () => {
// time
expect(dayjs('2019-02-01 12:34:56').locale('sv-fi').format('LT'))
.toBe('12.34')
expect(dayjs('2019-02-01 23:45:56').locale('sv-fi').format('LTS'))
.toBe('23.45.56')

// date
expect(dayjs('2019-02-01').locale('sv-fi').format('L'))
.toBe('01.02.2019')
expect(dayjs('2019-12-15').locale('sv-fi').format('LL'))
.toBe('15. december 2019')
// short
expect(dayjs('2019-02-01').locale('sv-fi').format('l'))
.toBe('1.2.2019')
expect(dayjs('2019-12-15').locale('sv-fi').format('ll'))
.toBe('15. dec 2019')

// date and time
expect(dayjs('2019-03-01 12:30').locale('sv-fi').format('LLL'))
.toBe('1. mars 2019, kl. 12.30')
expect(dayjs('2021-06-12 17:30').locale('sv-fi').format('LLLL'))
.toBe('lördag, 12. juni 2021, kl. 17.30')
// short
expect(dayjs('2019-03-01 12:30').locale('sv-fi').format('lll'))
.toBe('1. mar 2019, kl. 12.30')
expect(dayjs('2021-06-01 17:30').locale('sv-fi').format('llll'))
.toBe('tis, 1. jun 2021, kl. 17.30')
})
13 changes: 12 additions & 1 deletion test/parse.test.js
Expand Up @@ -89,11 +89,14 @@ describe('Parse', () => {
expect(ds.millisecond()).toEqual(ms.millisecond())
})

it('String Other, Null and isValid', () => {
it('String Other, Undefined and Null and isValid', () => {
global.console.warn = jest.genMockFunction()// moment.js otherString will throw warn
expect(dayjs('otherString').toString().toLowerCase()).toBe(moment('otherString').toString().toLowerCase())
expect(dayjs(undefined).toDate()).toEqual(moment(undefined).toDate())
expect(dayjs().isValid()).toBe(true)
expect(dayjs(undefined).isValid()).toBe(true)
expect(dayjs('').isValid()).toBe(false)
expect(dayjs(null).isValid()).toBe(false)
expect(dayjs('otherString').isValid()).toBe(false)
expect(dayjs(null).toString().toLowerCase()).toBe(moment(null).toString().toLowerCase())
})
Expand Down Expand Up @@ -201,4 +204,12 @@ describe('REGEX_PARSE', () => {
expect(dayjs(date).valueOf()).toBe(moment(date).valueOf())
expect(d).toBe(null)
})

// dots should not be matched, and fallback to Date
it('2021.01.03', () => {
const date = '2021.01.03'
const d = date.match(REGEX_PARSE)
expect(dayjs(date).valueOf()).toBe(moment(date).valueOf())
expect(d).toBe(null)
})
})

0 comments on commit ae87b5d

Please sign in to comment.