Date

​ ECMAScript 的 Date 类型参考了 Java 早期版本中的 java.util.Date。为此,Date 类型将日期保存为自协调世界时(UTC,Universal Time Coordinated)时间 1970 年 1 月 1 日午夜(零时)至今所经过的毫秒数。使用这种存储格式,Date 类型可以精确表示 1970 年 1 月 1 日之前及之后 285 616 年的 日期。

​ 要创建日期对象,就使用 new 操作符来调用 Date 构造函数:

let now = new Date();

​ 在不给 Date 构造函数传参数的情况下,创建的对象将保存当前日期和时间。要基于其他日期和时间创建日期对象,必须传入其毫秒表示(UNIX 纪元 1970 年 1 月 1 日午夜之后的毫秒数)。ECMAScript 为此提供了两个辅助方法:Date.parse()和 Date.UTC()

​ Date.parse()方法接收一个表示日期的字符串参数,尝试将这个字符串转换为表示该日期的毫秒数。ECMA-262 第 5 版定义了 Date.parse()应该支持的日期格式,填充了第 3 版遗留的空白。所有实现都必须支持下列日期格式:

- “月/日/年”,如"5/23/2019";
- “月名 日, 年”,如"May 23, 2019";
- “周几 月名 日 年 时:分:秒 时区”,如"Tue May 23 2019 00:00:00 GMT-0700";
- ISO 8601扩展格式“YYYY-MM-DDTHH:mm:ss.sssZ”,如2019-05-23T00:00:00(只适用于兼容 ES5 的实现)。

​ 比如,要创建一个表示“2019 年 5 月 23 日”的日期对象,可以使用以下代码:

let someDate = new Date(Date.parse("May 23, 2019"));

​ 如果传给Date.parse()的字符串并不表示日期,则该方法会返回NaN。如果直接把表示日期的字符串传给 Date 构造函数,那么 Date 会在后台调用 Date.parse()。换句话说,下面这行代码跟前面那行代码是等价的:

let someDate = new Date("May 23, 2019");

​ 这两行代码得到的日期对象相同。

注意 不同的浏览器对Date类型的实现有很多问题。比如,很多浏览器会选择用当前日期替代越界的日期,因此有些浏览器会将”January 32, 2019”解释为”February 1, 2019”。Opera 则会插入当前月的当前日,返回”January 当前日, 2019”。就是说,如果是在 9 月 21 日运行代码,会返回”January 21, 2019”。

​ Date.UTC()方法也返回日期的毫秒表示,但使用的是跟 Date.parse()不同的信息来生成这个值。 传给Date.UTC()的参数是年、零起点月数(1 月是 0,2 月是 1,以此类推)、日(1~31)时(0~23)分、秒和毫秒。这些参数中,只有前两个(年和月)是必需的。如果不提供日,那么默认为 1 日。其他参数的默认值都是 0。下面是使用 Date.UTC()的两个例子:

// GMT时间2000年1月1日零点
let y2k = new Date(Date.UTC(2000, 0));
// GMT时间2005年5月5日下午5点55分55秒
let allFives = new Date(Date.UTC(2005, 4, 5, 17, 55, 55)); //2005-05-05T17:55:55.000Z

​ 这个例子创建了两个日期 。第一个日期是 2000 年 1 月 1 日零点(GMT),2000 代表年,0 代表月 (1 月)。因为没有其他参数(日取 1,其他取 0),所以结果就是该月第 1 天零点。第二个日期表示 2005 年 5 月 5 日下午 5 点 55 分 55 秒(GMT)。虽然日期里面涉及的都是 5,但月数必须用 4,因为月数是零起点的。小时也必须是 17,因为这里采用的是 24 小时制,即取值范围是 0~23。其他参数就都很直观了。

​ 与 Date.parse()一样,Date.UTC()也会被 Date 构造函数隐式调用,但有一个区别:这种情况下创建的是本地日期不是 GMT 日期。不过 Date 构造函数跟 Date.UTC()接收的参数是一样的。因 此,如果第一个参数是数值,则构造函数假设它是日期中的年第二个参数就是月,以此类推。前面的例子也可以这样来写:

// 本地时间2000年1月1日零点
let y2k = new Date(2000, 0); // 1999-12-31T16:00:00.000Z
// 本地时间2005年5月5日下午5点55分55秒
let allFives = new Date(2005, 4, 5, 17, 55, 55); //2005-05-05T09:55:55.000Z

​ 以上代码创建了与前面例子中相同的两个日期,但这次的两个日期是(由于系统设置决定的)本地时区的日期

​ ECMAScript 还提供了 Date.now()方法,返回表示方法执行时日期和时间的毫秒数。这个方法可以方便地用在代码分析中:

// 起始时间
let start = Date.now();
// 调用函数 doSomething();
// 结束时间
let stop = Date.now(), 
    result = stop - start;

继承的方法

​ 与其他类型一样,Date 类型重写toLocaleString()、toString()和 valueOf()方法。但与其他类型不同,重写后这些方法的返回值不一样。Date 类型的 toLocaleString()方法返回与浏览器运行的本地环境一致的日期和时间。这通常意味着格式中包含针对时间的 AM(上午)或 PM(下午), 但不包含时区信息(具体格式可能因浏览器而不同)。toString()方法通常返回带时区信息的日期和时间,而时间也是以 24 小时制(0~23)表示的。下面给出了 toLocaleString()和 toString()返回的 2019 年 2 月 1 日零点的示例(地区为”en-US”的 PST,即 Pacific Standard Time,太平洋标准时间):

