面向 impatient programmers 的 JavaScript 指南 (ES2022 版)
请支持本书:购买捐赠
(广告,请勿屏蔽。)

44 日期 (Date)



本章介绍 JavaScript 中用于处理日期的 API——Date 类。

44.1 最佳实践:避免使用内置的 Date

JavaScript Date API 使用起来很麻烦。因此,最好依靠库来处理与日期相关的任何事情。流行的库包括:

有关这些库的优缺点,请参阅博客文章 “为什么你不应该使用 Moment.js……”

此外,TC39 正在为 JavaScript 开发一个新的日期 API:temporal

44.1.1 在日期库中需要寻找的内容

有两件事很重要,需要牢记:

44.2 时间标准

44.2.1 背景:UTC 与 Z 与 GMT

UTC、Z 和 GMT 是指定时间的几种方式,它们相似但又略有不同:

资料来源:

44.2.2 日期不支持时区

日期支持以下时间标准:

根据操作的不同,只有部分选项可用。例如,将日期转换为字符串或提取时间单位(如月份中的日期)时,只能在本地时区和 UTC 之间进行选择。

在内部,日期存储为 UTC。从本地时区转换或转换为本地时区时,必要的偏移量由日期确定。在以下示例中,本地时区为欧洲/巴黎:

// CEST (Central European Summer Time)
assert.equal(
  new Date('2122-06-29').getTimezoneOffset(), -120);
  
// CET (Central European Time)
assert.equal(
  new Date('2122-12-29').getTimezoneOffset(), -60);

每当创建或转换日期时,都需要注意所使用的时间标准——例如:new Date() 使用本地时区,而 .toISOString() 使用 UTC。

> new Date(2077, 0, 27).toISOString()
'2077-01-26T23:00:00.000Z'

日期将 0 解释为 1 月。月份中的日期在本地时区为 27 日,但在 UTC 中为 26 日。

  记录每个操作支持的时间标准

在本章的其余部分,将为每个操作注明支持的时间标准。

44.2.2.1 无法指定时区的缺点

无法指定时区有两个缺点:

44.3 背景:日期时间格式 (ISO)

日期时间格式描述:

以下是 .toISOString() 返回的日期时间字符串示例:

'2033-05-28T15:59:59.123Z'

日期时间格式具有以下结构:

我们可以指定相对于 UTC 的时间偏移量,而不是 Z(即 UTC+0):

44.3.1 提示:追加 Z 使日期解析确定性

如果在字符串末尾添加 Z,日期解析在不同位置不会产生不同的结果:

44.4 时间值

时间值 通过自 1970 年 1 月 1 日 00:00:00 UTC 以来的毫秒数来表示日期。

时间值可用于创建日期:

const timeValue = 0;
assert.equal(
  new Date(timeValue).toISOString(),
  '1970-01-01T00:00:00.000Z');

将日期强制转换为数字会返回其时间值:

> Number(new Date(123))
123

排序运算符会将其操作数强制转换为数字。因此,可以使用这些运算符来比较日期:

assert.equal(
  new Date('1972-05-03') < new Date('2001-12-23'), true);

// Internally:
assert.equal(73699200000 < 1009065600000, true);

44.4.1 创建时间值

以下方法创建时间值:

44.4.2 获取和设置时间值

44.5 创建日期

44.5.1 通过数字创建日期

new Date(year: number, month: number, date?: number, hours?: number, minutes?: number, seconds?: number, milliseconds?: number)(本地时区)

其中两个参数存在陷阱:

示例:

> new Date(2077,0,27, 21,49).toISOString() // CET (UTC+1)
'2077-01-27T20:49:00.000Z'

请注意,输入小时数 (21) 与输出小时数 (20) 不同。前者指的是本地时区,后者指的是 UTC。

44.5.2 从字符串解析日期

new Date(dateTimeStr: string)(本地时区、UTC、时间偏移量)

如果末尾有 Z,则使用 UTC:

> new Date('2077-01-27T00:00Z').toISOString()
'2077-01-27T00:00:00.000Z'

如果末尾没有 Z 或时间偏移量,则使用本地时区:

> new Date('2077-01-27T00:00').toISOString() // CET (UTC+1)
'2077-01-26T23:00:00.000Z'

如果字符串只包含日期,则将其解释为 UTC:

> new Date('2077-01-27').toISOString()
'2077-01-27T00:00:00.000Z'

44.5.3 创建日期的其他方法

44.6 获取器和设置器

44.6.1 时间单位获取器和设置器

日期具有用于时间单位的获取器和设置器——例如:

这些获取器和设置器符合以下模式:

以下是支持的时间单位:

还有一个获取器不符合前面提到的模式:

44.7 将日期转换为字符串

示例日期:

const d = new Date(0);

44.7.1 包含时间的字符串

44.7.2 包含日期的字符串

44.7.3 包含日期和时间的字符串

44.7.4 其他方法

以下三种方法实际上不属于 ECMAScript,而是属于 ECMAScript 国际化 API。该 API 具有许多用于格式化日期的功能(包括对时区的支持),但没有用于解析日期的功能。

  练习:创建日期字符串

exercises/dates/create_date_string_test.mjs