之前在项目中使用 moment.js
的 format
来做日期格式化,效果是一样的,缺点是多引入了一个库徒增体积。昨天突然发现 Quasar
的日期工具类中可以实现相同的功能,所以做了一个替换,并且研究了一下它是如何实现这个功能的。附 Quasar
官方文档:日期实用程序(Date Utils)
这里是我们项目中使用日期工具库的代码片段:
1
2
3
4
5
6
7
8
9
10
11
12
import { date } from 'quasar'
const { formatDate } = date
/**
* Reference:http://www.quasarchs.com/quasar-utils/date-utils#%E6%98%BE%E7%A4%BA%E6%A0%BC%E5%BC%8F
* 传入时间戳,例如:1600054260793
* 转换为:yyyy-MM-DD-HH:mm:ss 格式,如:2020-09-14 11:53:13
*/
export function transferTimestampToDate (timestamp) {
let date = formatDate(timestamp, 'YYYY-MM-DD-HH:mm:ss')
return date
}
这是 node_modules/quasar/src/utils/date.js
文件内复制处理日期格式化的代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
export function formatDate (val, mask, dateLocale, __forcedYear) {
// 兼容性处理
if (
(val !== 0 && !val) ||
val === Infinity ||
val === -Infinity
) {
return
}
// 1、init
let date = new Date(val)
if (isNaN(date)) {
return
}
if (mask === void 0) {
mask = defaultMask
}
// 负责第三个参数,主要作用于 i18n 处理
const locale = dateLocale !== void 0
? dateLocale
: lang.props.date
// 2、对 mask 替换
// 该方法核心思想是利用 String.Property.replace 中可以循环匹配替换的特性,将我们传入的 format 例如:YYYY-MM-DD-HH:mm:ss,逐个替换为具体数据。
// 这里的 token = /\[((?:[^\]\\]|\\]|\\)*)\]|d{1,4}|M{1,4}|m{1,2}|w{1,2}|Qo|Do|D{1,4}|YY(?:YY)?|H{1,2}|h{1,2}|s{1,2}|S{1,3}|Z{1,2}|a{1,2}|[AQExX]/g
return mask.replace(
token,
(match, text) => match in formatter // 这里用的 in 的语法返回布尔类型,判断这个 value 或 index 是否存在于这个对象或数组中
? formatter[match](date, locale, __forcedYear) // 下文附 formatter 对象
: (text === void 0 ? match : text.split('\\]').join(']'))
)
}
formatter
对象:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
const formatter = {
// Year: 00, 01, ..., 99
YY (date, _, forcedYear) {
// workaround for < 1900 with new Date()
const y = this.YYYY(date, _, forcedYear) % 100
return y > 0
? pad(y)
: '-' + pad(Math.abs(y))
},
// Year: 1900, 1901, ..., 2099
YYYY (date, _, forcedYear) {
// workaround for < 1900 with new Date()
return forcedYear !== void 0 && forcedYear !== null
? forcedYear
: date.getFullYear()
},
// Month: 1, 2, ..., 12
M (date) {
return date.getMonth() + 1
},
// Month: 01, 02, ..., 12
MM (date) {
return pad(date.getMonth() + 1)
},
// Month Short Name: Jan, Feb, ...
MMM (date, dateLocale) {
return dateLocale.monthsShort[date.getMonth()]
},
// Month Name: January, February, ...
MMMM (date, dateLocale) {
return dateLocale.months[date.getMonth()]
},
// Quarter: 1, 2, 3, 4
Q (date) {
return Math.ceil((date.getMonth() + 1) / 3)
},
// Quarter: 1st, 2nd, 3rd, 4th
Qo (date) {
return getOrdinal(this.Q(date))
},
// Day of month: 1, 2, ..., 31
D (date) {
return date.getDate()
},
// Day of month: 1st, 2nd, ..., 31st
Do (date) {
return getOrdinal(date.getDate())
},
// Day of month: 01, 02, ..., 31
DD (date) {
return pad(date.getDate())
},
// Day of year: 1, 2, ..., 366
DDD (date) {
return getDayOfYear(date)
},
// Day of year: 001, 002, ..., 366
DDDD (date) {
return pad(getDayOfYear(date), 3)
},
// Day of week: 0, 1, ..., 6
d (date) {
return date.getDay()
},
// Day of week: Su, Mo, ...
dd (date, dateLocale) {
return this.dddd(date, dateLocale).slice(0, 2)
},
// Day of week: Sun, Mon, ...
ddd (date, dateLocale) {
return dateLocale.daysShort[date.getDay()]
},
// Day of week: Sunday, Monday, ...
dddd (date, dateLocale) {
return dateLocale.days[date.getDay()]
},
// Day of ISO week: 1, 2, ..., 7
E (date) {
return date.getDay() || 7
},
// Week of Year: 1 2 ... 52 53
w (date) {
return getWeekOfYear(date)
},
// Week of Year: 01 02 ... 52 53
ww (date) {
return pad(getWeekOfYear(date))
},
// Hour: 0, 1, ... 23
H (date) {
return date.getHours()
},
// Hour: 00, 01, ..., 23
HH (date) {
return pad(date.getHours())
},
// Hour: 1, 2, ..., 12
h (date) {
const hours = date.getHours()
if (hours === 0) {
return 12
}
if (hours > 12) {
return hours % 12
}
return hours
},
// Hour: 01, 02, ..., 12
hh (date) {
return pad(this.h(date))
},
// Minute: 0, 1, ..., 59
m (date) {
return date.getMinutes()
},
// Minute: 00, 01, ..., 59
mm (date) {
return pad(date.getMinutes())
},
// Second: 0, 1, ..., 59
s (date) {
return date.getSeconds()
},
// Second: 00, 01, ..., 59
ss (date) {
return pad(date.getSeconds())
},
// 1/10 of second: 0, 1, ..., 9
S (date) {
return Math.floor(date.getMilliseconds() / 100)
},
// 1/100 of second: 00, 01, ..., 99
SS (date) {
return pad(Math.floor(date.getMilliseconds() / 10))
},
// Millisecond: 000, 001, ..., 999
SSS (date) {
return pad(date.getMilliseconds(), 3)
},
// Meridiem: AM, PM
A (date) {
return this.H(date) < 12 ? 'AM' : 'PM'
},
// Meridiem: am, pm
a (date) {
return this.H(date) < 12 ? 'am' : 'pm'
},
// Meridiem: a.m., p.m.
aa (date) {
return this.H(date) < 12 ? 'a.m.' : 'p.m.'
},
// Timezone: -01:00, +00:00, ... +12:00
Z (date) {
return formatTimezone(date.getTimezoneOffset(), ':')
},
// Timezone: -0100, +0000, ... +1200
ZZ (date) {
return formatTimezone(date.getTimezoneOffset())
},
// Seconds timestamp: 512969520
X (date) {
return Math.floor(date.getTime() / 1000)
},
// Milliseconds timestamp: 512969520900
x (date) {
return date.getTime()
}
}
看到这里原理你应该就懂了,就是如上文我说的,利用 replace
方法特性进行循环替换,最后返回一个用具体数据替代 mask
后的日期字符串。