## 40.日期(`Date`)
> 原文: [http://exploringjs.com/impatient-js/ch_dates.html](http://exploringjs.com/impatient-js/ch_dates.html)
>
> 贡献者:[facebesidewyj](https://github.com/facebesidewyj)
本章介绍 JavaScript 用于处理日期的 API - `Date`。
### 40.1。最佳实践:不要使用当前的内置 API
JavaScript `Date` API 使用起来很麻烦。因此,最好依靠第三方库来处理与日期相关的任何事情。热门第三方库包括:
* [Moment.js](https://momentjs.com)
* [Day.js](https://github.com/iamkun/dayjs)
* [Luxon](https://moment.github.io/luxon/)
* [js-joda](https://js-joda.github.io/js-joda/)
* [date-fns](https://github.com/date-fns/date-fns)
请参阅博客文章[“为什么你不应该使用 Moment.js ......”](https://inventi.studio/en/blog/why-you-shouldnt-use-moment-js)了解这些第三方库的优缺点。
此外,TC39(技术委员会(Technical Committee)第 39 号,它是 ECMA 的一部分,ECMA 是 “ECMAScript” 规范下的 JavaScript 语言标准化的机构。) 正在开发 JavaScript 的新日期 API: [`temporal`](https://github.com/maggiepint/proposal-temporal) 。
#### 41.1.1。一些要在日期库中寻找的内容
要记住两件很重要的事:
* [`Tree-shaking`](https://webpack.docschina.org/guides/tree-shaking/) 可以帮助减少库的大小,是一种仅将库的导出部署到Web服务器的技术,可以在某处导入。Tree-shaking对函数的影响比类更大。
* 支持时区:Date对象默认不支持时区,这会带来一些问题并且这是一个关键的弱点。确保您的日期库支持时区。
### 40.2。时区
#### 41.2.1。背景:UTC与GMT
UTC(协调世界时)和 GMT(格林威治标准时间)具有相同的当前时间,但它们是不同的东西:
* UTC:是所有时区所基于的时间标准。它们是相对于它指定的。也就是说,没有状态或地区将 UTC 作为其本地时区。
* GMT:是一些欧洲和非洲国家使用的时区。它是UTC加零小时,因此与UTC的时间相同。
资料来源:[“TimeTndDate.com 上的 GMT 和 UTC 之间的差异”](https://www.timeanddate.com/time/gmt-utc-time.html)
#### 41.2.2。JavaScript日期对象仅支持UTC和本地时区
我们无法为JavaScript日期指定任意时区。
它使用两个时间系统:
* UTC(协调世界时)
* 本地时区(从操作系统自动获取)
Date实例将其时间存储在UTC中。无论何时在日期和其他数据之间进行转换,我们都需要注意是否使用了UTC或本地时区。例如:`new Date()`使用本地时区,而`.toISOString()`使用UTC
```javascript
new Date(2077, 0, 27).toISOString()
'2077-01-26T23:00:00.000Z'
```
JavaScript日期对象将0解释为1月。本地时区的当月是27日,但UTC是26日。
> 日期操作:UTC与本地时区
>
> 对于本章中记录的每个操作,它在日期和其他数据之间进行转换,请注意是使用UTC还是本地时区。
#### 41.2.3 无法指定时区的缺点
无法指定时区,存在两个问题:
* 无法支持多个时区。
* 可能导致特定位置的bug。例如,前面的示例会根据执行的位置生成不同的结果。在这种特殊情况下,输入为CET,而输出则是UTC。这就是为什么这个月的日期不同(27对26)。
### 40.3。背景:日期时间格式(ISO)
日期时间格式描述:
* 接受的字符串:
* `Date.parse()`
* `new Date()`
* 返回的字符串(总是最长的格式):
* `Date.prototype.toISOString()`
以下是`.toISOString()`返回的日期时间字符串的示例:
```js
'2033-05-28T15:59:59.123Z'
```
日期时间格式具有以下结构:
* 日期格式:Y =年份; M =月; d =天
```js
YYYY-MM-DD
YYYY-MM
YYYY
```
* 时间格式:T =分隔符(字符串`'T'`); H =小时; M =分钟; s =秒和毫秒; Z =时区是 UTC(字符串`'Z'`)
```js
THH:mm:ss.sss
THH:mm:ss.sssZ
THH:mm:ss
THH:mm:ssZ
THH:mm
THH:mmZ
```
* 日期时间格式:日期格式后跟时间格式。
* 例如(最长):`YYYY-MM-DDTHH:mm:ss.sssZ`
`Z`的替代方案 - 相对于 UTC 的时区:
* `+hh:mm`
* `-hh:mm`
### 40.4。时间值
_ 时间值 _ 表示自 1970 年 1 月 1 日 00:00:00 UTC 以来的毫秒数的日期。
时间值可用于创建日期:
```js
const timeValue = 0;
assert.equal(
new Date(timeValue).toISOString(),
'1970-01-01T00:00:00.000Z');
```
将日期强制转换为数字会返回其时间值:
```js
> Number(new Date(123))
123
```
比较运算符将他们的操作数强制转换为数字。因此,您可以使用这些运算符来比较日期:
```js
assert.equal(new Date('1972-05-03') < new Date('2001-12-23'), true);
// Internally:
assert.equal(73699200000 < 1009065600000, true);
```
#### 40.4.1。创建时间值
以下方法创建时间值:
* `Date.now(): number`
返回当前时间作为时间值。
* `Date.parse(dateTimeString): number`(当地时区)
解析`dateTimeString`并返回相应的时间值。
* `Date.UTC(year, month, date?, hours?, minutes?, seconds?, milliseconds?): number`
返回指定的 UTC 日期时间的时间值。
#### 40.4.2。获取和设置时间值
* `Date.prototype.getTime(): number`
返回与 Date 对应的时间值。
* `Date.prototype.setTime(timeValue)`
将`this`设置为`timeValue`编码的日期。
### 40.5。创建日期
* `new Date(year: number, month: number, date?: number, hours?: number, minutes?: number, seconds?: number, milliseconds?: number)`(当地时区)
```js
> new Date(2077,0,27, 21,49,58, 888).toISOString() // CET (UTC+1)
'2077-01-27T20:49:58.888Z'
```
* `new Date(dateTimeStr: string)`(UTC)
```js
> new Date('2077-01-27').toISOString()
'2077-01-27T00:00:00.000Z'
```
* `new Date(timeValue: number)`
```js
> new Date(0).toISOString()
'1970-01-01T00:00:00.000Z'
```
* `new Date()`(与`new Date(Date.now())`相同)
#### 41.5.1 构造函数的陷阱
`new Date()`的构造函数会产生两个问题:
* 对于month,0是一月
* 如果0≤year≤99,则为1900+yaer
```js
> new Date(12, 1, 22, 19, 11).getFullYear()
1912
```
这就是为什么,在本章的其他地方,我们总是使用时间单位fullYear。但在这种情况下,我们别无选择。
### 40.6。Getters 和 Setters
#### 40.6.1。时间单位Getters和Setters
日期有时间单位的 getter 和 setter。例如:
* `Date.prototype.getFullYear()`
* `Date.prototype.setFullYear(num)`
这些 getter 和 setter 符合以下模式:
* 当地时间:
* `Date.prototype.get«Unit»()`
* `Date.prototype.set«Unit»(num)`
* 世界时间:
* `Date.prototype.getUTC«Unit»()`
* `Date.prototype.setUTC«Unit»(num)`
这些是支持的时间单位:
* 日期
* `FullYear`
* `Month`:月(0-11)。 **陷阱:** 0 是 1 月等
* `Date`:每月的某一天(1-31)
* `Day`(仅限吸气剂):星期几(0-6); 0 是星期天
* 时间
* `Hours`:小时(0-23)
* `Minutes`:分钟(0-59)
* `Seconds`:秒(0-59)
* `Milliseconds`:毫秒(0-999)
还有一个getter不符合前面提到的模式:
* `Date.prototype.getTimezoneOffset()`
返回本地时间和 UTC 之间的时差,以分钟为单位。例如,对于 CET,它返回`-60`。
### 40.7。将日期转换为字符串
示例日期:
```js
const d = new Date(0);
```
#### 40.7.1。带时间的字符串
* `Date.prototype.toTimeString()`(当地时区)
```js
> d.toTimeString()
'01:00:00 GMT+0100 (Central European Standard Time)'
```
* `Date.prototype.toLocaleTimeString()`(参见 [ECMAScript 国际化 API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl) )
#### 40.7.2。带日期的字符串
* `Date.prototype.toDateString()`(当地时区)
```js
> d.toDateString()
'Thu Jan 01 1970'
```
* `Date.prototype.toLocaleDateString()`( [ECMAScript 国际化 API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl) )
#### 40.7.3。带有日期和时间的字符串
* `Date.prototype.toString()`(当地时区)
```js
> d.toString()
'Thu Jan 01 1970 01:00:00 GMT+0100 (Central European Standard Time)
```
* `Date.prototype.toLocaleString()`(参见 [ECMAScript 国际化 API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl) )
* `Date.prototype.toUTCString()`(UTC)
```js
> d.toUTCString()
'Thu, 01 Jan 1970 00:00:00 GMT'
```
* `Date.prototype.toISOString()`(UTC)
```js
> d.toISOString()
'1970-01-01T00:00:00.000Z'
```
![](https://img.kancloud.cn/3e/d5/3ed5755d562179ae6c199264f5e21157.svg) **练习:创建日期字符串**
`exercises/dates/create_date_string_test.js`
- I.背景
- 1.关于本书(ES2019 版)
- 2.常见问题:本书
- 3. JavaScript 的历史和演变
- 4.常见问题:JavaScript
- II.第一步
- 5.概览
- 6.语法
- 7.在控制台上打印信息(console.*)
- 8.断言 API
- 9.测验和练习入门
- III.变量和值
- 10.变量和赋值
- 11.值
- 12.运算符
- IV.原始值
- 13.非值undefined和null
- 14.布尔值
- 15.数字
- 16. Math
- 17. Unicode - 简要介绍(高级)
- 18.字符串
- 19.使用模板字面值和标记模板
- 20.符号
- V.控制流和数据流
- 21.控制流语句
- 22.异常处理
- 23.可调用值
- VI.模块化
- 24.模块
- 25.单个对象
- 26.原型链和类
- 七.集合
- 27.同步迭代
- 28.数组(Array)
- 29.类型化数组:处理二进制数据(高级)
- 30.映射(Map)
- 31. WeakMaps(WeakMap)
- 32.集(Set)
- 33. WeakSets(WeakSet)
- 34.解构
- 35.同步生成器(高级)
- 八.异步
- 36. JavaScript 中的异步编程
- 37.异步编程的 Promise
- 38.异步函数
- IX.更多标准库
- 39.正则表达式(RegExp)
- 40.日期(Date)
- 41.创建和解析 JSON(JSON)
- 42.其余章节在哪里?