日期

基线 广泛可用

此功能已很成熟,可在许多设备和浏览器版本上运行。自 2015 年 7 月.

JavaScript Date 对象以与平台无关的格式表示时间中的单个时刻。Date 对象封装了一个整数,该整数代表自 1970 年 1 月 1 日 UTC 开始的午夜(纪元)以来的毫秒数。

注意:TC39 正在开发 Temporal,一个新的日期/时间 API。在 Igalia 博客 上了解更多信息。它尚未准备好投入生产使用!

描述

纪元、时间戳和无效日期

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 的时间戳值,即“无效日期”。

js
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"

有各种方法可以让您与存储在日期中的时间戳进行交互

日期组件和时区

日期在内部表示为一个数字,即时间戳。与之交互时,需要将时间戳解释为结构化的日期和时间表示。解释时间戳总是有两种方法:作为本地时间或作为协调世界时 (UTC),即世界时间标准定义的全球标准时间。本地时区未存储在日期对象中,而是由主机环境(用户设备)确定。

注意:UTC 不应与 格林威治标准时间 (GMT) 混淆,因为它们并不总是相等 - 这将在链接的维基百科页面中详细解释。

例如,时间戳 0 代表历史上一个独特的一瞬间,但它可以以两种方式解释

  • 作为 UTC 时间,它是在 1970 年 1 月 1 日 UTC 的午夜,
  • 作为纽约的本地时间 (UTC-5),它是 1969 年 12 月 31 日 19:00:00。

getTimezoneOffset() 方法返回 UTC 与本地时间之间的分钟差。请注意,时区偏移量不仅取决于当前时区,还取决于Date 对象所表示的时间,因为存在夏令时和历史变化。本质上,时区偏移量是从 UTC 时间的偏移量,在Date 对象所表示的时间和主机环境的位置。

Date 方法有两组:一组通过将时间戳解释为本地时间来获取和设置各种日期组件,而另一组使用 UTC。

组件 本地 UTC
获取 设置 获取 设置
年份 getFullYear() setFullYear() getUTCFullYear() setUTCFullYear()
月份 getMonth() setMonth() getUTCMonth() setUTCMonth()
日期(月日) getDate() setDate() getUTCDate() setUTCDate()
小时 getHours() setHours() getUTCHours() setUTCHours()
分钟 getMinutes() setMinutes() getUTCMinutes() setUTCMinutes()
getSeconds() setSeconds() getUTCSeconds() setUTCSeconds()
毫秒 getMilliseconds() setMilliseconds() getUTCMilliseconds() setUTCMilliseconds()
星期(星期几) getDay() N/A getUTCDay() N/A

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 是年份,用四位数字表示(00009999),或者用 +- 后跟六位数字表示的扩展年份。扩展年份需要符号。-000000 明确地不允许作为有效的年份。
  • MM 是月份,用两位数字表示(0112)。默认为 01
  • DD 是月份中的日期,用两位数字表示(0131)。默认为 01
  • T 是一个文字字符,它表示字符串中时间部分的开始。当指定时间部分时,T 是必需的。
  • HH 是小时,用两位数字表示(0023)。作为特殊情况,24:00:00 是允许的,它被解释为下一天开始时的午夜。默认为 00
  • mm 是分钟,用两位数字表示(0059)。默认为 00
  • ss 是秒,用两位数字表示(0059)。默认为 00
  • sss 是毫秒,用三位数字表示(000999)。默认为 000
  • Z 是时区偏移量,它可以是文字字符 Z(表示 UTC),也可以是 +- 后跟 HH:mm,表示相对于 UTC 的小时和分钟偏移量。

各种组件可以省略,因此以下都是有效的

  • 仅日期形式:YYYYYYYY-MMYYYY-MM-DD
  • 日期时间形式:上述任何仅日期形式,后跟 T,后跟 HH:mmHH:mm:ssHH: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()

返回指定日期的月份中的日期(131),根据本地时间。

Date.prototype.getDay()

返回指定日期的星期中的日期(06),根据本地时间。

Date.prototype.getFullYear()

返回指定日期的年份(对于四位数年份为四位数字),根据本地时间。

Date.prototype.getHours()

返回指定日期的小时(023),根据本地时间。

Date.prototype.getMilliseconds()

返回指定日期的毫秒(0999),根据本地时间。

Date.prototype.getMinutes()

返回指定日期的分钟(059),根据本地时间。

Date.prototype.getMonth()

返回指定日期的月份(011),根据本地时间。

Date.prototype.getSeconds()

返回指定日期的秒(059),根据本地时间。

Date.prototype.getTime()

返回指定日期的数值,作为自 1970 年 1 月 1 日 00:00:00 UTC 以来经过的毫秒数。(以前的时间返回负数。)

Date.prototype.getTimezoneOffset()

返回当前语言环境的时区偏移量(以分钟为单位)。

Date.prototype.getUTCDate()

返回指定日期的月份中的日期(131),根据世界时。

Date.prototype.getUTCDay()

返回指定日期的星期中的日期(06),根据世界时。

Date.prototype.getUTCFullYear()

返回指定日期的年份(对于四位数年份为四位数字),根据世界时。

Date.prototype.getUTCHours()

返回指定日期的小时(023),根据世界时。

Date.prototype.getUTCMilliseconds()

返回指定日期的毫秒(0999),根据世界时。

Date.prototype.getUTCMinutes()

返回指定日期的分钟(059),根据世界时。

Date.prototype.getUTCMonth()

返回指定日期的月份(011),根据世界时。

Date.prototype.getUTCSeconds()

返回指定日期的秒(059),根据世界时。

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 日期对象的几种方法

注意:从字符串创建日期存在很多行为不一致的情况。请参阅 日期时间字符串格式 了解使用不同格式时的注意事项。

js
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 方法返回值的格式

js
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

获取日期、月份和年份或时间

js
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 的偏移量。

js
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)

因此,要创建并获取 099 年之间的日期,请改用首选的 setFullYear()getFullYear() 方法:

js
// 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 日期之间以毫秒为单位的经过时间。

由于天数(由于夏令时切换)、月份和年份的长度不同,用大于小时、分钟和秒的单位表达经过时间需要解决许多问题,因此在尝试之前应进行彻底的研究。

js
// 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
js
// 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
js
// 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 纪元以来的秒数

js
const seconds = Math.floor(Date.now() / 1000);

在这种情况下,重要的是只返回整数——因此简单的除法是不行的。同样重要的是只返回实际经过的秒数。(这就是为什么此代码使用 Math.floor(),而不是 Math.round())。

规范

规范
ECMAScript 语言规范
# sec-date-objects

浏览器兼容性

BCD 表格仅在启用 JavaScript 的浏览器中加载。

另请参阅