JavaScript中的Date对象

这篇文章的目的主要是讲解JavaScript中的Date对象,同时解答下面几个困惑我好久的问题:html

  • 能够解析的表示时间的字符串格式有哪些?
  • 时区TimeZone
  • 进位问题

名词约定

表示时间的词不少,好比时间日期时刻等,为了便于下面的讲解以及概念的统一,对于下面这种格式浏览器

YYYY-MM-DDTHH:mm:ss.sssZ

如今统一约定:函数

  • YYYY-MM-DD: 也就是年月日部分使用日期这个词;
  • HH:mm:ss.sss: 也就是时分秒部分使用时刻这个词;
  • YYYY-MM-DDTHH:mm:ss.sssZ: 也就是说并不特指日期时刻时,咱们用时间这个词;

其它名词约定:prototype

  • 时间对象:经过Date构造函数建立的对象;
  • 内部插槽:指官网文档中的internal slot
  • 计算机时区:指计算机设置的时区,而不是计算机所在地区的时区;

虽然JavaScript用了Date这个单词,这个单词翻译过来是日期,可是从上面的约定来看,翻译成时间这个词或许更为合适。翻译

至于为何采用上面这种字符串格式,而不是YYYY/MM/DD HH:mm:ss或者其它格式进行说明的缘由下面会说起。code

另外,下面全部代码的运行环境为Chrome浏览器,而且注释部分不必定表明返回值。orm

内容结构

文章将会从如下几个方面进行讲解:htm

  • Date概述
  • Date做为构造器的用法;
  • Date做为函数的用法;
  • Date上的静态方法;
  • getter相关函数;
  • setter相关函数;

Date概述

经过把Date做为构造函数使用,能够建立一个时间对象,这个时间对象表示时间长河中的一个时间点。时间对象内部有一个名为[[DateValue]]的内部插槽,这个内部插槽里面存储的是一个时间戳。这个时间戳表示的是以世界协调时的1970年1月1日0时0分0秒0毫秒做为起始的毫秒数。对象

问:不知道是否有人有过疑问,时间戳和时区相关吗,同一时间不一样时区获取的时间戳同样吗?
答:根据上面时间戳的规定,时间戳就是从世界协调时开始算的,因此能够说时间戳和时区有关,这个时区就是世界协调时。但也是由于这个时区是定死的,因此不一样的时区在同一时间获取到的时间戳都是同样的。ip

Date做为构造器的用法

JavaScript中,咱们常常会经过参数的类型和个数让函数做出不一样的处理,如:

function justForExample () { // 这个例子只是起说明做用,并没有实际意义
    let length = arguments.length
    if (length === 0) return 'zero parameter'
    if (length === 1) return arguments[0]
    if (length === 2) return arguments[0] + arguments[1] // 两个参数作加法
    if (length === 3) return arguments[0] * arguments[1] * arguments[2] // 三个参数作乘法
    // ...
}

Date也是经过判断参数的类型和个数来进行不一样处理的。Date能够处理的参数的个数是07个。

当参数的个数是0的时候,返回一个时间对象,[[DateValue]]内部插槽的值表明以世界协调时为基准的当前时间的时间戳。

当参数的个数是1的时候,还需根据参数的类型作进一步判断:

  1. 若是参数的类型是数字,返回一个时间对象,[[DateValue]]内部插槽的值就是这个数字,固然若是这个数据不合法或者超出边界的话,这个插槽的值就不必定是这个数字了。未免本文过于啰嗦,本文不讨论数字不合法或者超出边界等其它状况,有兴趣的能够参阅规范文档。
  2. 若是参数的类型是字符串,就会调用Date上的静态方法parse,而后把返回值做为[[DateValue]]的值。具体详见下面的Date.parse

当参数的个数大于2的时候,就会使用下面这种形式:

// 从左到右参数分别表明年,月,日,时,分,秒,毫秒
Date (year, month [,date [, hours [, minutes [, seconds [, ms ]]]]])

上面这种形式接受27个参数。日的默认值是1,时,分,秒,毫秒的默认值是0

