Skip to content
56 changes: 28 additions & 28 deletions 1-js/05-data-types/11-date/article.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# 日期和时间

让我一起学习一个新的内建对象:[日期(Date)](mdn:js/Date)。该对象存储日期和时间,并提供了日期/时间的管理方法。
让我们来学习一个新的内建对象:[日期(Date)](mdn:js/Date)。该对象存储日期和时间,并提供了日期/时间的管理方法。

例如,我们可以使用它来存储创建/修改时间,或者用来测量时间,再或者仅用来打印当前时间
我们可以使用它来存储创建/修改时间,测量时间,或者仅用来打印当前时间

## 创建

创建一个新的 `Date` 对象,只需要调用 `new Date()`,在调用时可以带有下面这些参数之一
调用 `new Date()` 来创建一个新的 `Date` 对象。在调用时可以带有一些参数,如下所示

`new Date()`
: 不带参数 —— 创建一个表示当前日期和时间的 `Date` 对象:
Expand Down Expand Up @@ -41,13 +41,13 @@
```

`new Date(datestring)`
: 如果只有一个参数,并且是字符串,那么它会被自动解析。该算法与 `Date.parse` 所使用的算法相同,我们将在下文中进行介绍
: 如果只有一个参数,并且是字符串,那么它会被自动解析。该算法与 `Date.parse` 所使用的算法相同,将在下文中进行介绍

```js run
let date = new Date("2017-01-26");
alert(date);
// 该时间未被设定,因此被假定为格林尼治标准时间(GMT)的午夜(midnight)
// 并会根据你运行代码时的时区进行调整
// 未指定具体时间,所以假定时间为格林尼治标准时间(GMT)的午夜零点
// 并根据运行代码时的用户的时区进行调整
// 因此,结果可能是
// Thu Jan 26 2017 11:00:00 GMT+1100 (Australian Eastern Daylight Time)
// 或
Expand Down Expand Up @@ -93,7 +93,7 @@
: 获取相应的时间组件。

```warn header="不是 `getYear()`,而是 `getFullYear()`"
很多 JavaScript 引擎都实现了一个非标准化的方法 `getYear()`。不推荐使用这个方法。它有时候可能会返回 2 位的年份信息。永远都不要使用它。要获取年份就使用 `getFullYear()`。
很多 JavaScript 引擎都实现了一个非标准化的方法 `getYear()`。不推荐使用这个方法。它有时候可能会返回 2 位的年份信息。永远不要使用它。要获取年份就使用 `getFullYear()`。
```

另外,我们还可以获取一周中的第几天:
Expand Down Expand Up @@ -175,7 +175,7 @@ alert(date); // ……是 1st Feb 2013!

超出范围的日期组件将会被自动分配。

假设我们要在日期 "28 Feb 2016" 上加 2 天。结果可能是 "2 Mar" 或 "1 Mar",因为存在闰年。但是我们不需要去考虑这些,只需要直接加 2 天,剩下的 `Date` 对象会帮我们处理:
假设我们要在日期 "28 Feb 2016" 上加 2 天。结果可能是 "2 Mar" 或 "1 Mar",因为存在闰年。但是我们不需要考虑这些,只需要直接加 2 天,剩下的 `Date` 对象会帮我们处理:

```js run
let date = new Date(2016, 1, 28);
Expand Down Expand Up @@ -239,7 +239,7 @@ alert( `The loop took ${end - start} ms` );

有一个特殊的方法 `Date.now()`,它会返回当前的时间戳。

它相当于 `new Date().getTime()`,但它不会创建中间的 `Date` 对象。因此它更快,而且不会对垃圾处理造成额外的压力
它相当于 `new Date().getTime()`,但它不会创建中间的 `Date` 对象。因此它更快,而且不会对垃圾回收造成额外的压力

这种方法很多时候因为方便,又或是因性能方面的考虑而被采用,例如使用 JavaScript 编写游戏或其他的特殊应用场景。

Expand All @@ -262,13 +262,13 @@ let end = Date.now(); // 完成
alert( `The loop took ${end - start} ms` ); // 相减的是时间戳,而不是日期
```

## 度量(Benchmarking)
## 基准测试(Benchmarking)

如果我们想要为一个很耗 CPU 性能的函数提供一个可靠的度量(benchmark),我们应该小心一点
在对一个很耗 CPU 性能的函数进行可靠的基准测试(Benchmarking)时,我们需要谨慎一点

例如,我们想判断两个计算日期差值的函数:哪个更快?
例如,我们想判断以下两个计算日期差值的函数:哪个更快?

这种性能测量通常称为“度量(benchmark)”。
这种性能测量通常称为“基准测试(benchmark)”。

```js
// 我们有 date1 和 date2,哪个函数会更快地返回两者的时间差?
Expand All @@ -282,11 +282,11 @@ function diffGetTime(date1, date2) {
}
```

这两个函数做的事情完全相同,但是其中一个函数使用显性的 `date.getTime()` 来获取毫秒形式的日期,另一个则依赖于“日期 — 数字”的转换。它们的结果是一样的。
这两个函数做的事情完全相同,但是其中一个函数使用显式的 `date.getTime()` 来获取毫秒形式的日期,另一个则依赖于“日期 — 数字”的转换。它们的结果是一样的。

那么,哪个更快呢?

