理解Dayjs

3,044 阅读5分钟
  • 时间字符串: 指的是 YYYY-MM-DD 、 HH:mm:ss诸如,在本地显示的时间字符串

理解时间和时区

A

假设张三在A地区(+8)执行了一行代码,new Date('2022-01-01 00:00:00:000').valueOf(),同时老王在B地区(+7)地区也执行了这行代码,请问他们获得的时间戳是否相同?

答: 不相同。为什么呢,因为A地区 22年一月一号0点的时候,B地区比我们早了一个钟, 时钟上显示着 '2021-12-31 23:00:00',而当B地区到了22年一月一日0点的时候,我们已经过了一个钟时钟上显示的是 '2022-01-01 01:00:00'

// A地区 +8
new Date('2022-01-01 00:00:00:000').valueOf()  // 1640966400000// B地区 +7
new Date('2022-01-01 00:00:00:000').valueOf()  // 1640970000000
 

B

假设张三在A地区(+8)执行了一行代码,new Date(1640966400000),同时老王在B地区(+7)地区也执行了这行代码,请问他们获得的时间戳是否相同?

答: 不相同。这个原因和上面是一样的,同一个时刻,不同的地区上,时钟显示的是不一样的,ID比我们早了一个时区,自然是比我们快了一个钟。

// A +8
new Date(1640966400000)  // Sat Jan 01 2022 00:00:00 GMT+0800 (A地区标准时间)// B +7
new Date(1640966400000)  // Fri Dec 31 2021 23:00:00 GMT+0700 (B地区标准时间)

从这两个例子我们可以看到,

  • 时间字符串相同时,在不同的地区获得的时间戳是不同的
  • 时间戳相同时,在不同的地区获取的时间字符串是不同的

看到这里,你似乎已经对时间、时区、时间字符串有了一个初步的印象和理解。

关于时间和时区

  1. 时间是什么?

    这是个很深刻的问题了,关于时间的定义,很复杂。但是简单来说,指的是某一瞬间。

  2. 时间戳、UTC、GMT这些都是什么?

    参考: 日期与时间(UTC、GMT、时间戳、时区)

  3. 时间戳需要理解时区概念吗?

    时间戳是不需要考虑时区概念的。

    为什么这样说,假设 1657535893504(东八区 2022-07-11 18:39:22) 这个时间戳,无论在哪个国家哪个地区,它都代表着某一个时刻时间,它是时间本身的记录。

  4. 那时间字符串有时区概念呢?

    当然有,因为在不同的时区下,同一个时间字符串代表的是不同的时间本身。 时间字符串只是当地时间的一个表达。

  5. 时间字符串和 UTC 、 GMT有什么区别,不都是字符串吗?

    Good,福尔摩斯的你已经发现了端倪。 '2022-01-01 00:00:00' 和 'Sat Jan 01 2022 00:00:00 GMT+0800 (中国标准时间)' 虽然同样都是字符串,但是前者没有时区,所以在不同的时区下,它代表着不同的时间,后者带上了时区,它永久地指向了一个特定的时间。

  6. 理解dayjs对象?

    我们应该知道dayjs对象本质上就是时间,在理解 时区、本地字符串、时间的关系和转换时,我们需要把dayjs对象当成时间当成时间戳去处理。

Dayjs的使用

从上面我们知道, 时间字符串 + 时区 = 时间。 那我们再来了解一下dayjs的api

  1. dayjs()

    这是最基础的一个api。调用时,时区都是机器时区无论你是否设置了tz的默认时区

    从下面可以看到,当我们传入一个普通的时间字符串时,它是指我们本地的2022-01-01 image.png

  2. dayjs().tz() // tz(timezone?: string, keepLocalTime?: boolean): Dayjs

    interface Dayjs {
        tz(timezone?: string, keepLocalTime?: boolean): Dayjs
    }
    

    可以注意到,此时的tz是dayjs实例上的共有函数,它的作用是转换时区。记住我们上面的等式, 时间字符串 + 时区 = 时间。所以,时区改变了,要么时间字符串改变,要么时间改变,这里是通过第二个参数去控制的,不传第二个函数默认是false

    • keepLocalTimefalse, 时间不变,时间字符串改变了 image.png
    • keepLocalTimetrue , 时间字符串没变,时间变了 image.png
  3. dayjs.tz()

    可以先看下它的类型定义

    interface DayjsTimezone {
        (date: ConfigType, timezone?: string): Dayjs
        (date: ConfigType, format: string, timezone?: string): Dayjs
    }
    const tz: DayjsTimezone
    

    首先和第二个函数不同,它是挂载在dayjs上的静态函数,它的作用和第一个函数 dayjs() 类似,都是用来构造dayjs对象的,但是不同的是,你可以指定你的目标时区,如果第二个参数没传,会使用tz.setDefault指定的时区

    仍然是那个等式, 时间字符串 + 时区 = 时间,所以如果第一个参数传入了时间字符串,那么就是 时间字符串 + 指定时区, 如果传入的是时间,则format的时候是结果会不同

    • 传入时间字符串 image.png

    • 传入时间 image.png

    • 传入dayjs image.png

      在上面我们说过,dayjs对象需要当成时间来理解,所以传入dayjs 等同于 传入时间。那么当我们需要保持时间字符串不变时,那我们就需要先format一下。 image.png

      可能有的同学已经发现了,既然传入的是dayjs,为啥不直接调用第二个例子, tz这个实例方法呢? 这里有两个理由:

      1. 如果是时间选择器出来的时间,这个dayjs可能是没有tz这个实例方法的,因为没有继承过timezone

        dayjs.extend(utc)
        dayjs.extend(timezone)
        
      2. 通常来说,都是用dayjs.tz.setDefault 设置一个默认的目标时区,而tz这个实例方法,又不能绕开第一个参数去设置第二个参数