须要注意的是:

  1. 月份是从0开始算的,也就是0表明1月1表明2月...11表明12月
  2. 我在文章的开始说过一个进位的问题。咱们知道当两个十进制的数相加时,若是低位超出该位的最大值,那么就会向高位进位,以使该位的值在合法范围以内。一样,在Date构造器以上述形式调用的时候,就会发生自动进位,也就是若是该位的值已经超出了该位的最大值,并不会报错,而是自动执行进位操做:

    // 进位
    new Date(2018, 8, 34) // Thu Oct 04 2018 00:00:00 GMT+0800 (中国标准时间)
    // 退位,相似于数学中的减法,也是能够的
    new Date(2018, 8, -1) // Thu Aug 30 2018 00:00:00 GMT+0800 (中国标准时间)

    能够看到,第三个参数34表示月份中的天数,可是9月只有30天,因此34并非9月合法的日期,因此就产生了进位,月份进入10月,而后日期是4日,也就是34-30。同理,当第三个参数是-1的时候,会退到8月份。

  3. 时区是计算机时区。也就是年,月,日,时,分,秒,毫秒表明的是计算机时区的时间。所以,不一样的计算机返回的时间多是不同的:

    let date1 = new Date(2018, 8, 8, 8, 8, 8) // Sat Sep 08 2018 08:08:08 GMT+0800 (中国标准时间)
    date1.getTime() // 1536365288000
    
    // 而后,改了下计算机时区
    let date2 = new Date(2018, 8, 8, 8, 8, 8) // Sat Sep 08 2018 08:08:08 GMT+0300 (莫斯科标准时间)
    date2.getTime() // 1536383288000
    
    (date1 - date2) / 3600 / 1000 // 5,由于date1是东八区,date2是东三区,正好相差5个小时

Date做为函数的用法

Date做为普通函数调用时,并不会对参数进行处理,直接返回表明当前时间的字符串。

Date() // "Sat Aug 18 2018 17:26:16 GMT+0800 (中国标准时间)"
Date(2018, 9, 9) // "Sat Aug 18 2018 17:26:21 GMT+0800 (中国标准时间)"

Date上的静态方法

Date上的静态方法有三个:

  • Date.now()
  • Date.parse(string)
  • Date.UTC(year, month [, date [, hours [, minutes [, seconds [, ms ]]]]])

Date.now()

返回函数调用时,以世界协调时为基准的时间戳。

Date.parse(string)

Date.parse处理第一个参数,返回一个以世界协调时为基准的时间戳。
在上面介绍Date做为构造函数使用的时候,当参数的个数是1,而且类型是字符串时,会在内部调用Date.parse方法。
咱们平时见过不少表示时间的格式:

"2018-08-08 08:08:08"
"2018/08/08 08:08:08"
"2018/8/8 8:8:8"
...

那么,JavaScript支持的格式有哪些?JavaScript是否支持上述所有格式呢?

根据文档,规范只定义了一种格式:YYYY-MM-DDTHH:mm:ss.sssZ,其中T表明时间的开始,Z表明时区,也就是世界协调时。时区还能够用或者-拼上HH:mm来表示。这也是我为何在开头使用这种格式的缘由。当字符串的格式不符合上述格式的时候,就交给具体的实现本身看着办了。

