上周,业务报了个 IE 兼容性的 bug,原本想据理力争,当初项目定位只要求兼容 chrome 。但产品说,业务很多人都用的 IE,有用户习惯在。而这个 bug 呢,就是日期格式化传字符串导致的兼容性问题。做移动端项目用 safari 的时候遇到过,这次是 IE。被一个问题坑了两次,真是不应该。

阅读清单

为什么是要读清单中的三条链接?

MDN 上的文章,语言通俗易懂,并提供了典型示例帮助阅读者更好的理解,是很好的入门文档。

如果你需要深入了解更精准的定义,更完整的实现细节,则建议阅读下 ECMAScript 官方标准

最后,了解 dayjs 是来补充前者没有涉及的实战内容:处理浏览器兼容性;已有 API 之外更多实用的方法和技巧。

阅读前提问

  • Date 可以表示任意时间吗?
  • Date 构造函数如何重载?
  • Date()new Date() 的区别?
  • 各浏览器实现上有哪些差异?

相关概念

  • 世界时 GMT
  • 国际原子时 TAI
  • 协调世界时 UTC
  • 闰秒 leap seconds
  • unix epoch
  • 时间戳 timestamps

世界时 GMT

世界时、格林尼治平太阳时间,是指格林尼治所在地的标准时间。以地球自转为基础的时间计量系统。

国际原子时 TAI

一个高精度的原子坐标时间标准,基于地球上的大地水准上的固有时间。针对某些元素的原子能级跃迁频率有极高的稳定性,可采用基于铯原子(Cs 132.9)的能级跃迁原子秒作为时标。

协调世界时 UTC

UTC 是以原子时秒长为基础,在时刻上尽量接近于 GMT 的一种时间计量系统。

TAI 的准确度为每日数纳秒,而 GMT 的准确度为每日数毫秒。许多应用部门要求时间系统接近 GMT,一种称为 UTC 的折衷时标于1972年面世。

闰秒 leap seconds

为确保 UTC 与 GMT 相差不会超过0.9秒,在有需要的情况下会在 UTC 内加上正或负闰秒。一般会在每年的6月30日、12月31日的最后一秒进行调整。

JavaScript 忽略闰秒。

unix epoch

unix 纪元。即,1970-01-01 UTC

时间戳 timestamps

the number of milliseconds that have elapsed since midnight on January 1, 1970, UTC.

常用语法

构造函数

无参数

新创建的日期对象表示实例化时的当前日期和时间。

new Date()          // Date Object
new Date(undefined) // Invalid Date

时间戳字符串

各浏览器实现存在差异,小心使用。支持一下两种格式的字符串:

  • RFC 2822 格式,例如2020/02/02,表示本地时间,这并不是官方标准要求支持的格式,而是 convention only
  • 简化版 ISO 8601 格式,例如2020-02-02T00:00:00.000Z,ES 标准中对此标准做了简化,并未支持全部的格式。注意,年份只支持4位或者6位的格式,具体见标准。

查阅了 ES文档,直到 ES5 才引入了标准的字符串格式的规范,ES3 中并未提及,ES5 发布于 2009 年,IE8 同年也发布了第一个版本,因此猜测这就是为什么 IE 9+ 才支持的原因。

new Date(2020, 1, 2)
// Sun Feb 02 2020 00:00:00 GMT+0800 (中国标准时间)

new Date('2020/02/02')
// RFC 2822 => Sun Feb 02 2020 00:00:00 GMT+0800 (中国标准时间)

new Date('2020-02-02T00:00:00.000Z')
// ISO 8601 => Sun Feb 02 2020 08:00:00 GMT+0800 (中国标准时间)

new Date('2020T00:00')
// ISO 8601 => Wed Jan 01 2020 00:00:00 GMT+0800 (中国标准时间)

其他

new Date(year, monthIndex [, day [, hours [, minutes [, seconds [, milliseconds]]]]])
  • 至少需要输入 yearmonthIndex 两个参数
  • 其他缺省值的默认值:day1,其他为 0
  • year 取值如果在 0-99,则对应的实际值为 1900-1999
  • monthIndex 参数名直观的说明,是一个索引值,从 0 开始

阅读后答疑

Date 可以表示任意时间吗?

Date 对象的范围是 UTC 1970,1,1 前后一百万天,即:公元前271821-04-20 至公元 275760-09-13。

var oneMillionDays = 100000000 * 24 * 60 * 60 * 1000
var max = new Date(oneMillionDays)
var min = new Date(-oneMillionDays)

console.log(max.toString(), min.toString(), max.toUTCString(), min.toUTCString())

// chrome 80.0.3987.149(正式版本) (64 位)

// Sat Sep 13 275760 08:00:00 GMT+0800 (中国标准时间) 
// Tue Apr 20 -271821 08:05:43 GMT+0805 (中国标准时间) 
// Sat, 13 Sep 275760 00:00:00 GMT 
// Tue, 20 Apr -271821 00:00:00 GMT

// IE Edge

// Sat Sep 13 275760 08:00:00 GMT+0800 (中国标准时间) 
// Tue Apr 20 -271821 08:00:00 GMT+0800 (中国标准时间) 
// Sat, 13 Sep 275760 00:00:00 GMT 
// Tue, 20 Apr 271822 B.C. 00:00:00 GMT

// IE 9/10

// Sat Sep 13 08:00:00 UTC+0800 275760 
// Tue Apr 20 08:00:00 UTC+0800 271822 B.C. 
// Sat, 13 Sep 275760 00:00:00 UTC 
// Tue, 20 Apr 271822 B.C. 00:00:00 UTC

// IE 5/7/8

// Sat Sep 13 275760 08:00:00 GMT+0800 
// Tue Apr 20 -271821 08:00:00 GMT+0800 
// Sat, 13 Sep 275760 00:00:00 GMT 
// Tue, 20 Apr -271821 00:00:00 GMT

var maxAdd1 = new Date(oneMillionDays + 1)
var minAdd1 = new Date(-oneMillionDays - 1)

console.log(maxAdd1, minAdd1, maxAdd1.toUTCString(), minAdd1.toUTCString())

// chrome 80.0.3987.149(正式版本) (64 位)
// IE Edge/10/9

// Invalid Date
// Invalid Date
// Invalid Date
// Invalid Date

// IE 5/7/8

// undefined undefined NaN NaN NaN:NaN:NaN GMT+NaNNaN 
// undefined undefined NaN NaN NaN:NaN:NaN GMT+NaNNaN 
// undefined, NaN undefined NaN NaN:NaN:NaN GMT 
// undefined, NaN undefined NaN NaN:NaN:NaN GMT

注意,chrome 里面显示的是 Tue Apr 20 -271821 08:05:43 GMT+0805,为什么会出现 +0805 呢?因为1901年之前,上海时间是+8:05:43的,直到1901年之后,切换为真正的东八区

Date 构造函数如何重载?

new Date()
new Date(value)
new Date(dateString)
new Date(year, monthIndex [, day [, hours [, minutes [, seconds [, milliseconds]]]]])

Date 构造函数支持多种形式的入参,MDN 文档的书写的顺序,并非标准里描述的重载顺序。具体实现见 Date constructor

Date()new Date() 的区别?

If NewTarget is undefined, then

  1. Let now be the Number that is the time value(UTC) identifying the current time.
  2. Return ToDateString(now).

各浏览器实现上有哪些差异?

dayjs 源码

参考


siwuxie
528 声望67 粉丝

404