首先想到的方法可能是连续运行它们很多次,并计算时间差。就我们的例子而言,函数非常简单,所以我们必须执行至少 100000 次。
首先想到的方法可能是连续运行两者很多次,并计算所消耗的时间之差。就这个例子而言,函数过于简单,所以我们必须执行至少 100000 次。

让我们开始测量:

Expand All @@ -312,15 +312,15 @@ alert( 'Time of diffSubtract: ' + bench(diffSubtract) + 'ms' );
alert( 'Time of diffGetTime: ' + bench(diffGetTime) + 'ms' );
```

哇!使用 `getTime()` 这种方式快得多!原因是它没有类型转化,这样对引擎优化来说更加简单
看起来使用 `getTime()` 这种方式快得多,这是因为它没有进行类型转换,对引擎优化来说更加简单

好,我们得到了结论,但是这并不是一个很好的度量的例子。
我们得到了结论,但是这并不是一个很好的度量的例子。

想象一下当运行 `bench(diffSubtract)` 的同时,CPU 还在并行处理其他事务,并且这也会占用资源。然而,运行 `bench(diffGetTime)` 的时候,并行处理的事务完成了。

这是对于现代多进程操作系统来说的一个非常真实的场景
对于现代多进程操作系统来说,这是一个非常常见的场景

结果就是,第一个函数相比于第二个函数,缺少 CPU 资源。这可能导致错误的结论。
比起第二个函数,第一个函数所能使用的 CPU 资源更少。这可能导致错误的结论。

**为了得到更加可靠的度量,整个度量测试包应该重新运行多次。**

Expand Down Expand Up @@ -359,10 +359,10 @@ alert( 'Total time for diffSubtract: ' + time1 );
alert( 'Total time for diffGetTime: ' + time2 );
```

现代的 JavaScript 引擎的先进优化策略只对执行很多次的 "hot code" 有效(对于执行很少次数的代码没有必要优化)。因此,在上面的例子中,第一次执行的优化程度不高。我们可能需要增加一个升温步骤
现代的 JavaScript 引擎的先进优化策略只对执行很多次的 "hot code" 有效(对于执行很少次数的代码没有必要优化)。因此,在上面的例子中,第一次执行的优化程度不高。我们可能需要增加一个预热步骤

```js
// 在主循环中增加“升温”环节
// 在主循环中增加预热环节
bench(diffSubtract);
bench(diffGetTime);

Expand All @@ -373,13 +373,13 @@ for (let i = 0; i < 10; i++) {
}
```

```warn header="进行微度量测试时要小心"
现代的 JavaScript 引擎执行了很多优化。与“正常使用”相比,它们可能会改变“人为测试”的结果,特别是在我们对很细微的东西进行度量测试时,例如 operator 的工作方式或内建函数。因此,如果你想好好了解一下性能,请学习 JavaScript 引擎的工作原理。在那之后,你可能再也不需要微度量了
```warn header="进行微型基准测试时要小心"
现代的 JavaScript 引擎执行了很多优化。与正常编写的代码相比,它们可能会改变“人为编写的专用于测试的代码”的执行流程,特别是在我们对很小的代码片段进行基准测试时,例如某个运算符或内建函数的工作方式。因此,为了深入理解性能问题,请学习 JavaScript 引擎的工作原理。在那之后,你或许再也不需要进行微型基准测试了

关于 V8 引擎的大量文章,可以在 <http://mrale.ph> 找到
<http://mrale.ph> 提供了很多 V8 引擎相关的文章
```

## 对一个字符串使用 Date.parse
## 对字符串调用 Date.parse

[Date.parse(str)](mdn:js/Date/parse) 方法可以从一个字符串中读取日期。

Expand Down Expand Up @@ -412,10 +412,10 @@ alert(date);

## 总结

- 在 JavaScript 中,日期和时间使用 [Date](mdn:js/Date) 对象来表示。我们不能只创建日期,或者只创建时间,`Date` 对象总是同时创建两者。
- 在 JavaScript 中,日期和时间使用 [Date](mdn:js/Date) 对象来表示。我们不能单独创建日期或时间,`Date` 对象总是同时创建两者。
- 月份从 0 开始计数(对,一月是 0)。
- 一周中的某一天 `getDay()` 同样从 0 开始计算(0 代表星期日)。
- 当设置了超出范围的组件时,`Date` 会进行自我校准。这一点对于日/月/小时的加减很有用。
- 当设置了超出范围的组件时,`Date` 会进行自动校准。这一点对于日/月/小时的加减很有用。
- 日期可以相减,得到的是以毫秒表示的两者的差值。因为当 `Date` 被转换为数字时,`Date` 对象会被转换为时间戳。
- 使用 `Date.now()` 可以更快地获取当前时间的时间戳。

Expand All @@ -430,4 +430,4 @@ alert(`Loading started ${performance.now()}ms ago`);
// 小数点后超过 3 位的数字是精度错误,只有前三位数字是正确的
```

Node.js `microtime` 模块以及其他方法。从技术上讲,几乎所有的设备和环境都允许获取更高精度的数值,只是不是通过 `Date` 对象。
Node.js 可以通过 `microtime` 模块或使用其他方法。从技术上讲,几乎所有的设备和环境都允许获取更高精度的时间数值,只不过不是使用 `Date` 对象。