温故而知新系列(二)内建引用数据类型之Date

730 阅读8分钟

在正式介绍Date前,如果有兴趣的话可以了解一下1970年1月1日这个神奇的日子吧!大部分童鞋都知道时间戳都是从这个日期起算的,但很少有童鞋了解那段历史,附上一个比较有意思的介绍链接,还可以了解一下《苹果"1970事件"》

漫话:为什么计算机起始时间是1970年1月1日? - 云+社区 - 腾讯云 (tencent.com)

1970 年1月1日

被称为Unix纪元时间the epoch,通常我们说的时间戳,就是指格林尼治时间(GMT)1970年01月01日00时00分00秒起至现在的总秒数,而中国处于东八区,所以时间会比标准时间早8小时,苹果1970事件的原因就是IOS设备是以UTC时区(GMT时间)的1970年1月1日0点0时0秒为界限,数值为0,用户把时间调整到1969年12月31日16时0分0秒,系统就要出现负值的时间,从而发生bug,不过早已修复了😄

一、构造方法

共有4中方式,以下测试均在node环境下执行,并未处理时区问题,显示的还是格林尼治时间,在浏览器中运行会自动处理,显示的是本地时间,但实际上都是同一个时间。

image-20211126213353579

1. 方式1👉无参构造

得到的是当前的格林尼治标准时间GMT(GreenwichMeanTime)时间,如果要获取当前中国时间需要加8小时时间

let now = new Date()
console.log(now) 
//NodeJs   2021-11-26T14:34:31.531Z
//Edge浏览器     Fri Nov 26 2021 22:34:31 GMT+0800 (中国标准时间)

浏览器中执行时,会显示本地时间,加上8小时时差,下面的测试均在node环境下进行,大家知道这么个意思就行了。

2. 方式2👉Unix时间戳

接收一个时间戳参数,它是一个整数值,表示自纪元时间以来的毫秒数

let epochTime = new Date(0) //获取纪元时间
console.log(epochTime) 
//NodeJs        1970-01-01T00:00:00.000Z
//Edge浏览器     Thu Jan 01 1970 08:00:00 GMT+0800 (中国标准时间)

3. 方式3👉时间戳字符串

参数为表示日期的字符串值,该字符串能被静态方法Date.parse()转换为该日期表示的毫秒数,ECMA-262有一个字符串的书写规范

由于浏览器之间的差异性,强烈不推荐使用这种方式来创建日期对象,仅做一些了解就行,列举几个规范

  • “月/日/年”,如"10/24/2021"

  • “月名 日, 年”,如"October 24, 2021"

  • “周几 月名 日 年 时:分:秒 时区”,如"Sun October 24 2021 00:00:00 GMT+0800"

  • ISO 8601扩展格式“YYYY-MM-DDTHH:mm:ss.sssZ”,如2021-10-24T00:00:00(只适用于

    兼容 ES5 的实现)

🌰举个栗子

