Allen's blog Allen's blog
首页
面经
算法 (opens new window)
分类

Allen

前端CV工程师
首页
面经
算法 (opens new window)
分类
  • Javascript

  • TypeScript

  • CSS

  • Vue

  • React

  • 框架和构建工具

  • 工具库

    • Dayjs使用笔记
      • 基础知识点
        • 解析
        • 当前时间
        • string + Format
        • Date 对象
        • 验证
        • 插件
        • 取值/赋值
        • 操作
        • Add
        • Subtract
        • 显示
        • Format
        • Difference
        • 查询
        • Is Before
        • Is Same
        • Is After
        • Is Same or Before
        • Is Same or After
        • Is Between
        • Is a Dayjs
      • 帖子发布时间
        • 解决思路
        • 判断是否跨年
        • 判断是否昨日
        • 判断是否当日
        • 判断是否超过一小时
        • 判断是否超过 10 分钟
    • Viewjs图片查看器
    • better-scroll无限滚动
    • ESLint笔记
    • fundlint代码规范工具开发
  • 常见业务场景

  • Bug

  • 项目实战

  • 前端
  • 工具库
Allen
2023-01-31
目录

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()
1

等同于 dayjs(new Date()) 的调用。

当没有传入参数时,参数默认值是 undefined,所以调用 dayjs(undefined) 就相当于调用 dayjs()。

Day.js 将 dayjs(null) 视为无效的输入。

# string + Format

如果知道输入字符串的格式,您可以用它来解析日期。

这依赖 CustomParseFormat 插件,才能正常运行

dayjs.extend(customParseFormat)
dayjs('12-25-1995', 'MM-DD-YYYY')
1
2

如果想解析包含本地化语言的日期字符串,可以传入第三个参数。

require('dayjs/locale/zh-cn')
dayjs('2018 三月 15', 'YYYY MMMM DD', 'zh-cn')
1
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
1
2
3

如果您不知道输入字符串的确切格式,但知道它可能是几种中的一种,可以使用数组传入多个格式。

dayjs('12-25-2001', ['YYYY', 'YYYY-MM-DD'], 'es', true)
1

支持的解析占位符列表

输入 例子 详情
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)
1
2

这将克隆 Date 对象。 对传入的 Date 对象做进一步更改不会影响 Day.js 对象,反之亦然。

# 验证

返回 布尔值 表示 Dayjs 的日期是否通过校验

  • 不严格的校验 只检查传入的值能否被解析成一个时间日期
    dayjs('2022-01-33').isValid()
    // true, parsed to 2022-02-02
    dayjs('some invalid string').isValid()
    // false
    
    1
    2
    3
    4
  • 严格校验 检查传入的值能否被解析,且是否是一个有意义的日期。 最后两个参数 format 和 strict 必须提供。

    这依赖 CustomParseFormat 插件,才能正常运行

    dayjs('2022-02-31', 'YYYY-MM-DD', true).isValid()
    // false
    
    1
    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()
1
2

如果您处于 UTC 模式,将会调用对应的 UTC 方法。

dayjs.utc().second(30).valueOf() // => new Date().setUTCSeconds(30)
dayjs.utc().second() // => new Date().getUTCSeconds()
1
2

# 操作

您可能需要一些方法来操作 Day.js 对象。

Day.js 支持像这样的链式调用:

dayjs('2019-01-25').add(1, 'day').subtract(1, 'year').year(2009).toString()
1

# Add

返回增加一定时间的复制的 Day.js 对象。

const a = dayjs()
const b = a.add(7, 'day')

// a -> the original value and will not change
// b -> the manipulation result
1
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))
1
2

# Subtract

返回减去一定时间的复制的 Day.js 对象。

dayjs().subtract(7, 'year')
1