toLocaleString() //- 2/1/2019 12:00:00 AM
toString() //- Thu Feb 1 2019 00:00:00 GMT-0800 (Pacific Standard Time)

​ 现代浏览器在这两个方法的输出上已经趋于一致。在比较老的浏览器上,每个方法返回的结果可能在每个浏览器上都是不同的。这些差异意味着 toLocaleString()和 toString()可能只对调试有用,不能用于显示。

​ Date 类型的 valueOf()方法根本就不返回字符串,这个方法被重写后返回的是日期的毫秒表示。因此,操作符(如小于号和大于号)可以直接使用它返回的值。比如下面的例子:

let date1 = new Date(2019, 0, 1); // 2019年1月1日 
let date2 = new Date(2019, 1, 1); // 2019年1月1日 
console.log(date1 < date2); // true
console.log(date1 > date2); // false

​ 日期 2019 年 1 月 1 日在 2019 年 2 月 1 日之前,所以说前者小于后者没问题。因为 2019 年 1 月 1 日 的毫秒表示小于 2019 年 2 月 1 日的毫秒表示,所以用小于号比较这两个日期时会返回 true。这也是确保日期先后的一个简单方式。

日期格式化方法

​ Date 类型有几个专门用于格式化日期的方法,它们都会返回字符串:

- toDateString()显示日期中的周几、月、日、年(格式特定于实现);
- toTimeString()显示日期中的时、分、秒和时区(格式特定于实现);
- toLocaleDateString()显示日期中的周几、月、日、年(格式特定于实现和地区);
- toLocaleTimeString()显示日期中的时、分、秒(格式特定于实现和地区);
- toUTCString()显示完整的 UTC 日期(格式特定于实现)。

​ 这些方法的输出与 toLocaleString()和 toString()一样,会因浏览器而异。因此不能用于在用户界面上一致地显示日期。

注意 还有一个方法叫 toGMTString(),这个方法跟 toUTCString()是一样的,目的是为了向后兼容。不过,规范建议新代码使用 toUTCString()。

日期/时间组件方法

​ Date 类型剩下的方法(见下表)直接涉及取得或设置日期值的特定部分。注意表中“UTC 日期”,指的是没有时区偏移(将日期转换为 GMT)时的日期。

方法说明
getTime()返回日期的毫秒表示;与 valueOf()相同
setTime(milliseconds)设置日期的毫秒表示,从而修改整个日期
getFullYear()返回 4 位数年(即 2019 而不是 19)
getUTCFullYear()返回 UTC 日期的 4 位数年
setFullYear(year)设置日期的年(year 必须是 4 位数)
setUTCFullYear(year)设置 UTC 日期的年(year 必须是 4 位数)
getMonth()返回日期的月(0 表示 1 月,11 表示 12 月)
getUTCMonth()返回 UTC 日期的月(0 表示 1 月,11 表示 12 月)
setMonth(month)设置日期的月(month 为大于 0 的数值,大于 11 加年)
setUTCMonth(month)设置 UTC 日期的月(month 为大于 0 的数值,大于 11 加年)
getDate()返回日期中的日(1~31)
getUTCDate()返回 UTC 日期中的日(1~31)
setDate(date)设置日期中的日(如果 date 大于该月天数,则加月)
setUTCDate(date)设置 UTC 日期中的日(如果 date 大于该月天数,则加月)
getDay()返回日期中表示周几的数值(0 表示周日,6 表示周六)
getUTCDay()返回 UTC 日期中表示周几的数值(0 表示周日,6 表示周六)
getHours()返回日期中的时(0~23)
getUTCHours()返回 UTC 日期中的时(0~23)
setHours(hours)设置日期中的时(如果 hours 大于 23,则加日)
setUTCHours(hours)设置 UTC 日期中的时(如果 hours 大于 23,则加日)
getMinutes()返回日期中的分(0~59)
getUTCMinutes()返回 UTC 日期中的分(0~59)
setMinutes(minutes)设置日期中的分(如果 minutes 大于 59,则加时)
setUTCMinutes(minutes)设置 UTC 日期中的分(如果 minutes 大于 59,则加时)
getSeconds()返回日期中的秒(0~59)
getUTCSeconds()返回 UTC 日期中的秒(0~59)
setSeconds(seconds)设置日期中的秒(如果 seconds 大于 59,则加分)
setUTCSeconds(seconds)设置 UTC 日期中的秒(如果 seconds 大于 59,则加分)
getMilliseconds()返回日期中的毫秒
getUTCMilliseconds()返回 UTC 日期中的毫秒
setMilliseconds(milliseconds)设置日期中的毫秒
setUTCMilliseconds(milliseconds)设置 UTC 日期中的毫秒
getTimezoneOffset()返回以分钟计的 UTC 与本地时区的偏移量(如美国 EST 即“东部标准时间” 返回 300,进入夏令时的地区可能有所差异)