日期
JavaScript Date
对象以与平台无关的格式表示时间中的单个时刻。Date
对象封装了一个整数,该整数代表自 1970 年 1 月 1 日 UTC 开始的午夜(纪元)以来的毫秒数。
描述
纪元、时间戳和无效日期
JavaScript 日期从根本上定义为自 纪元以来的毫秒数,纪元定义为 1970 年 1 月 1 日 UTC 的午夜(等效于 UNIX 纪元)。此时间戳与时区无关,并且唯一地定义了历史上的一瞬间。
注意:虽然 Date 对象的核心时间值是 UTC,但用于获取日期和时间或其组件的基本方法都在本地(即主机系统)时区和偏移量中工作。
Date
对象可表示的最大时间戳略小于最大安全整数(Number.MAX_SAFE_INTEGER
,即 9,007,199,254,740,991)。Date
对象最多可以表示相对于纪元的 ±8,640,000,000,000,000 毫秒,或 ±100,000,000(一亿)天。这是从公元前 271821 年 4 月 20 日到公元 275760 年 9 月 13 日的范围。任何尝试表示此范围之外的时间都会导致Date
对象保存 NaN
的时间戳值,即“无效日期”。
console.log(new Date(8.64e15).toString()); // "Sat Sep 13 275760 00:00:00 GMT+0000 (Coordinated Universal Time)"
console.log(new Date(8.64e15 + 1).toString()); // "Invalid Date"
有各种方法可以让您与存储在日期中的时间戳进行交互
- 您可以使用
getTime()
和setTime()
方法直接与时间戳值进行交互。 valueOf()
和[Symbol.toPrimitive]()
(当传递"number"
时)方法 - 在 数字强制转换 中自动调用 - 返回时间戳,导致Date
对象在数字上下文中使用时表现得像它们的时间戳。- 所有静态方法(
Date.now()
、Date.parse()
和Date.UTC()
)返回时间戳而不是Date
对象。 Date()
构造函数可以用时间戳作为唯一参数来调用。
日期组件和时区
日期在内部表示为一个数字,即时间戳。与之交互时,需要将时间戳解释为结构化的日期和时间表示。解释时间戳总是有两种方法:作为本地时间或作为协调世界时 (UTC),即世界时间标准定义的全球标准时间。本地时区未存储在日期对象中,而是由主机环境(用户设备)确定。
注意:UTC 不应与 格林威治标准时间 (GMT) 混淆,因为它们并不总是相等 - 这将在链接的维基百科页面中详细解释。
例如,时间戳 0 代表历史上一个独特的一瞬间,但它可以以两种方式解释
- 作为 UTC 时间,它是在 1970 年 1 月 1 日 UTC 的午夜,
- 作为纽约的本地时间 (UTC-5),它是 1969 年 12 月 31 日 19:00:00。
getTimezoneOffset()
方法返回 UTC 与本地时间之间的分钟差。请注意,时区偏移量不仅取决于当前时区,还取决于Date
对象所表示的时间,因为存在夏令时和历史变化。本质上,时区偏移量是从 UTC 时间的偏移量,在Date
对象所表示的时间和主机环境的位置。
Date
方法有两组:一组通过将时间戳解释为本地时间来获取和设置各种日期组件,而另一组使用 UTC。
Date()
构造函数可以接受两个或更多个参数,在这种情况下,它们分别被解释为本地时间的年份、月份、日期、小时、分钟、秒和毫秒。Date.UTC()
的工作方式类似,但它将这些组件解释为 UTC 时间,并且还接受一个表示年份的单个参数。
注意: 一些方法,包括 Date()
构造函数、Date.UTC()
以及已弃用的 getYear()
/setYear()
方法,将两位数的年份解释为 1900 年代的年份。例如,new Date(99, 5, 24)
被解释为 1999 年 6 月 24 日,而不是 99 年 6 月 24 日。有关详细信息,请参阅 两位数年份的解释。
当一个段溢出或下溢超出其预期的范围时,它通常会“进位”到或“借位”自更高段。例如,如果月份设置为 12(月份从零开始,因此 12 月为 11),它将变成下一年的 1 月。如果月份的日期设置为 0,它将变成前一个月的最后一天。这也适用于使用 日期时间字符串格式 指定的日期。
日期时间字符串格式
有很多方法可以将日期格式化为字符串。JavaScript 规范仅指定了一种必须普遍支持的格式:日期时间字符串格式,它是 ISO 8601 日历日期扩展格式的简化版本。格式如下
YYYY-MM-DDTHH:mm:ss.sssZ
YYYY
是年份,用四位数字表示(0000
到9999
),或者用+
或-
后跟六位数字表示的扩展年份。扩展年份需要符号。-000000
明确地不允许作为有效的年份。MM
是月份,用两位数字表示(01
到12
)。默认为01
。DD
是月份中的日期,用两位数字表示(01
到31
)。默认为01
。T
是一个文字字符,它表示字符串中时间部分的开始。当指定时间部分时,T
是必需的。HH
是小时,用两位数字表示(00
到23
)。作为特殊情况,24:00:00
是允许的,它被解释为下一天开始时的午夜。默认为00
。mm
是分钟,用两位数字表示(00
到59
)。默认为00
。ss
是秒,用两位数字表示(00
到59
)。默认为00
。sss
是毫秒,用三位数字表示(000
到999
)。默认为000
。Z
是时区偏移量,它可以是文字字符Z
(表示 UTC),也可以是+
或-
后跟HH:mm
,表示相对于 UTC 的小时和分钟偏移量。
各种组件可以省略,因此以下都是有效的
- 仅日期形式:
YYYY
、YYYY-MM
、YYYY-MM-DD
- 日期时间形式:上述任何仅日期形式,后跟
T
,后跟HH:mm
、HH:mm:ss
或HH:mm:ss.sss
。每种组合都可以后跟时区偏移量。
例如,"2011-10-10"
(仅日期 形式)、"2011-10-10T14:48:00"
(日期时间 形式)或 "2011-10-10T14:48:00.000+09:00"
(日期时间 形式,带有毫秒和时区)都是有效的日期时间字符串。
当时区偏移量不存在时,仅日期形式被解释为 UTC 时间,日期时间形式被解释为本地时间。 这是由于历史规范错误造成的,该错误与 ISO 8601 不一致,但由于 Web 兼容性问题而无法更改。请参阅 损坏的解析器 – Web 现实问题。
Date.parse()
和 Date()
构造函数都接受日期时间字符串格式的字符串作为输入。此外,允许实现支持其他日期格式,如果输入与这种格式不匹配。
toISOString()
方法返回日期的字符串表示形式,以日期时间字符串格式表示,时区偏移量始终设置为 Z
(UTC)。
注意: 为了获得最大的兼容性,建议您确保您的输入符合上述日期时间字符串格式,因为对其他格式的支持不能保证。但是,在所有主要实现中都支持一些格式(例如 RFC 2822 格式),在这种情况下,使用这些格式是可以接受的。始终进行 跨浏览器测试 以确保您的代码在所有目标浏览器中都能正常工作。如果要处理许多不同的格式,库可以提供帮助。
非标准字符串可以以任何实现想要的方式进行解析,包括时区——大多数实现默认情况下使用本地时区。实现不需要为超出范围的日期组件返回无效日期,尽管它们通常这样做。字符串可能包含范围内的日期组件(范围在上面定义),但实际上并不表示日期(例如,“2 月 30 日”)。在这种情况下,实现的行为不一致。Date.parse()
页面提供了有关这些非标准情况的更多示例。
其他日期格式化方法
toISOString()
返回一个字符串,格式为1970-01-01T00:00:00.000Z
(上面介绍的日期时间字符串格式,它是简化的 ISO 8601)。toJSON()
调用toISOString()
并返回结果。toString()
返回一个字符串,格式为Thu Jan 01 1970 00:00:00 GMT+0000 (Coordinated Universal Time)
,而toDateString()
和toTimeString()
分别返回字符串的日期部分和时间部分。[Symbol.toPrimitive]()
(当传递"string"
或"default"
时)调用toString()
并返回结果。toUTCString()
返回一个字符串,格式为Thu, 01 Jan 1970 00:00:00 GMT
(广义 RFC 7231)。toLocaleDateString()
、toLocaleTimeString()
和toLocaleString()
使用特定于语言环境的日期和时间格式,通常由Intl
API 提供。
有关示例,请参阅 toString
方法返回值的格式 部分。
构造函数
Date()
-
当作为构造函数调用时,返回一个新的
Date
对象。当作为函数调用时,返回当前日期和时间的字符串表示形式。
静态方法
Date.now()
-
返回对应于当前时间的数值——自 1970 年 1 月 1 日 00:00:00 UTC 以来经过的毫秒数,忽略闰秒。
Date.parse()
-
解析日期的字符串表示形式,并返回自 1970 年 1 月 1 日 00:00:00 UTC 以来经过的毫秒数,忽略闰秒。
Date.UTC()
-
接受与构造函数的最长形式相同的参数(即 2 到 7 个),并返回自 1970 年 1 月 1 日 00:00:00 UTC 以来经过的毫秒数,忽略闰秒。
实例属性
这些属性在 Date.prototype
上定义,并由所有 Date
实例共享。
Date.prototype.constructor
-
创建实例对象的构造函数。对于
Date
实例,初始值为Date
构造函数。
实例方法
Date.prototype.getDate()
-
返回指定日期的月份中的日期(
1
–31
),根据本地时间。 Date.prototype.getDay()
-
返回指定日期的星期中的日期(
0
–6
),根据本地时间。 Date.prototype.getFullYear()
-
返回指定日期的年份(对于四位数年份为四位数字),根据本地时间。
Date.prototype.getHours()
-
返回指定日期的小时(
0
–23
),根据本地时间。 Date.prototype.getMilliseconds()
-
返回指定日期的毫秒(
0
–999
),根据本地时间。 Date.prototype.getMinutes()
-
返回指定日期的分钟(
0
–59
),根据本地时间。 Date.prototype.getMonth()
-
返回指定日期的月份(
0
–11
),根据本地时间。 Date.prototype.getSeconds()
-
返回指定日期的秒(
0
–59
),根据本地时间。 Date.prototype.getTime()
-
返回指定日期的数值,作为自 1970 年 1 月 1 日 00:00:00 UTC 以来经过的毫秒数。(以前的时间返回负数。)
Date.prototype.getTimezoneOffset()
-
返回当前语言环境的时区偏移量(以分钟为单位)。
Date.prototype.getUTCDate()
-
返回指定日期的月份中的日期(
1
–31
),根据世界时。 Date.prototype.getUTCDay()
-
返回指定日期的星期中的日期(
0
–6
),根据世界时。 Date.prototype.getUTCFullYear()
-
返回指定日期的年份(对于四位数年份为四位数字),根据世界时。
Date.prototype.getUTCHours()
-
返回指定日期的小时(
0
–23
),根据世界时。 Date.prototype.getUTCMilliseconds()
-
返回指定日期的毫秒(
0
–999
),根据世界时。 Date.prototype.getUTCMinutes()
-
返回指定日期的分钟(
0
–59
),根据世界时。 Date.prototype.getUTCMonth()
-
返回指定日期的月份(
0
–11
),根据世界时。 Date.prototype.getUTCSeconds()
-
返回指定日期的秒(
0
–59
),根据世界时。 Date.prototype.getYear()
已弃用-
返回指定日期的年份(通常为 2-3 位数字),根据本地时间。使用
getFullYear()
代替。 Date.prototype.setDate()
-
设置指定日期的月份中的日期,根据本地时间。
Date.prototype.setFullYear()
-
设置指定日期的完整年份(例如,对于四位数年份为四位数字),根据本地时间。
Date.prototype.setHours()
-
设置指定日期的小时,根据本地时间。
Date.prototype.setMilliseconds()
-
设置指定日期的毫秒,根据本地时间。
Date.prototype.setMinutes()
-
设置指定日期的分钟,根据本地时间。
Date.prototype.setMonth()
-
设置指定日期的月份,根据本地时间。
Date.prototype.setSeconds()
-
设置指定日期的秒,根据本地时间。
Date.prototype.setTime()
-
将
Date
对象设置为自 1970 年 1 月 1 日 00:00:00 UTC 以来经过的毫秒数所表示的时间。对于以前的时间使用负数。 Date.prototype.setUTCDate()
-
设置指定日期的月份中的日期,根据世界时。
Date.prototype.setUTCFullYear()
-
设置指定日期的完整年份(例如,对于四位数年份为四位数字),根据世界时。
Date.prototype.setUTCHours()
-
设置指定日期的小时,根据世界时。
Date.prototype.setUTCMilliseconds()
-
设置指定日期的毫秒,根据世界时。
Date.prototype.setUTCMinutes()
-
设置指定日期的分钟,根据世界时。
Date.prototype.setUTCMonth()
-
设置指定日期的月份,根据世界时。
Date.prototype.setUTCSeconds()
-
设置指定日期的秒,根据世界时。
Date.prototype.setYear()
已弃用-
根据本地时间设置指定日期的年份(通常为 2-3 位数字)。请改用
setFullYear()
方法。 Date.prototype.toDateString()
-
返回
Date
对象的“日期”部分,以人类可读的字符串形式表示,例如'Thu Apr 12 2018'
。 Date.prototype.toISOString()
-
将日期转换为符合 ISO 8601 扩展格式的字符串。
Date.prototype.toJSON()
-
使用
toISOString()
返回表示Date
对象的字符串。旨在用于JSON.stringify()
方法。 Date.prototype.toLocaleDateString()
-
返回一个字符串,其中包含基于系统设置的日期部分的本地化表示。
Date.prototype.toLocaleString()
-
返回一个字符串,其中包含此日期的本地化表示。覆盖了
Object.prototype.toLocaleString()
方法。 Date.prototype.toLocaleTimeString()
-
返回一个字符串,其中包含基于系统设置的此日期的时间部分的本地化表示。
Date.prototype.toString()
-
返回表示指定
Date
对象的字符串。覆盖了Object.prototype.toString()
方法。 Date.prototype.toTimeString()
-
返回
Date
对象的“时间”部分,以人类可读的字符串形式表示。 Date.prototype.toUTCString()
-
使用 UTC 时区将日期转换为字符串。
Date.prototype.valueOf()
-
返回
Date
对象的原始值。覆盖了Object.prototype.valueOf()
方法。 Date.prototype[Symbol.toPrimitive]()
-
将此
Date
对象转换为原始值。
示例
创建 Date 对象的几种方法
以下示例展示了创建 JavaScript 日期对象的几种方法
注意:从字符串创建日期存在很多行为不一致的情况。请参阅 日期时间字符串格式 了解使用不同格式时的注意事项。
const today = new Date();
const birthday = new Date("December 17, 1995 03:24:00"); // DISCOURAGED: may not work in all runtimes
const birthday2 = new Date("1995-12-17T03:24:00"); // This is standardized and will work reliably
const birthday3 = new Date(1995, 11, 17); // the month is 0-indexed
const birthday4 = new Date(1995, 11, 17, 3, 24, 0);
const birthday5 = new Date(628021800000); // passing epoch timestamp
toString 方法返回值的格式
const date = new Date("2020-05-12T23:50:21.817Z");
date.toString(); // Tue May 12 2020 18:50:21 GMT-0500 (Central Daylight Time)
date.toDateString(); // Tue May 12 2020
date.toTimeString(); // 18:50:21 GMT-0500 (Central Daylight Time)
date[Symbol.toPrimitive]("string"); // Tue May 12 2020 18:50:21 GMT-0500 (Central Daylight Time)
date.toISOString(); // 2020-05-12T23:50:21.817Z
date.toJSON(); // 2020-05-12T23:50:21.817Z
date.toUTCString(); // Tue, 12 May 2020 23:50:21 GMT
date.toLocaleString(); // 5/12/2020, 6:50:21 PM
date.toLocaleDateString(); // 5/12/2020
date.toLocaleTimeString(); // 6:50:21 PM
获取日期、月份和年份或时间
const date = new Date("2000-01-17T16:45:30");
const [month, day, year] = [
date.getMonth(),
date.getDate(),
date.getFullYear(),
];
// [0, 17, 2000] as month are 0-indexed
const [hour, minutes, seconds] = [
date.getHours(),
date.getMinutes(),
date.getSeconds(),
];
// [16, 45, 30]
两位数年份的解释
new Date()
在处理两位数年份时会表现出不必要的、不一致的遗留行为;具体来说,当 new Date()
调用中传递两位数年份值时,该年份值不会被视为字面意义上的年份并直接使用,而是会被解释为相对偏移量——在某些情况下是相对于年份 1900
的偏移量,但在其他情况下,则是相对于年份 2000
的偏移量。
let date = new Date(98, 1); // Sun Feb 01 1998 00:00:00 GMT+0000 (GMT)
date = new Date(22, 1); // Wed Feb 01 1922 00:00:00 GMT+0000 (GMT)
date = new Date("2/1/22"); // Tue Feb 01 2022 00:00:00 GMT+0000 (GMT)
// Legacy method; always interprets two-digit year values as relative to 1900
date.setYear(98);
date.toString(); // Sun Feb 01 1998 00:00:00 GMT+0000 (GMT)
date.setYear(22);
date.toString(); // Wed Feb 01 1922 00:00:00 GMT+0000 (GMT)
因此,要创建并获取 0
到 99
年之间的日期,请改用首选的 setFullYear()
和 getFullYear()
方法:
// Preferred method; never interprets any value as being a relative offset,
// but instead uses the year value as-is
date.setFullYear(98);
date.getFullYear(); // 98 (not 1998)
date.setFullYear(22);
date.getFullYear(); // 22 (not 1922, not 2022)
计算经过时间
以下示例展示了如何确定两个 JavaScript 日期之间以毫秒为单位的经过时间。
由于天数(由于夏令时切换)、月份和年份的长度不同,用大于小时、分钟和秒的单位表达经过时间需要解决许多问题,因此在尝试之前应进行彻底的研究。
// Using Date objects
const start = Date.now();
// The event to time goes here:
doSomethingForALongTime();
const end = Date.now();
const elapsed = end - start; // elapsed time in milliseconds
// Using built-in methods
const start = new Date();
// The event to time goes here:
doSomethingForALongTime();
const end = new Date();
const elapsed = end.getTime() - start.getTime(); // elapsed time in milliseconds
// To test a function and get back its return
function printElapsedTime(testFn) {
const startTime = Date.now();
const result = testFn();
const endTime = Date.now();
console.log(`Elapsed time: ${String(endTime - startTime)} milliseconds`);
return result;
}
const yourFunctionReturn = printElapsedTime(yourFunction);
注意:在支持 性能 API 的高分辨率时间功能的浏览器中,Performance.now()
可以提供比 Date.now()
更可靠、更精确的经过时间测量结果。
获取自 ECMAScript 纪元以来的秒数
const seconds = Math.floor(Date.now() / 1000);
在这种情况下,重要的是只返回整数——因此简单的除法是不行的。同样重要的是只返回实际经过的秒数。(这就是为什么此代码使用 Math.floor()
,而不是 Math.round()
)。
规范
规范 |
---|
ECMAScript 语言规范 # sec-date-objects |
浏览器兼容性
BCD 表格仅在启用 JavaScript 的浏览器中加载。