上周,业务报了个 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]]]]])
- 至少需要输入
year
和monthIndex
两个参数 - 其他缺省值的默认值:
day
为1
,其他为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
- Let now be the Number that is the time value(UTC) identifying the current time.
- Return ToDateString(now).
各浏览器实现上有哪些差异?
dayjs 源码
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。