JavaScript日期与时间

        Date类是Javascript中用于操作日期和时间的API。使用Date()构造函数可以创建一个日期对象。在不传参数的情况下,这个构造函数会返回一个表示当前日期和时间的Date对象:

let now = new Date();    //当前时间

        如果传入一个数值参数,Date()构造函数会将其解释为自1970年至今经过的毫秒数:

let epoch = new Date(0);    //格林尼治标准时间1970年1月1日0时

        如果传入一个或多个整数参数,它们会被解释为本地时区的年、月、日、时、分、秒和毫秒,如下所示:

let century = new Date(2100,    //2100年

    0,    //1月

    1,    //1日

    2,3,4,5);    //本地时间02:03:04.005

        Date API有个奇怪的地方,即每年第一个月对应数值0,而每月第一天对应数值1.如果省略时间字段,Date()构造函数默认它们都为0,将时间设置为半夜12点。

        注意,在使用多个参数调用时,Date()构造函数会使用本地计算机的时区来解释它们。如果想以UTC指定日期和时间,可以使用Date.UTC()。这个静态方法接收与Date()构造函数同样的参数,但使用UTC来解释它们,并返回毫秒时间戳,可以传给Date()构造函数:

let century = new Date(Date.UTC(2100,0,1));

        如果要打印日期(比如,使用console.log(century)),默认会以本地时区打印。如果想以UTC显示日期,应该先使用toUTCString()或toISOString()转换它。

        最后,如果给Date()构造函数传入字符串,它会尝试按照日期和时间格式来解析该字符串。这个构造函数可以解析toString()、toUTCString()、toISOString()方法产生的格式:

let century = new Date("2100-01-01T00:00:00Z");    //ISO格式的日期

        有了一个Date()对象后,可以通过很多方法获取或设置这个对象的年、月、日、时、分、秒和毫秒字段。这些方法都有两种形式,一种使用本地时间来获取和设置。比如,要获取或设置一个Date对象的年份,可以使用getFullYear()、getUTCFullYear()、setFullYear()或setUTCFullYear():

let d = new Date();

d.setFullYear(d.getFullYear()+1);

    注意,查询日的方法是getDate()和getUTCDate()。而名字听起来更自然的函数getDay()和getUTCDay()返回的代表周几的数值(0表示周日,6表示周六)。周几字段是只读的,因此没有对应的setDay()方法。

# 时间戳

        Javascript在内部将日期表示为整数,代表自1970年1月1日半夜12点起(或之前)的毫秒数。由于Javascript最大支持的整数上限,因此Javascript表示的时间不会超过27万年。

        对于任何Date对象,getTime()方法返回这个内部值,而setTime()方法设置这个值。因此,可以像下面这样给一个Date对象添加30秒:

d.setTime(d.getTime()+30000);

        这些毫秒值有时候也被称为时间戳(timestamp),有时候直接使用这些值比使用Date对象更方便。静态的Date.now()方法返回当前时间的时间戳,经常用于度量代码运行时间:

let startTime = Date.now();

reticulateSplines();

let endTime = Date.now();

console.log('Spline reticulation took ${endTime - startTime}ms.');

# 高精度时间戳

        Date.now()返回的时间戳是以毫秒为单位的。毫秒对计算机来说实际上是个比较长的时间单位。有时候可能需要使用更高的精度来表示经历的时间。此时可以使用performance.now(),虽然它返回的也是以毫秒为单位的时间戳,但返回值并不是整数,包含毫秒后面的小数部分。performance.now()返回的值并不是像Date.now()返回的值一样的绝对时间戳,而是相对于网页加载完成后或Node进程启动后经过的时间。

        performance对象是W3C定义的Performance API的一部分,已经被浏览器和Node实现。要在Node中使用Performance对象,必须先导入它:

const { performance } = require("perf_hooks");

        高精度计时可能会让一些没有底线的网站用于采集访客指纹,因此浏览器(特别是Firefox)默认可能会降低performance.now()的精度。作为Web开发者,应该可以通过某种方式更新或启用高精度计时(比如在Firefox中可以设置privacy.reduceTimePrecision为false)。

# 日期计算

        Date对象可以使用Javascript标准的<、<=、>和>=等比较操作符进行比较。可以使用一个Date对象减去另一个以确定两个日期相关的毫秒数(这本质上是因为Date类定义了valueOf()方法,这个方法返回的是日期的时间戳)。

        如果想要给Date对象加或减指定数量的秒、分或小时,最简单的方式就是像前面例子中(给日期加上30秒)那样修改时间戳。但这种方式在涉及加天时就比较麻烦了,因为这不适合所有月份和年份,在不同月份和年份的天数也可能不一样。要完成涉及天数、月数和年数的计算,可以使用steDate()、setMonth()和setYear()。比如,下面的代码给当前日期加上了3个月和2周:

let d = new Date();

d.setMonth(d.getMonth() + 3,d.getDate() + 14);

        日期设置方法即使在数值溢出的情况下也能正确工作。比如,在给当前月份加了3个月之后,最终值可能大于11(11表示12月)。setMonth()在遇到这种情况时会按照需要增加年份。类似的,在将天数设置为超过相应月份的天数时,月份也会相应递增。

# 格式化与解析日期字符串

        如果使用Date类去记录日期和时间(而不只是度量时间),那很可能需要通过代码向用户展示日期和时间。Date类定义了一些方法,可以将日期对象转换为字符串。下面是几个例子:

let d = new Date(2020,0,1,17,10,30); //2020年元旦5:10:30pm

console.log(d.toString()); //Wed Jan 01 2020 17:10:30 GMT+0800 (中国标准时间)

console.log(d.toUTCString()); //Wed, 01 Jan 2020 09:10:30 GMT

console.log(d.toLocaleDateString()); //2020/1/1

console.log(d.toLocaleTimeString()); //17:10:30

console.log(d.toISOString()); //2020-01-01T09:10:30.000Z

下面分别介绍Date类定义的全部字符串格式化方法。

toString()

这个方法使用本地时区但不按照当地惯例格式化日期和时间。

toUTCString()

这个方法使用UTC时区但不按照当地惯例格式化日期。

toISOString()

这个方法以标准的ISO-8601“年-月-日时:分:秒:毫秒”格式打印日期和时间。字母“T”在输出中分隔日期部分和时间部分。时间以UTC表示,可以通过输出在末尾的字母“Z”看出来。

toLocaleString()

这个方法使用本地时区及用户当地惯例一致的格式。

toDateString()

这个方法只格式化Date的日期部分,忽略时间部分。它使用本地时区,但不与当地惯例适配。

toLocaleDateString()

这个方法只格式化日期部分。它使用本地时区,也适配当地惯例。

toTimeString()

这个方法只格式化时间部分。它使用本地时区,但不与当地惯例适配。

toLocaleTimeString()

这个方法只格式化时间部分。它使用本地时区,也适配当地惯例。

        注意,这些日期到字符串的转换方法都可以用于格式化日期和时间并展示给用户。

        最后,除了将Date对象转换为字符串的方法,还有一个静态的Date.parse()方法。该方法接收一个字符串参数,并尝试将其作为日期和时间来解析,返回一个表示该日期的时间戳。Date.parse()可以像Date()构造函数一样解析同样的字符串,也可以解析toISOString()、toUTCString()和toString()的输出。

标签: JavaScript 日期 时间 Date