Dayjs使用笔记
Day.js 是一个极简的 JavaScript 库,可以为现代浏览器解析、验证、操作和显示日期和时间。所有更改 Day.js 对象的 API 操作都将返回一个新的实例。这有助于防止错误和避免长时间的调试会话。 下面罗列的是我用到的 dayjs 的功能。
官网:https://day.js.org/zh-CN/ (opens new window)
# 基础知识点
# 解析
Day.js 并没有对原生 Date.prototype 做任何修改, 而是给 Date 对象做了一层封装。 使用支持的数据格式调用 dayjs() 即可取到这个封装的对象。
Day.js 对象是不可变的,所有的 API 操作都将返回一个全新的实例。
# 当前时间
直接调用 dayjs() 将返回一个包含当前日期和时间的 Day.js 对象。
var now = dayjs()
等同于 dayjs(new Date()) 的调用。
当没有传入参数时,参数默认值是 undefined,所以调用 dayjs(undefined) 就相当于调用 dayjs()。
Day.js 将 dayjs(null) 视为无效的输入。
# string + Format
如果知道输入字符串的格式,您可以用它来解析日期。
这依赖 CustomParseFormat 插件,才能正常运行
dayjs.extend(customParseFormat)
dayjs('12-25-1995', 'MM-DD-YYYY')
2
如果想解析包含本地化语言的日期字符串,可以传入第三个参数。
require('dayjs/locale/zh-cn')
dayjs('2018 三月 15', 'YYYY MMMM DD', 'zh-cn')
2
最后一个参数可传入布尔值来启用严格解析模式。 严格解析要求格式和输入内容完全匹配,包括分隔符。
dayjs('1970-00-00', 'YYYY-MM-DD').isValid() // true
dayjs('1970-00-00', 'YYYY-MM-DD', true).isValid() // false
dayjs('1970-00-00', 'YYYY-MM-DD', 'es', true).isValid() // false
2
3
如果您不知道输入字符串的确切格式,但知道它可能是几种中的一种,可以使用数组传入多个格式。
dayjs('12-25-2001', ['YYYY', 'YYYY-MM-DD'], 'es', true)
支持的解析占位符列表
| 输入 | 例子 | 详情 |
|---|---|---|
| YY | 01 | 两位数的年份 |
| YYYY | 2001 | 四位数的年份 |
| M | 1-12 | 月份,从 1 开始 |
| MM | 01-12 | 月份,两位数 |
| MMM | Jan-Dec | 缩写的月份名称 |
| MMMM | January-December | |
| D | 1-31 | 月份里的一天 |
| DD | 01-31 | 月份里的一天,两位数 |
| H | 0-23 | 小时 |
| HH | 00-23 | 小时,两位数 |
| h | 1-12 | 小时, 12 小时制 |
| hh | 01-12 | 小时, 12 小时制, 两位数 |
| m | 0-59 | 分钟 |
| mm | 00-59 | 分钟,两位数 |
| s | 0-59 | 秒 |
| ss | 00-59 | 秒 两位数 |
| S | 0-9 | 毫秒,一位数 |
| SS | 00-99 | 毫秒,两位数 |
| SSS | 000-999 | 毫秒,三位数 |
| Z | -05:00 | UTC 的偏移量 |
| ZZ | -0500 | UTC 的偏移量,两位数 |
| A | AM PM | 上午 下午 大写 |
| a | am pm | 上午 下午 小写 |
| Do | 1st... 31st | 带序数词的月份里的一天 |
| X | 1410715640.579 | Unix 时间戳 |
| x | 1410715640579 | Unix 时间戳 |
# Date 对象
使用原生 Javascript Date 对象创建一个 Day.js 对象。
var d = new Date(2018, 8, 18)
var day = dayjs(d)
2
这将克隆 Date 对象。 对传入的 Date 对象做进一步更改不会影响 Day.js 对象,反之亦然。
# 验证
返回 布尔值 表示 Dayjs 的日期是否通过校验
- 不严格的校验
只检查传入的值能否被解析成一个时间日期
dayjs('2022-01-33').isValid() // true, parsed to 2022-02-02 dayjs('some invalid string').isValid() // false1
2
3
4 - 严格校验
检查传入的值能否被解析,且是否是一个有意义的日期。 最后两个参数 format 和 strict 必须提供。
这依赖 CustomParseFormat 插件,才能正常运行
dayjs('2022-02-31', 'YYYY-MM-DD', true).isValid() // false1
2
# 插件
在引入插件后,使用dayjs.extend(xxx)就可以使用插件,相关的实用的插件,参考官网 (opens new window)
# 取值/赋值
在设计上 Day.js 的 getter 和 setter 使用了相同的 API,也就是说,不传参数调用方法即为 getter,调用并传入参数为 setter。
由于 dayjs 对象是不可变的,所有设置操作将返回一个新的 dayjs 实例。
这些 API 调用了对应原生 Date 对象的方法。
dayjs().second(30).valueOf() // => new Date().setSeconds(30)
dayjs().second() // => new Date().getSeconds()
2
如果您处于 UTC 模式,将会调用对应的 UTC 方法。
dayjs.utc().second(30).valueOf() // => new Date().setUTCSeconds(30)
dayjs.utc().second() // => new Date().getUTCSeconds()
2
# 操作
您可能需要一些方法来操作 Day.js 对象。
Day.js 支持像这样的链式调用:
dayjs('2019-01-25').add(1, 'day').subtract(1, 'year').year(2009).toString()
# Add
返回增加一定时间的复制的 Day.js 对象。
const a = dayjs()
const b = a.add(7, 'day')
// a -> the original value and will not change
// b -> the manipulation result
2
3
4
5
各个传入的单位对大小写不敏感,支持缩写和复数。 请注意,缩写是区分大小写的。
支持的单位列表
| 单位 | 缩写 | 详情 |
|---|---|---|
| day | d | 日 |
| week | w | 周 |
| month | M | 月 |
| quarter | Q | 季度 ( 依赖 QuarterOfYear 插件 ) |
| year | y | 年 |
| hour | h | 小时 |
| minute | m | 分钟 |
| second | s | 秒 |
| millisecond | ms | 毫秒 |
或者,也可以给 Day.js 对象增加一个 持续时间 。
result = dayjs().add(dayjs.duration({ days: 1 }))
console.log(dayjs.duration().days(1))
2
# Subtract
返回减去一定时间的复制的 Day.js 对象。
dayjs().subtract(7, 'year')
各个传入的单位对大小写不敏感,支持缩写和复数。 支持的单位列表 (opens new window)
# 显示
当解析和操作完成后,您需要一些方式来展示 Day.js 对象。
# Format
根据传入的占位符返回格式化后的日期。
将字符放在方括号中,即可原样返回而不被格式化替换 (例如, [MM])。
dayjs().format()
// 默认返回的是 ISO8601 格式字符串 '2020-04-02T08:02:17-05:00'
dayjs('2019-01-25').format('[YYYYescape] YYYY-MM-DDTHH:mm:ssZ[Z]')
// 'YYYYescape 2019-01-25T00:00:00-02:00Z'
dayjs('2019-01-25').format('DD/MM/YYYY') // '25/01/2019'
2
3
4
5
6
7
支持的格式化占位符列表 (opens new window)
# Difference
返回指定单位下两个日期时间之间的差异。
要获得以毫秒为单位的差异,请使用 dayjs#diff。
const date1 = dayjs('2019-01-25')
const date2 = dayjs('2018-06-05')
date1.diff(date2) // 20214000000 默认单位是毫秒
2
3
要获取其他单位下的差异,则在第二个参数传入相应的单位。
const date1 = dayjs('2019-01-25')
date1.diff('2018-06-05', 'month') // 7
2
默认情况下 dayjs#diff 会将结果进位成整数。 如果要得到一个浮点数,将 true 作为第三个参数传入。
const date1 = dayjs('2019-01-25')
date1.diff('2018-06-05', 'month', true) // 7.645161290322581
2
支持的单位列表 各个传入的单位对大小写不敏感,支持缩写和复数。 请注意,缩写是区分大小写的。
| 单位 | 缩写 | 详情 |
|---|---|---|
| day | d | 日 |
| week | w | Week of Year |
| quarter | Q | Quarter |
| month | M | 月份 (一月 0, 十二月 11) |
| year | y | Year |
| hour | h | Hour |
| minute | m | Minute |
| second | s | Second |
| millisecond | ms | Millisecond |
# 查询
# Is Before
这表示 Day.js 对象是否在另一个提供的日期时间之前。
dayjs().isBefore(dayjs('2011-01-01')) // 默认毫秒
如果想使用除了毫秒以外的单位进行比较,则将单位作为第二个参数传入。 在这种情况下,会使用传入的单位以及比其范围大的单位进行比较。
dayjs().isBefore('2011-01-01', 'month') // compares month and year
各个传入的单位对大小写不敏感,支持缩写和复数。 支持的单位列表 (opens new window)
# Is Same
这表示 Day.js 对象是否和另一个提供的日期时间相同。
dayjs().isSame(dayjs('2011-01-01')) // 默认毫秒
如果想使用除了毫秒以外的单位进行比较,则将单位作为第二个参数传入。
当使用第二个参数时,将会连同去比较更大的单位。 如传入 month 将会比较 month 和 year。 传入 day 将会比较 day、 month 和 year。
dayjs().isSame('2011-01-01', 'year')
各个传入的单位对大小写不敏感,支持缩写和复数。 支持的单位列表 (opens new window)
# Is After
这表示 Day.js 对象是否在另一个提供的日期时间之后。
dayjs().isAfter(dayjs('2011-01-01')) // 默认毫秒
如果想使用除了毫秒以外的单位进行比较,则将单位作为第二个参数传入。 在这种情况下,会使用传入的单位以及比其范围大的单位进行比较。
dayjs().isAfter('2011-01-01', 'month') // compares month and year
各个传入的单位对大小写不敏感,支持缩写和复数。 支持的单位列表 (opens new window)
# Is Same or Before
这表示 Day.js 对象是否和另一个提供的日期时间相同或在其之前。
这依赖 IsSameOrBefore 插件,才能正常运行
dayjs.extend(isSameOrBefore)
dayjs().isSameOrBefore(dayjs('2011-01-01')) // 默认毫秒
2
如果想使用除了毫秒以外的单位进行比较,则将单位作为第二个参数传入。
dayjs().isSameOrBefore('2011-01-01', 'year')
各个传入的单位对大小写不敏感,支持缩写和复数。
# Is Same or After
这表示 Day.js 对象是否和另一个提供的日期时间相同或在其之后。
这依赖 IsSameOrAfter 插件,才能正常运行
dayjs.extend(isSameOrAfter)
dayjs().isSameOrAfter(dayjs('2011-01-01')) // 默认毫秒
2
如果想使用除了毫秒以外的单位进行比较,则将单位作为第二个参数传入。
dayjs().isSameOrAfter('2011-01-01', 'year')
各个传入的单位对大小写不敏感,支持缩写和复数。 支持的单位列表 (opens new window)
# Is Between
这表示 Day.js 对象是否在其他两个的日期时间之间。
这依赖 IsBetween 插件,才能正常运行
dayjs.extend(isBetween)
dayjs('2010-10-20').isBetween('2010-10-19', dayjs('2010-10-25'))
// 默认毫秒
2
3
如果想使用除了毫秒以外的单位进行比较,则将单位作为第三个参数传入。 在这种情况下,会使用传入的单位以及比其范围大的单位进行比较。
dayjs().isBetween('2010-10-19', '2010-10-25', 'month') // compares month and year
各个传入的单位对大小写不敏感,支持缩写和复数。
第四个参数是设置包容性。 [ 表示包含。 ( 表示排除。
要使用包容性参数,必须同时传入两个指示符。
dayjs('2016-10-30').isBetween('2016-01-01', '2016-10-30', null, '[)')
# Is a Dayjs
这表示一个变量是否为 Day.js 对象。
dayjs.isDayjs(dayjs()) // true
dayjs.isDayjs(new Date()) // false
2
这和使用 instanceof 的结果是一样的:
dayjs() instanceof dayjs // true
# 帖子发布时间
在做评论之类的帖子类型的需求的时候,会在每个帖子上附带发帖时间,不同网站的显示时间的规则是有差异的。
比如:
| 时间 | 显示文字 | 示例 |
|---|---|---|
| 十分钟内 | 刚刚发布 | 刚刚发布 |
| 大于 10 分钟,小于 1 小时 | xxx 分钟前 | 19 分钟前 |
| 大于 1 小时,不超过当日 | xxx 小时前 | 4 小时前 |
| 昨天 | 昨日 hh:mm | 昨日 13:44 |
| 当年 | MM-DD hh:mm | 01-31 11:26 |
| 跨年 | YYYY-MM-DD hh:mm | 2020-12-12 13:44 |
又如,项目另一个模块:
| 时间 | 显示文字 | 示例 |
|---|---|---|
| 十分钟内 | 刚刚更新 | 刚刚更新 |
| 大于 10 分钟,小于 1 小时 | xxx 分钟前 | 19 分钟前 |
| 大于 1 小时,不超过当日 | xxx 小时前更新 | 4 小时前更新 |
| 昨天 | 昨日 hh:mm 更新 | 昨日 13:44 更新 |
| 当年 | MM-DD hh:mm 更新 | 01-31 11:26 更新 |
| 跨年 | YYYY-MM-DD hh:mm 更新 | 2020-12-12 13:44 更新 |
# 解决思路
用多个条件分支进行判断:跨年、当日、昨日 判断方法采用 dayjs 自带的查询功能。
我最开始想到的是使用
relativeTime插件,然后自定义输出内容 (opens new window),这样就实现了不同时间段的不同前缀和后缀的配置。但是这样有一个缺陷,这个前后缀的配置是全局的,我配置完成后,在项目另一个地方也采用这种配置前后缀的方法,就会相互影响。不清楚是否可以进行局部配置,我后续尝试一下
dayjs 自带查询功能
# 判断是否跨年
dayjs(inputTime).isSameOrBefore(dayjs(dayjs().subtract(1, 'year')))
# 判断是否昨日
dayjs(inputTime).isSame(dayjs().subtract(1, 'day'), 'day')
# 判断是否当日
dayjs(inputTime).isSame(dayjs(), 'day')
# 判断是否超过一小时
dayjs(inputTime).isSameOrBefore(dayjs().subtract(1, 'hour'), 'hour')
# 判断是否超过 10 分钟
dayjs(inputTime).isSameOrBefore(dayjs().subtract(10, 'minute'), 'minute')
整合逻辑判断后的代码
function getPostPublishTime(inputTime) {
const isOneYearBefore = dayjs(inputTime).isSameOrBefore(
dayjs(dayjs().subtract(1, 'year'))
)
const isYesterday = dayjs(inputTime).isSame(
dayjs().subtract(1, 'day'),
'day'
)
const isToday = dayjs(inputTime).isSame(dayjs(), 'day')
const isMoreThanAnHour = dayjs(inputTime).isSameOrBefore(
dayjs().subtract(1, 'hour'),
'hour'
)
const isMoreThan10Mins = dayjs(inputTime).isSameOrBefore(
dayjs().subtract(10, 'minute'),
'minute'
)
if (isOneYearBefore) {
// 是否跨年
return dayjs(inputTime).format('YYYY-MM-DD HH:mm')
} else if (isYesterday) {
// 是否昨日
return dayjs(inputTime).format('昨日 HH:mm')
} else if (isToday) {
// 是否今天
if (isMoreThanAnHour) {
// 超过1小时
return dayjs().diff(dayjs(inputTime), 'hour') + '小时前'
} else if (isMoreThan10Mins) {
// 超过10分钟
return dayjs().diff(dayjs(inputTime), 'minute') + '分钟前'
} else {
// 10分钟以内
return '刚刚发布'
}
} else {
// 今年发布的
return dayjs(inputTime).format('MM-DD HH:mm')
}
}
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