console.log(new Date('10/24/2021'))
console.log(new Date(Date.parse('October 24, 2021')))
console.log(new Date('Sun October 24 2021 00:00:00 GMT+0800'))
console.log(new Date('2021-10-24T00:00:00Z'))
//node
/**
2021-10-23T16:00:00.000Z
2021-10-23T16:00:00.000Z
2021-10-23T16:00:00.000Z
2021-10-24T00:00:00.000Z
/

new Date传入当地时间字符串,将得到减去时差的格林尼治时间

4. 方式4👉分别提供日期和时间的每一个成员

Date(year: number, month: number, date?: number, hours?: number, minutes?: number, seconds?: number, ms?: number)

可以看出,年月为必传参数,其余都是可选参数

  • year

    表示年份的整数值。 0到99会被映射至1900年至1999年,其它值代表实际年份

  • month

    表示月份的整数值,从 0(1月)到 11(12月),要注意月份的对应关系

  • date

    默认为1,整数值,表示一个月中的第几天

  • hours

    默认为0,整数值,表示一天中的小时数(24小时制)

  • minutes

    默认为0,整数值,表示分钟部分整数值(0-59)

  • seconds

    默认为0,整数值,表示秒钟部分整数值(0-59)

  • ms

    默认为0,整数值,表示毫秒部分整数值(0-999)

🌰举个栗子

let date1 = new Date(99, 0)
let date2 = new Date(2021, 11, 24, 20, 0, 0, 999)
//node
console.log(date1) //1998-12-31T16:00:00.000Z
console.log(date2) //2021-12-24T12:00:00.999Z

分析一下原因:new Date(99, 0)本来想表示的是当地时间1999年1月1日0时0分0秒,减去8个时区则可以得到格林尼治时间1998年12月31日16:00:00.000。第二个例子也是一样的分析,只是要注意月份表示中,0代表1月份,11代表12月份。

那如果月份我偏不是0-11呢,比如我来个12,13...会是什么情况呢,下面做个测试

let date1 = new Date(99, 11) //1999-12-1-00:00:00.000
let date2 = new Date(99, 12)
let date3 = new Date(99, 13)
let date4 = new Date(99, 14)
//node
console.log('date1: ', date1) //date1:  1999-11-30T16:00:00.000Z
console.log('date2: ', date2) //date2:  1999-12-31T16:00:00.000Z
console.log('date3: ', date3) //date3:  2000-01-31T16:00:00.000Z
console.log('date4: ', date4) //date4:  2000-02-29T16:00:00.000Z

可以看出,即使使用了12以上的月份数,也不会报错,而是继续往后加月份数

这里也有一个对应的静态方法Date.UTC()方法返回日期对应的毫秒数,这个方法接收的参数和第四种构造函数接收的参数是一样的,不过它传入的时间是UTC时间,输出的时间也是对等的utc时间

let date = new Date(Date.UTC(99, 11))
console.log(date) 
//NodeJs       1999-12-01T00:00:00.000Z
//Edge浏览器     Wed Dec 01 1999 08:00:00 GMT+0800 (中国标准时间)

5. Date.now()

Date总共三个静态方法,Date.parse()、Date.UTC()、Date.now()前两个上面已经讲过Date.now()用来获取自纪元时间至今所经过的毫秒数

console.log(Date.now())  //1637939378061

可以利用这个来做一些耗时的测试

//伪代码
let start = Date.now()
//你要测试的代码在这里运行......
let end = Date.now()
//耗时const timeCost = end - start

6. Date()new Date()

两者是不一样的,不加new的不是构造函数,返回值是一个字符串

但是他们是有关系的,看下面的测试

let a = Date()
let b = new Date()
console.log(a) //Fri Nov 26 2021 23:15:23 GMT+0800 (China Standard Time)
console.log(b) //2021-11-26T15:15:23.526Z
console.log(b.toString()) //Fri Nov 26 2021 23:15:23 GMT+0800 (China Standard Time)
console.log(b.toLocaleString()) //Fri Nov 26 2021 23:15:23 GMT+0800 (China Standard Time)

可以看出,Date()其实等价于new Date().toString()

**回过头来,我貌似发现了些什么?浏览器控制台之所以会输出本地时间,应该是调用了时间对象的toString()方法吧!**跟着就来学习他们了...

二、重写的方法

1. toString()toLocaleString()

toString()返回带时区信息的日期和时间,而时间也是以 24 小时制(0~23)表示的

toLocaleString()返回与浏览器运行的本地环境一致的日期和时间。这通常意味着格式中包含针对时间的 AM(上午)或 PM(下午), 但不包含时区信息(具体格式可能因浏览器而不同)

let b = new Date()
console.log(b) //Fri Nov 26 2021 23:32:46 GMT+0800 (中国标准时间)
console.log(b.toString()) //Fri Nov 26 2021 23:32:46 GMT+0800 (中国标准时间)
console.log(b.toLocaleString())
//Edge浏览器中为   2021/11/26 下午11:32:46
//Node环境中为     11/26/2021, 11:32:46 PM

可以看出使用上述方法不管在Node还是Edge浏览器环境都返回了本地时间

2. valueOf()

重写后的该方法返回的是日期的毫秒表示,为一个正整数,因此日期对象可以用于直接比较

let a = new Date(2021, 11, 20)
let b = new Date(2021, 11, 20, 2)
console.log(a < b) //true

三、日期格式化

有几个专门的用于格式化日期的方法,但是这些方法的输出会因浏览器而异,因此不能用于在用户界面上显示日期,可以了解一下toDateString()\toTimeString()\toLocaleDateString()\toLocaleTimeString()toUTCString(),具体就不做演示了,详情可上MDN查阅。

四、其他方法

这里借用红宝书上的一张表,用到的时候查一下就好,主要是获取和设置相关操作

image-20211126234846402

但是!

我们平时很少使用原生Date对象,而是使用它的封装库来进行日期和时间的相关操作。主流的有两个库吧,一个是Day.js,一个是Moment.js,前者超轻量小巧2KB,后者比较重200+,前者可以看成是后者的精华缩小版吧,看喜好食用!🐒

五、封装库Day.js

内置的Date对象还是比较难用的,处理一些简单问题可以,开发中一般使用别人封装好的库来操作会比较方便,所以上面讲的那么多东西还有什么用!?哈哈,原理还是要懂得嘛....

官方文档:Day.js中文网 (fenxianglu.cn)

看看人家的首页还是比较清新耐看的,我啥时候能有这点水平也整一个呢

image-20211126235351761

注意配合Typescript食用的时候有些单独注意事项,具体使用直接看官网就好了,还是比较简单的

日期时间可以说是开发中用的也非常多的数据类型了,还是需要好好掌握的!

创作不易,求个关注或点赞😄😄🤗