Skip to content

Commit b4f310c

Browse files
Merge pull request #1299 from iamkun/dev
D2M
2 parents 601eb7f + 0e51f41 commit b4f310c

File tree

14 files changed

+431
-10
lines changed

14 files changed

+431
-10
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ English | [简体中文](./docs/zh-cn/README.zh-CN.md) | [日本語](./docs/ja/R
55
alt="Day.js"></a></p>
66
<p align="center">Fast <b>2kB</b> alternative to Moment.js with the same modern API</p>
77
<p align="center">
8-
<a href="https://www.duohui.cn?utm_source=dayjs" title="多会 - 专业活动管理系统" target="_blank"><img height="120px" alt="多会" src="https://user-images.githubusercontent.com/17680888/97983132-c433bd80-1e0f-11eb-8dde-9f216e05ee8a.png"/></a></p>
8+
<a href="https://www.duohui.cn?utm_source=dayjs" title="多会 - 专业活动管理系统" target="_blank"><img height="120px" width="120px" alt="多会" src="https://user-images.githubusercontent.com/17680888/97983132-c433bd80-1e0f-11eb-8dde-9f216e05ee8a.png"/></a></p>
99
<p align="center">
1010
<a href="https://unpkg.com/dayjs/dayjs.min.js"><img
1111
src="http://img.badgesize.io/https://unpkg.com/dayjs/dayjs.min.js?compression=gzip&style=flat-square"

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"description": "2KB immutable date time library alternative to Moment.js with the same modern API ",
55
"main": "dayjs.min.js",
66
"types": "index.d.ts",
7-
"module": "dayjs.min.js",
7+
"module": "esm/index.js",
88
"scripts": {
99
"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",
1010
"test-tz": "date && jest test/timezone.test --coverage=false",

src/constant.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,5 @@ export const FORMAT_DEFAULT = 'YYYY-MM-DDTHH:mm:ssZ'
2626
export const INVALID_DATE_STRING = 'Invalid Date'
2727

2828
// regex
29-
export const REGEX_PARSE = /^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[^0-9]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?.?(\d+)?$/
29+
export const REGEX_PARSE = /^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[^0-9]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?\.?(\d+)?$/
3030
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

src/locale/ar.js

+38
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,31 @@
22
import dayjs from 'dayjs'
33

44
const months = 'يناير_فبراير_مارس_أبريل_مايو_يونيو_يوليو_أغسطس_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split('_')
5+
const symbolMap = {
6+
1: '١',
7+
2: '٢',
8+
3: '٣',
9+
4: '٤',
10+
5: '٥',
11+
6: '٦',
12+
7: '٧',
13+
8: '٨',
14+
9: '٩',
15+
0: '٠'
16+
}
17+
18+
const numberMap = {
19+
'١': '1',
20+
'٢': '2',
21+
'٣': '3',
22+
'٤': '4',
23+
'٥': '5',
24+
'٦': '6',
25+
'٧': '7',
26+
'٨': '8',
27+
'٩': '9',
28+
'٠': '0'
29+
}
530

631
const locale = {
732
name: 'ar',
@@ -26,6 +51,19 @@ const locale = {
2651
y: 'عام واحد',
2752
yy: '%d أعوام'
2853
},
54+
preparse(string) {
55+
return string
56+
.replace(
57+
/[١٢٣٤٥٦٧٨٩٠]/g,
58+
match => numberMap[match]
59+
)
60+
.replace(/،/g, ',')
61+
},
62+
postformat(string) {
63+
return string
64+
.replace(/\d/g, match => symbolMap[match])
65+
.replace(/,/g, '،')
66+
},
2967
ordinal: n => n,
3068
formats: {
3169
LT: 'HH:mm',

src/plugin/localeData/index.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ export default (o, c, dayjs) => { // locale needed later
2929
weekdaysShort: instance =>
3030
(instance ? instance.format('ddd') : getShort(this, 'weekdaysShort', 'weekdays', 3)),
3131
longDateFormat: format => getLongDateFormat(this.$locale(), format),
32-
meridiem: this.$locale().meridiem
32+
meridiem: this.$locale().meridiem,
33+
ordinal: this.$locale().ordinal
3334
}
3435
}
3536
proto.localeData = function () {
@@ -46,7 +47,8 @@ export default (o, c, dayjs) => { // locale needed later
4647
months: () => dayjs.months(),
4748
monthsShort: () => dayjs.monthsShort(),
4849
longDateFormat: format => getLongDateFormat(localeObject, format),
49-
meridiem: localeObject.meridiem
50+
meridiem: localeObject.meridiem,
51+
ordinal: localeObject.ordinal
5052
}
5153
}
5254

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Plugin template from https://day.js.org/docs/en/plugin/plugin
2+
export default (option, dayjsClass) => {
3+
const oldParse = dayjsClass.prototype.parse
4+
dayjsClass.prototype.parse = function (cfg) {
5+
if (typeof cfg.date === 'string') {
6+
const locale = this.$locale()
7+
cfg.date =
8+
locale && locale.preparse ? locale.preparse(cfg.date) : cfg.date
9+
}
10+
// original parse result
11+
return oldParse.bind(this)(cfg)
12+
}
13+
14+
// // overriding existing API
15+
// // e.g. extend dayjs().format()
16+
const oldFormat = dayjsClass.prototype.format
17+
dayjsClass.prototype.format = function (...args) {
18+
// original format result
19+
const result = oldFormat.call(this, ...args)
20+
// return modified result
21+
const locale = this.$locale()
22+
return locale && locale.postformat ? locale.postformat(result) : result
23+
}
24+
25+
const oldFromTo = dayjsClass.prototype.fromToBase
26+
27+
if (oldFromTo) {
28+
dayjsClass.prototype.fromToBase = function (
29+
input,
30+
withoutSuffix,
31+
instance,
32+
isFrom
33+
) {
34+
const locale = this.$locale() || instance.$locale()
35+
36+
// original format result
37+
return oldFromTo.call(
38+
this,
39+
input,
40+
withoutSuffix,
41+
instance,
42+
isFrom,
43+
locale && locale.postformat
44+
)
45+
}
46+
}
47+
}

src/plugin/relativeTime/index.js

+10-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export default (o, c, d) => {
1919
yy: '%d years'
2020
}
2121
d.en.relativeTime = relObj
22-
const fromTo = (input, withoutSuffix, instance, isFrom) => {
22+
proto.fromToBase = (input, withoutSuffix, instance, isFrom, postFormat) => {
2323
const loc = instance.$locale().relativeTime || relObj
2424
const T = o.thresholds || [
2525
{ l: 's', r: 44, d: C.S },
@@ -46,11 +46,14 @@ export default (o, c, d) => {
4646
? d(input).diff(instance, t.d, true)
4747
: instance.diff(input, t.d, true)
4848
}
49-
const abs = (o.rounding || Math.round)(Math.abs(result))
49+
let abs = (o.rounding || Math.round)(Math.abs(result))
5050
isFuture = result > 0
5151
if (abs <= t.r || !t.r) {
5252
if (abs <= 1 && i > 0) t = T[i - 1] // 1 minutes -> a minute, 0 seconds -> 0 second
5353
const format = loc[t.l]
54+
if (postFormat) {
55+
abs = postFormat(`${abs}`)
56+
}
5457
if (typeof format === 'string') {
5558
out = format.replace('%d', abs)
5659
} else {
@@ -66,6 +69,11 @@ export default (o, c, d) => {
6669
}
6770
return pastOrFuture.replace('%s', out)
6871
}
72+
73+
function fromTo(input, withoutSuffix, instance, isFrom) {
74+
return proto.fromToBase(input, withoutSuffix, instance, isFrom)
75+
}
76+
6977
proto.to = function (input, withoutSuffix) {
7078
return fromTo(input, withoutSuffix, this, true)
7179
}

test/locale/ar.test.js

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import moment from 'moment'
2+
import MockDate from 'mockdate'
3+
import dayjs from '../../src'
4+
import relativeTime from '../../src/plugin/relativeTime'
5+
import preParsePostFormat from '../../src/plugin/preParsePostFormat'
6+
import localeData from '../../src/plugin/localeData'
7+
import '../../src/locale/ar'
8+
9+
dayjs.extend(localeData)
10+
dayjs.extend(relativeTime)
11+
dayjs.extend(preParsePostFormat)
12+
13+
beforeEach(() => {
14+
MockDate.set(new Date())
15+
})
16+
17+
afterEach(() => {
18+
MockDate.reset()
19+
})
20+
21+
it('Format Month with locale function', () => {
22+
for (let i = 0; i <= 7; i += 1) {
23+
const dayjsAR = dayjs().locale('ar').add(i, 'day')
24+
const momentAR = moment().locale('ar').add(i, 'day')
25+
const testFormat1 = 'DD MMMM YYYY MMM'
26+
const testFormat2 = 'MMMM'
27+
const testFormat3 = 'MMM'
28+
expect(dayjsAR.format(testFormat1)).toEqual(momentAR.format(testFormat1))
29+
expect(dayjsAR.format(testFormat2)).toEqual(momentAR.format(testFormat2))
30+
expect(dayjsAR.format(testFormat3)).toEqual(momentAR.format(testFormat3))
31+
}
32+
})
33+
34+
it('Preparse with locale function', () => {
35+
for (let i = 0; i <= 7; i += 1) {
36+
dayjs.locale('ar')
37+
const momentAR = moment().locale('ar').add(i, 'day')
38+
expect(dayjs(momentAR.format()).format()).toEqual(momentAR.format())
39+
}
40+
})
41+
42+
it('RelativeTime: Time from X gets formatted', () => {
43+
const T = [
44+
[44.4, 'second', 'منذ ثانية واحدة']
45+
]
46+
47+
T.forEach((t) => {
48+
dayjs.locale('ar')
49+
expect(dayjs().from(dayjs().add(t[0], t[1])))
50+
.toBe(t[2])
51+
})
52+
})

test/locale/ja.test.js

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import MockDate from 'mockdate'
2+
import moment from 'moment'
3+
import dayjs from '../../src'
4+
import relativeTime from '../../src/plugin/relativeTime'
5+
import '../../src/locale/ja'
6+
7+
dayjs.extend(relativeTime)
8+
9+
beforeEach(() => {
10+
MockDate.set(new Date())
11+
})
12+
13+
afterEach(() => {
14+
MockDate.reset()
15+
})
16+
17+
it('Finnish locale relative time in past and future', () => {
18+
const cases = [
19+
[1, 'd', '1日後'],
20+
[-1, 'd', '1日前'],
21+
[2, 'd', '2日後'],
22+
[-2, 'd', '2日前'],
23+
[10, 'd', '10日後'],
24+
[-10, 'd', '10日前'],
25+
[6, 'm', '6分後'],
26+
[-6, 'm', '6分前'],
27+
[5, 'h', '5時間後'],
28+
[-5, 'h', '5時間前'],
29+
[3, 'M', '3ヶ月後'],
30+
[-3, 'M', '3ヶ月前'],
31+
[4, 'y', '4年後'],
32+
[-4, 'y', '4年前']
33+
]
34+
cases.forEach((c) => {
35+
expect(dayjs().add(c[0], c[1]).locale('ja').fromNow())
36+
.toBe(c[2])
37+
expect(dayjs().add(c[0], c[1]).locale('ja').fromNow())
38+
.toBe(moment().add(c[0], c[1]).locale('ja').fromNow())
39+
})
40+
expect(dayjs().add(-10, 'd').locale('ja').fromNow(true))
41+
.toBe('10日')
42+
expect(dayjs().add(-10, 'd').locale('ja').fromNow(true))
43+
.toBe(moment().add(-10, 'd').locale('ja').fromNow(true))
44+
})
45+

test/parse.test.js

+45
Original file line numberDiff line numberDiff line change
@@ -148,4 +148,49 @@ describe('REGEX_PARSE', () => {
148148
expect(dayjs(date).valueOf()).toBe(moment(date).valueOf())
149149
expect(d.join('-')).toBe('2019-03-25T06:41:00.999999999-2019-03-25-06-41-00-999999999')
150150
})
151+
it('20210102T012345', () => {
152+
const date = '20210102T012345'
153+
const d = date.match(REGEX_PARSE)
154+
expect(dayjs(date).valueOf()).toBe(moment(date).valueOf())
155+
expect(d.join('-')).toBe('20210102T012345-2021-01-02-01-23-45-')
156+
})
157+
it('2021-01-02T01:23', () => {
158+
const date = '2021-01-02T01:23'
159+
const d = date.match(REGEX_PARSE)
160+
expect(dayjs(date).valueOf()).toBe(moment(date).valueOf())
161+
expect(d.join('-')).toBe('2021-01-02T01:23-2021-01-02-01-23--')
162+
})
163+
it('2021-01-02T01:23:45', () => {
164+
const date = '2021-01-02T01:23:45'
165+
const d = date.match(REGEX_PARSE)
166+
expect(dayjs(date).valueOf()).toBe(moment(date).valueOf())
167+
expect(d.join('-')).toBe('2021-01-02T01:23:45-2021-01-02-01-23-45-')
168+
})
169+
170+
it('2020-12-31T18:00:00.000-0500 (no regex match)', () => {
171+
const date = '2020-12-31T18:00:00.000-0500'
172+
const d = date.match(REGEX_PARSE)
173+
expect(dayjs(date).valueOf()).toBe(moment(date).valueOf())
174+
expect(d).toBe(null)
175+
})
176+
177+
it('2020-12-31T18:00:00-05:00 (no regex match)', () => {
178+
const date = '2020-12-31T18:00:00-05:00'
179+
const d = date.match(REGEX_PARSE)
180+
expect(dayjs(date).valueOf()).toBe(moment(date).valueOf())
181+
expect(d).toBe(null)
182+
})
183+
184+
it('2021-01-02T01:23:45-0500 (no regex match)', () => {
185+
const date = '2021-01-02T01:23:45-0500'
186+
const d = date.match(REGEX_PARSE)
187+
expect(dayjs(date).valueOf()).toBe(moment(date).valueOf())
188+
expect(d).toBe(null)
189+
})
190+
it('2021-01-02T01:23:45Z (no regex match)', () => {
191+
const date = '2021-01-02T01:23:45Z'
192+
const d = date.match(REGEX_PARSE)
193+
expect(dayjs(date).valueOf()).toBe(moment(date).valueOf())
194+
expect(d).toBe(null)
195+
})
151196
})

test/plugin/localeData.test.js

+7
Original file line numberDiff line numberDiff line change
@@ -110,3 +110,10 @@ it('meridiem', () => {
110110
expect(typeof dayjs().localeData().meridiem).toEqual('function')
111111
dayjs.locale('en')
112112
})
113+
114+
it('ordinal', () => {
115+
dayjs.locale('zh-cn')
116+
expect(typeof dayjs.localeData().ordinal).toEqual('function')
117+
expect(typeof dayjs().localeData().ordinal).toEqual('function')
118+
dayjs.locale('en')
119+
})

0 commit comments

Comments
 (0)