Date
)Date
Z
使日期解析确定性本章介绍 JavaScript 中用于处理日期的 API——Date
类。
Date
JavaScript Date
API 使用起来很麻烦。因此,最好依靠库来处理与日期相关的任何事情。流行的库包括:
有关这些库的优缺点,请参阅博客文章 “为什么你不应该使用 Moment.js……”。
此外,TC39 正在为 JavaScript 开发一个新的日期 API:temporal
。
有两件事很重要,需要牢记:
摇树优化 可以大大减少库的大小。这是一种只将库中被某个地方导入的导出部署到 Web 服务器的技术。函数比类更适合摇树优化。
对时区的支持:如后文所述,Date
不支持时区,这会导致许多陷阱,是一个关键弱点。确保你的日期库支持它们。
UTC、Z 和 GMT 是指定时间的几种方式,它们相似但又略有不同:
UTC(协调世界时)是所有时区都基于的时间标准。它们是相对于 UTC 指定的。也就是说,没有哪个国家或地区使用 UTC 作为其本地时区。
Z(祖鲁时区)是一个军事时区,在航空和军队中经常使用,是 UTC+0 的另一个名称。
GMT(格林尼治标准时间)是一些欧洲和非洲国家使用的时区。它是 UTC 加上零小时,因此与 UTC 时间相同。
资料来源:
日期支持以下时间标准:
根据操作的不同,只有部分选项可用。例如,将日期转换为字符串或提取时间单位(如月份中的日期)时,只能在本地时区和 UTC 之间进行选择。
在内部,日期存储为 UTC。从本地时区转换或转换为本地时区时,必要的偏移量由日期确定。在以下示例中,本地时区为欧洲/巴黎:
// CEST (Central European Summer Time)
.equal(
assertnew Date('2122-06-29').getTimezoneOffset(), -120);
// CET (Central European Time)
.equal(
assertnew 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 日。
记录每个操作支持的时间标准
在本章的其余部分,将为每个操作注明支持的时间标准。
无法指定时区有两个缺点:
它使得支持多个时区变得不可能。
它可能导致特定于位置的错误。例如,前面的示例会根据执行位置的不同产生不同的结果。为了安全起见:
Z
或时间偏移量(有关详细信息,请参阅下一节)。日期时间格式描述:
Date.parse()
new Date()
Date.prototype.toISOString()
以下是 .toISOString()
返回的日期时间字符串示例:
'2033-05-28T15:59:59.123Z'
日期时间格式具有以下结构:
日期格式:Y=年;M=月;D=日
YYYY-MM-DD
YYYY-MM
YYYY
时间格式:T=分隔符(字符串 'T'
);H=小时;m=分钟;s=秒和毫秒;Z=祖鲁时区(字符串 'Z'
)
THH:mm:ss.sss
THH:mm:ss.sssZ
THH:mm:ss
THH:mm:ssZ
THH:mm
THH:mmZ
日期时间格式:是日期格式后跟时间格式。
YYYY-MM-DDTHH:mm:ss.sssZ
我们可以指定相对于 UTC 的时间偏移量,而不是 Z
(即 UTC+0):
THH:mm+HH:mm
(等等)THH:mm-HH:mm
(等等)Z
使日期解析确定性如果在字符串末尾添加 Z
,日期解析在不同位置不会产生不同的结果:
没有 Z
:输入为 1 月 27 日(欧洲/巴黎时区),输出为 1 月 26 日(UTC)。
> new Date('2077-01-27T00:00').toISOString()'2077-01-26T23:00:00.000Z'
使用 Z
:输入为 1 月 27 日,输出为 1 月 27 日。
> new Date('2077-01-27T00:00Z').toISOString()'2077-01-27T00:00:00.000Z'
时间值 通过自 1970 年 1 月 1 日 00:00:00 UTC 以来的毫秒数来表示日期。
时间值可用于创建日期:
const timeValue = 0;
.equal(
assertnew Date(timeValue).toISOString(),
'1970-01-01T00:00:00.000Z');
将日期强制转换为数字会返回其时间值:
> Number(new Date(123))123
排序运算符会将其操作数强制转换为数字。因此,可以使用这些运算符来比较日期:
.equal(
assertnew Date('1972-05-03') < new Date('2001-12-23'), true);
// Internally:
.equal(73699200000 < 1009065600000, true); assert
以下方法创建时间值:
Date.now(): number
(UTC)
以时间值的形式返回当前时间。
Date.parse(dateTimeStr: string): number
(本地时区、UTC、时间偏移量)
解析 dateTimeStr
并返回相应的时间值。
Date.UTC(year, month, date?, hours?, minutes?, seconds?, milliseconds?): number
(UTC)
返回指定 UTC 日期时间的时间值。
Date.prototype.getTime(): number
(UTC)
返回与日期相对应的时间值。
Date.prototype.setTime(timeValue)
(UTC)
将 this
设置为 timeValue
编码的日期。
new Date(year: number, month: number, date?: number, hours?: number, minutes?: number, seconds?: number, milliseconds?: number)
(本地时区)
其中两个参数存在陷阱:
对于 month
,0 为 1 月,1 为 2 月,依此类推。
如果 0 ≤ year
≤ 99,则添加 1900。
> new Date(12, 1, 22, 19, 11).getFullYear()1912
这就是为什么在本章的其他地方,我们避免使用时间单位 year
,而始终使用 fullYear
。但在这种情况下,我们别无选择。
示例:
> new Date(2077,0,27, 21,49).toISOString() // CET (UTC+1)'2077-01-27T20:49:00.000Z'
请注意,输入小时数 (21) 与输出小时数 (20) 不同。前者指的是本地时区,后者指的是 UTC。
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'
new Date(timeValue: number)
(UTC)
> new Date(0).toISOString()'1970-01-01T00:00:00.000Z'
new Date()
(UTC)
与 new Date(Date.now())
相同。
日期具有用于时间单位的获取器和设置器——例如:
Date.prototype.getFullYear()
Date.prototype.setFullYear(num)
这些获取器和设置器符合以下模式:
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)还有一个获取器不符合前面提到的模式:
Date.prototype.getTimezoneOffset()
以分钟为单位返回本地时区与 UTC 之间的时间差。例如,对于欧洲/巴黎,它返回 -120
(CEST,欧洲中部夏令时)或 -60
(CET,欧洲中部时间):
> new Date('2122-06-29').getTimezoneOffset()-120
> new Date('2122-12-29').getTimezoneOffset()-60
示例日期:
const d = new Date(0);
Date.prototype.toTimeString()
(本地时区)
> d.toTimeString()'01:00:00 GMT+0100 (Central European Standard Time)'
Date.prototype.toDateString()
(本地时区)
> d.toDateString()'Thu Jan 01 1970'
Date.prototype.toString()
(本地时区)
> d.toString()'Thu Jan 01 1970 01:00:00 GMT+0100 (Central European Standard Time)'
Date.prototype.toUTCString()
(UTC)
> d.toUTCString()'Thu, 01 Jan 1970 00:00:00 GMT'
Date.prototype.toISOString()
(UTC)
> d.toISOString()'1970-01-01T00:00:00.000Z'
以下三种方法实际上不属于 ECMAScript,而是属于 ECMAScript 国际化 API。该 API 具有许多用于格式化日期的功能(包括对时区的支持),但没有用于解析日期的功能。
Date.prototype.toLocaleTimeString()
Date.prototype.toLocaleDateString()
Date.prototype.toLocaleString()
练习:创建日期字符串
exercises/dates/create_date_string_test.mjs