须要注意的是:

  1. 尽可能使用规范规定的字符串格式,不然可能会出现不一样的浏览器运行结果不一致的问题;
  2. 另外上述格式不是全部部分都有才算合法,能够省略某些部分,日期部分容许的格式以下:

    YYYY
    YYYY-MM
    YYYY-MM-DD

    时刻部分容许的格式以下:

    THH:mm
    THH:mm:ss
    THH:mm:ss.sss

    能够只使用上面的日期格式,也可使用上面的任意一种日期格式+上面的任意一种时刻格式。月、日的默认值是"01",时、分、秒的默认值是"00",毫秒的默认值是"000"。时区缺省的时候,日期+时刻的格式表明的是计算机时区。

    // 只有日期格式
    new Date('2018-08-08') // Wed Aug 08 2018 08:00:00 GMT+0800 (中国标准时间)
    // 日期+时刻格式,时区默认是计算机时区
    new Date('2018-08-08 08:08:08') // Wed Aug 08 2018 08:08:08 GMT+0800 (中国标准时间)
    // 时区为东三区,个人电脑是在东八区,因此输出的时间是08+05,也就是13点
    new Date('2018-08-08 08:08:08+03:00') // Wed Aug 08 2018 13:08:08 GMT+0800 (中国标准时间)

    上面第一个例子,能够发现当只有日期格式的时候,字符串是按照世界协调时解析的,也就是世界协调时的2018年8月8日,因此东八区就变成了8点了。文档只规定了日期+时刻格式默认时区是计算机时区,只有日期的时候并无规定用什么时区,因此尽可能不要用日期格式。
    因此,就我的而言,我以为应该尽可能避免使用字符串格式来实例化一个时间对象。当想建立一个本地时区的时间对象时,可使用上面Date做为构造函数接受27个参数的那种形式去实例化一个时间对象。

  3. 没有进位问题,相应部分超出合法值以外就会报错:

    new Date('2018-08-34') // Invalid Date

Date.UTC(year, month [, date [, hours [, minutes [, seconds [, ms ]]]]])

相似于上面Date做为构造函数时,使用27个参数的形式。不一样之处在于:

  1. 依据的时区不一样,该方法参考世界协调时,而不是计算机时区;
  2. 返回值不一样,该方法返回以世界协调时为基准的时间戳,而不是一个时间对象。

因此,能够经过下述方式建立参数以计算机时区和世界协调时为基准的时间对象:

// 参数是以计算机时区为基准
new Date(2018, 8, 8) // Sat Sep 08 2018 00:00:00 GMT+0800 (中国标准时间)
// 参数是以世界协调时为基准
new Date(Date.UTC(2018, 8, 8)) // Sat Sep 08 2018 08:00:00 GMT+0800 (中国标准时间)

getter相关函数

获取一个时间对象的年、月、日、时、分、秒、毫秒等都有对应的方法,这里再也不赘述,只简述几个注意点:

  1. 上述方法针对计算机时区和世界协调时都有对应的一系列方法,如获取小时:

    // Date.prototype.getHours() 计算机时区
    // Date.prototype.getUTCHours() 世界协调时
    let date = new Date(2018, 8, 8, 8) //Sat Sep 08 2018 08:00:00 GMT+0800 (中国标准时间)
    date.getHours() // 8
    date.getUTCHours() // 0
  2. Date.prototype.getTime()返回时间对象的内部插槽[[DateValue]]的值,也就是以世界协调时为基准的时间戳。

setter相关函数

getter相关函数同样,设置一个时间对象的年、月、日、时、分、秒、毫秒等都有对应的方法,这里一样再也不赘述。只简述几个注意点:

  1. getter相关函数同样,上述方法针对计算机时区和世界协调时都有对应的一系列方法,如设置日期:

    // Date.prototype.setHours() 计算机时区
    // Date.prototype.setUTCHours() 世界协调时
    let date = new Date(2018, 8, 8, 8) //Sat Sep 08 2018 08:00:00 GMT+0800 (中国标准时间)
    date.setHours(9) // Sat Sep 08 2018 09:00:00 GMT+0800 (中国标准时间)
    date.setUTCHours(9) // Sat Sep 08 2018 17:00:00 GMT+0800 (中国标准时间)
  2. 设置月、日、时、分、秒、毫秒的时候,一样会有进位:

    let date = new Date(2018, 8, 8) // Sat Sep 08 2018 00:00:00 GMT+0800 (中国标准时间)
    
    date.setDate(34) // Thu Oct 04 2018 00:00:00 GMT+0800 (中国标准时间)

总结

但愿上述内容对你们有所帮助。若是发现本文有什么错误,您能够在评论区留言。

相关文章
相关标签/搜索