各个传入的单位对大小写不敏感,支持缩写和复数。 支持的单位列表 (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'
1
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 默认单位是毫秒
1
2
3

要获取其他单位下的差异,则在第二个参数传入相应的单位。

const date1 = dayjs('2019-01-25')
date1.diff('2018-06-05', 'month') // 7
1
2

默认情况下 dayjs#diff 会将结果进位成整数。 如果要得到一个浮点数,将 true 作为第三个参数传入。

const date1 = dayjs('2019-01-25')
date1.diff('2018-06-05', 'month', true) // 7.645161290322581
1
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')) // 默认毫秒
1

如果想使用除了毫秒以外的单位进行比较,则将单位作为第二个参数传入。 在这种情况下,会使用传入的单位以及比其范围大的单位进行比较。

dayjs().isBefore('2011-01-01', 'month') // compares month and year
1

各个传入的单位对大小写不敏感,支持缩写和复数。 支持的单位列表 (opens new window)

# Is Same

这表示 Day.js 对象是否和另一个提供的日期时间相同。

dayjs().isSame(dayjs('2011-01-01')) // 默认毫秒
1

如果想使用除了毫秒以外的单位进行比较,则将单位作为第二个参数传入。

当使用第二个参数时,将会连同去比较更大的单位。 如传入 month 将会比较 month 和 year。 传入 day 将会比较 day、 month 和 year。

dayjs().isSame('2011-01-01', 'year')
1

各个传入的单位对大小写不敏感,支持缩写和复数。 支持的单位列表 (opens new window)

# Is After

这表示 Day.js 对象是否在另一个提供的日期时间之后。

dayjs().isAfter(dayjs('2011-01-01')) // 默认毫秒
1

如果想使用除了毫秒以外的单位进行比较,则将单位作为第二个参数传入。 在这种情况下,会使用传入的单位以及比其范围大的单位进行比较。

dayjs().isAfter('2011-01-01', 'month') // compares month and year
1

各个传入的单位对大小写不敏感,支持缩写和复数。 支持的单位列表 (opens new window)

# Is Same or Before

这表示 Day.js 对象是否和另一个提供的日期时间相同或在其之前。

这依赖 IsSameOrBefore 插件,才能正常运行

dayjs.extend(isSameOrBefore)
dayjs().isSameOrBefore(dayjs('2011-01-01')) // 默认毫秒
1
2

如果想使用除了毫秒以外的单位进行比较,则将单位作为第二个参数传入。

dayjs().isSameOrBefore('2011-01-01', 'year')
1

各个传入的单位对大小写不敏感,支持缩写和复数。

支持的单位列表 (opens new window)

# Is Same or After

这表示 Day.js 对象是否和另一个提供的日期时间相同或在其之后。

这依赖 IsSameOrAfter 插件,才能正常运行

dayjs.extend(isSameOrAfter)
dayjs().isSameOrAfter(dayjs('2011-01-01')) // 默认毫秒
1
2

如果想使用除了毫秒以外的单位进行比较,则将单位作为第二个参数传入。

dayjs().isSameOrAfter('2011-01-01', 'year')
1

各个传入的单位对大小写不敏感,支持缩写和复数。 支持的单位列表 (opens new window)

# Is Between

这表示 Day.js 对象是否在其他两个的日期时间之间。

这依赖 IsBetween 插件,才能正常运行

dayjs.extend(isBetween)
dayjs('2010-10-20').isBetween('2010-10-19', dayjs('2010-10-25'))
// 默认毫秒
1
2
3

如果想使用除了毫秒以外的单位进行比较,则将单位作为第三个参数传入。 在这种情况下,会使用传入的单位以及比其范围大的单位进行比较。

dayjs().isBetween('2010-10-19', '2010-10-25', 'month') // compares month and year
1

各个传入的单位对大小写不敏感,支持缩写和复数。

支持的单位列表 (opens new window)

第四个参数是设置包容性。 [ 表示包含。 ( 表示排除。

要使用包容性参数,必须同时传入两个指示符。

dayjs('2016-10-30').isBetween('2016-01-01', '2016-10-30', null, '[)')
1

# Is a Dayjs

这表示一个变量是否为 Day.js 对象。

dayjs.isDayjs(dayjs()) // true
dayjs.isDayjs(new Date()) // false
1
2

这和使用 instanceof 的结果是一样的:

dayjs() instanceof dayjs // true
1

# 帖子发布时间

在做评论之类的帖子类型的需求的时候,会在每个帖子上附带发帖时间,不同网站的显示时间的规则是有差异的。
比如:

时间 显示文字 示例
十分钟内 刚刚发布 刚刚发布
大于 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')))
1

# 判断是否昨日

dayjs(inputTime).isSame(dayjs().subtract(1, 'day'), 'day')
1

# 判断是否当日

dayjs(inputTime).isSame(dayjs(), 'day')
1

# 判断是否超过一小时

dayjs(inputTime).isSameOrBefore(dayjs().subtract(1, 'hour'), 'hour')
1

# 判断是否超过 10 分钟

dayjs(inputTime).isSameOrBefore(dayjs().subtract(10, 'minute'), 'minute')
1

整合逻辑判断后的代码

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')
    }
}
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
上次更新: 2023/12/16, 09:22:46
ts、vite、vitepress配置别名alias
Viewjs图片查看器

← ts、vite、vitepress配置别名alias Viewjs图片查看器→

最近更新
01
rollup使用配置文件rollup.config.ts打包
12-08
02
package.json导出类型
12-08
03
关键问题方案
11-17
更多文章>
Theme by Vdoing | Copyright © 2023-2023 Allen | Github
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式