Appearance
Day.js 是一个极简的 JavaScript 库,可以为现代浏览器解析、验证、操作和显示日期和时间。所有更改 Day.js 对象的 API 操作都将返回一个新的实例。这有助于防止错误和避免长时间的调试会话。 下面罗列的是我用到的 dayjs 的功能。
基础知识点
解析
Day.js 并没有对原生 Date.prototype 做任何修改, 而是给 Date 对象做了一层封装。 使用支持的数据格式调用 dayjs() 即可取到这个封装的对象。
Day.js 对象是不可变的,所有的 API 操作都将返回一个全新的实例。
当前时间
直接调用 dayjs() 将返回一个包含当前日期和时间的 Day.js 对象。
js
var now = dayjs()var now = dayjs()等同于 dayjs(new Date()) 的调用。
当没有传入参数时,参数默认值是 undefined,所以调用 dayjs(undefined) 就相当于调用 dayjs()。
Day.js 将 dayjs(null) 视为无效的输入。
string + Format
如果知道输入字符串的格式,您可以用它来解析日期。
这依赖 CustomParseFormat 插件,才能正常运行
js
dayjs.extend(customParseFormat)
dayjs('12-25-1995', 'MM-DD-YYYY')dayjs.extend(customParseFormat)
dayjs('12-25-1995', 'MM-DD-YYYY')如果想解析包含本地化语言的日期字符串,可以传入第三个参数。
js
require('dayjs/locale/zh-cn')
dayjs('2018 三月 15', 'YYYY MMMM DD', 'zh-cn')require('dayjs/locale/zh-cn')
dayjs('2018 三月 15', 'YYYY MMMM DD', 'zh-cn')最后一个参数可传入布尔值来启用严格解析模式。 严格解析要求格式和输入内容完全匹配,包括分隔符。
js
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() // falsedayjs('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如果您不知道输入字符串的确切格式,但知道它可能是几种中的一种,可以使用数组传入多个格式。
js
dayjs('12-25-2001', ['YYYY', 'YYYY-MM-DD'], 'es', true)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 对象。
js
var d = new Date(2018, 8, 18)
var day = dayjs(d)var d = new Date(2018, 8, 18)
var day = dayjs(d)这将克隆 Date 对象。 对传入的 Date 对象做进一步更改不会影响 Day.js 对象,反之亦然。
验证
返回 布尔值 表示 Dayjs 的日期是否通过校验
- 不严格的校验 只检查传入的值能否被解析成一个时间日期js
dayjs('2022-01-33').isValid() // true, parsed to 2022-02-02 dayjs('some invalid string').isValid() // falsedayjs('2022-01-33').isValid() // true, parsed to 2022-02-02 dayjs('some invalid string').isValid() // false - 严格校验 检查传入的值能否被解析,且是否是一个有意义的日期。 最后两个参数 format 和 strict 必须提供。
这依赖 CustomParseFormat 插件,才能正常运行
jsdayjs('2022-02-31', 'YYYY-MM-DD', true).isValid() // falsedayjs('2022-02-31', 'YYYY-MM-DD', true).isValid() // false
插件
在引入插件后,使用dayjs.extend(xxx)就可以使用插件,相关的实用的插件,参考官网
取值/赋值
在设计上 Day.js 的 getter 和 setter 使用了相同的 API,也就是说,不传参数调用方法即为 getter,调用并传入参数为 setter。
由于 dayjs 对象是不可变的,所有设置操作将返回一个新的 dayjs 实例。
这些 API 调用了对应原生 Date 对象的方法。
js
dayjs().second(30).valueOf() // => new Date().setSeconds(30)
dayjs().second() // => new Date().getSeconds()dayjs().second(30).valueOf() // => new Date().setSeconds(30)
dayjs().second() // => new Date().getSeconds()如果您处于 UTC 模式,将会调用对应的 UTC 方法。
js
dayjs.utc().second(30).valueOf() // => new Date().setUTCSeconds(30)
dayjs.utc().second() // => new Date().getUTCSeconds()dayjs.utc().second(30).valueOf() // => new Date().setUTCSeconds(30)
dayjs.utc().second() // => new Date().getUTCSeconds()操作
您可能需要一些方法来操作 Day.js 对象。
Day.js 支持像这样的链式调用:
js
dayjs('2019-01-25').add(1, 'day').subtract(1, 'year').year(2009).toString()dayjs('2019-01-25').add(1, 'day').subtract(1, 'year').year(2009).toString()Add
返回增加一定时间的复制的 Day.js 对象。
js
const a = dayjs()
const b = a.add(7, 'day')
// a -> the original value and will not change
// b -> the manipulation resultconst a = dayjs()
const b = a.add(7, 'day')
// a -> the original value and will not change
// b -> the manipulation result各个传入的单位对大小写不敏感,支持缩写和复数。 请注意,缩写是区分大小写的。
支持的单位列表
| 单位 | 缩写 | 详情 |
|---|---|---|
| day | d | 日 |
| week | w | 周 |
| month | M | 月 |
| quarter | Q | 季度 ( 依赖 QuarterOfYear 插件 ) |
| year | y | 年 |
| hour | h | 小时 |
| minute | m | 分钟 |
| second | s | 秒 |
| millisecond | ms | 毫秒 |
| 或者,也可以给 Day.js 对象增加一个 持续时间 。 |
js
result = dayjs().add(dayjs.duration({ days: 1 }))
console.log(dayjs.duration().days(1))result = dayjs().add(dayjs.duration({ days: 1 }))
console.log(dayjs.duration().days(1))Subtract
返回减去一定时间的复制的 Day.js 对象。
js
dayjs().subtract(7, 'year')dayjs().subtract(7, 'year')各个传入的单位对大小写不敏感,支持缩写和复数。 支持的单位列表
显示
当解析和操作完成后,您需要一些方式来展示 Day.js 对象。
Format
根据传入的占位符返回格式化后的日期。
将字符放在方括号中,即可原样返回而不被格式化替换 (例如, [MM])。
js
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'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'Difference
返回指定单位下两个日期时间之间的差异。
要获得以毫秒为单位的差异,请使用 dayjs#diff。
js
const date1 = dayjs('2019-01-25')
const date2 = dayjs('2018-06-05')
date1.diff(date2) // 20214000000 默认单位是毫秒const date1 = dayjs('2019-01-25')
const date2 = dayjs('2018-06-05')
date1.diff(date2) // 20214000000 默认单位是毫秒要获取其他单位下的差异,则在第二个参数传入相应的单位。
js
const date1 = dayjs('2019-01-25')
date1.diff('2018-06-05', 'month') // 7const date1 = dayjs('2019-01-25')
date1.diff('2018-06-05', 'month') // 7默认情况下 dayjs#diff 会将结果进位成整数。 如果要得到一个浮点数,将 true 作为第三个参数传入。
js
const date1 = dayjs('2019-01-25')
date1.diff('2018-06-05', 'month', true) // 7.645161290322581const date1 = dayjs('2019-01-25')
date1.diff('2018-06-05', 'month', true) // 7.645161290322581支持的单位列表 各个传入的单位对大小写不敏感,支持缩写和复数。 请注意,缩写是区分大小写的。
| 单位 | 缩写 | 详情 |
|---|---|---|
| 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 对象是否在另一个提供的日期时间之前。
js
dayjs().isBefore(dayjs('2011-01-01')) // 默认毫秒dayjs().isBefore(dayjs('2011-01-01')) // 默认毫秒如果想使用除了毫秒以外的单位进行比较,则将单位作为第二个参数传入。 在这种情况下,会使用传入的单位以及比其范围大的单位进行比较。
js
dayjs().isBefore('2011-01-01', 'month') // compares month and yeardayjs().isBefore('2011-01-01', 'month') // compares month and year各个传入的单位对大小写不敏感,支持缩写和复数。 支持的单位列表
Is Same
这表示 Day.js 对象是否和另一个提供的日期时间相同。
js
dayjs().isSame(dayjs('2011-01-01')) // 默认毫秒dayjs().isSame(dayjs('2011-01-01')) // 默认毫秒如果想使用除了毫秒以外的单位进行比较,则将单位作为第二个参数传入。
当使用第二个参数时,将会连同去比较更大的单位。 如传入 month 将会比较 month 和 year。 传入 day 将会比较 day、 month 和 year。
js
dayjs().isSame('2011-01-01', 'year')dayjs().isSame('2011-01-01', 'year')各个传入的单位对大小写不敏感,支持缩写和复数。 支持的单位列表
Is After
这表示 Day.js 对象是否在另一个提供的日期时间之后。
js
dayjs().isAfter(dayjs('2011-01-01')) // 默认毫秒dayjs().isAfter(dayjs('2011-01-01')) // 默认毫秒如果想使用除了毫秒以外的单位进行比较,则将单位作为第二个参数传入。 在这种情况下,会使用传入的单位以及比其范围大的单位进行比较。
js
dayjs().isAfter('2011-01-01', 'month') // compares month and yeardayjs().isAfter('2011-01-01', 'month') // compares month and year各个传入的单位对大小写不敏感,支持缩写和复数。 支持的单位列表
Is Same or Before
这表示 Day.js 对象是否和另一个提供的日期时间相同或在其之前。
这依赖 IsSameOrBefore 插件,才能正常运行
js
dayjs.extend(isSameOrBefore)
dayjs().isSameOrBefore(dayjs('2011-01-01')) // 默认毫秒dayjs.extend(isSameOrBefore)
dayjs().isSameOrBefore(dayjs('2011-01-01')) // 默认毫秒如果想使用除了毫秒以外的单位进行比较,则将单位作为第二个参数传入。
js
dayjs().isSameOrBefore('2011-01-01', 'year')dayjs().isSameOrBefore('2011-01-01', 'year')各个传入的单位对大小写不敏感,支持缩写和复数。
Is Same or After
这表示 Day.js 对象是否和另一个提供的日期时间相同或在其之后。
这依赖 IsSameOrAfter 插件,才能正常运行
js
dayjs.extend(isSameOrAfter)
dayjs().isSameOrAfter(dayjs('2011-01-01')) // 默认毫秒dayjs.extend(isSameOrAfter)
dayjs().isSameOrAfter(dayjs('2011-01-01')) // 默认毫秒如果想使用除了毫秒以外的单位进行比较,则将单位作为第二个参数传入。
js
dayjs().isSameOrAfter('2011-01-01', 'year')dayjs().isSameOrAfter('2011-01-01', 'year')各个传入的单位对大小写不敏感,支持缩写和复数。 支持的单位列表
Is Between
这表示 Day.js 对象是否在其他两个的日期时间之间。
这依赖 IsBetween 插件,才能正常运行
js
dayjs.extend(isBetween)
dayjs('2010-10-20').isBetween('2010-10-19', dayjs('2010-10-25'))
// 默认毫秒dayjs.extend(isBetween)
dayjs('2010-10-20').isBetween('2010-10-19', dayjs('2010-10-25'))
// 默认毫秒如果想使用除了毫秒以外的单位进行比较,则将单位作为第三个参数传入。 在这种情况下,会使用传入的单位以及比其范围大的单位进行比较。
js
dayjs().isBetween('2010-10-19', '2010-10-25', 'month') // compares month and yeardayjs().isBetween('2010-10-19', '2010-10-25', 'month') // compares month and year各个传入的单位对大小写不敏感,支持缩写和复数。
第四个参数是设置包容性。 [ 表示包含。 ( 表示排除。
要使用包容性参数,必须同时传入两个指示符。
js
dayjs('2016-10-30').isBetween('2016-01-01', '2016-10-30', null, '[)')dayjs('2016-10-30').isBetween('2016-01-01', '2016-10-30', null, '[)')Is a Dayjs
这表示一个变量是否为 Day.js 对象。
js
dayjs.isDayjs(dayjs()) // true
dayjs.isDayjs(new Date()) // falsedayjs.isDayjs(dayjs()) // true
dayjs.isDayjs(new Date()) // false这和使用 instanceof 的结果是一样的:
js
dayjs() instanceof dayjs // truedayjs() 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插件,然后自定义输出内容,这样就实现了不同时间段的不同前缀和后缀的配置。但是这样有一个缺陷,这个前后缀的配置是全局的,我配置完成后,在项目另一个地方也采用这种配置前后缀的方法,就会相互影响。不清楚是否可以进行局部配置,我后续尝试一下
dayjs 自带查询功能
判断是否跨年
js
dayjs(inputTime).isSameOrBefore(dayjs(dayjs().subtract(1, 'year')))dayjs(inputTime).isSameOrBefore(dayjs(dayjs().subtract(1, 'year')))判断是否昨日
js
dayjs(inputTime).isSame(dayjs().subtract(1, 'day'), 'day')dayjs(inputTime).isSame(dayjs().subtract(1, 'day'), 'day')判断是否当日
js
dayjs(inputTime).isSame(dayjs(), 'day')dayjs(inputTime).isSame(dayjs(), 'day')判断是否超过一小时
js
dayjs(inputTime).isSameOrBefore(dayjs().subtract(1, 'hour'), 'hour')dayjs(inputTime).isSameOrBefore(dayjs().subtract(1, 'hour'), 'hour')判断是否超过 10 分钟
js
dayjs(inputTime).isSameOrBefore(dayjs().subtract(10, 'minute'), 'minute')dayjs(inputTime).isSameOrBefore(dayjs().subtract(10, 'minute'), 'minute')整合逻辑判断后的代码
js
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')
}
}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')
}
}