ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
[TOC] # date对象 ## 构造 ~~~ new Date() :返回当前的本地日期和时间 new Date(milliseconds) :把毫秒数转换为 Date 对象 new Date(-1000 * 60 * 1); // 倒退1分钟的毫秒数 ~~~ ~~~ new Date(dateStr) :把字符串转换为 Date 对象 参数: 1) yyyy/MM/dd HH:mm:ss (推荐):若省略时间,返回的 Date 对象的时间为 00:00:00。 2) yyyy-MM-dd HH:mm:ss :若省略时间,返回的 Date 对象的时间为 08:00:00(加上本地时区)。若不省略时间,此字符串在IE中会转换失败! 3) new Date('August 19, 1975 23:15:30 GMT-02:00'); ~~~ ~~~ new Date(year, month, opt_day, opt_hours, opt_minutes, opt_seconds, opt_milliseconds) :把年月日、时分秒转换为 Date 对象 参数 ①year {int} :年份;4位数字。如:1999、2014 ②month {int} :月份;2位数字。从0开始计算,0表示1月份、11表示12月份。 ③opt_day {int} 可选:号; 2位数字;从1开始计算,1表示1号。 ④opt_hours {int} 可选:时;2位数字;取值0~23。 ⑤opt_minutes {int} 可选:分;2位数字;取值0~59。 ⑥opt_seconds {int} 可选:秒;2未数字;取值0~59 ⑦opt_milliseconds {int} 可选:毫秒;取值0~999 ~~~ ## 实例方法 Date 对象的实例方法主要分为2种形式:本地时间和 UTC 时间。同一个方法,一般都会有此2种时间格式操作(方法名带 UTC 的,就是操作 UTC 时间),这里主要介绍对本地时间的操作。 ### get方法 * getFullYear() :返回 Date 对象的年份值;4位年份。 * getMonth() :返回 Date 对象的月份值。从0开始,所以真实月份=返回值+1 。 * getDate() :返回 Date 对象的月份中的日期值;值的范围1~31 。 * getHours() :返回 Date 对象的小时值。 * getMinutes() :返回 Date 对象的分钟值。 * getSeconds() :返回 Date 对象的秒数值。 * getMilliseconds() :返回 Date 对象的毫秒值。 * getDay() :返回 Date 对象的一周中的星期值;0为星期天,1为星期一、2为星期二,依此类推 * getTime() :返回 Date 对象与'1970/01/01 00:00:00'之间的毫秒值(北京时间的时区为东8区,起点时间实际为:'1970/01/01 08:00:00') 。 ### set 方法 * setFullYear(year, opt\_month, opt\_date) :设置 Date 对象的年份值;4位年份。 * setMonth(month, opt\_date) :设置 Date 对象的月份值。0表示1月,11表示12月。 * setDate(date) :设置 Date 对象的月份中的日期值;值的范围1~31 。 \-setHours(hour, opt\_min, opt\_sec, opt\_msec) :设置 Date 对象的小时值。 * setMinutes(min, opt\_sec, opt\_msec) :设置 Date 对象的分钟值。 * setSeconds(sec, opt\_msec) :设置 Date 对象的秒数值。 * setMilliseconds(msec) :设置 Date 对象的毫秒值。 ### 其他方法 * toString() :将 Date 转换为一个'年月日 时分秒'字符串 * toLocaleString() :将 Date 转换为一个'年月日 时分秒'的本地格式字符串 * toDateString() :将 Date 转换为一个'年月日'字符串 * toLocaleDateString() :将 Date 转换为一个'年月日'的本地格式字符串 * toTimeString() :将 Date 转换为一个'时分秒'字符串 * toLocaleTimeString() :将 Date 转换为一个'时分秒'的本地格式字符串 * valueOf() :与getTime()一样, 返回 Date 对象与'1970/01/01 00:00:00'之间的毫秒值(北京时间的时区为东8区,起点时间实际为:'1970/01/01 08:00:00') ### 静态方法 #### Date.now() 说明:返回当前日期和时间的 Date 对象与'1970/01/01 00:00:00'之间的毫秒值(北京时间的时区为东8区,起点时间实际为:'1970/01/01 08:00:00') 参数:无 返回值: {int} :当前时间与起始时间之间的毫秒数。 #### Date.parse(dateStr) 说明:把字符串转换为 Date 对象 ,然后返回此 Date 对象与'1970/01/01 00:00:00'之间的毫秒值(北京时间的时区为东8区,起点时间实际为:'1970/01/01 08:00:00') 参数: ①dateStr {string} :可转换为 Date 对象的字符串(可省略时间);字符串的格式主要有两种: 1) yyyy/MM/dd HH:mm:ss (推荐):若省略时间,返回的 Date 对象的时间为 00:00:00。 2) yyyy-MM-dd HH:mm:ss :若省略时间,返回的 Date 对象的时间为 08:00:00(加上本地时区)。若不省略时间,此字符串在IE中返回NaN(非数字)! 返回值: {int} 返回转换后的Date对象与起始时间之间的毫秒数。 # 时区问题 ## 如何获取时区? 如果想在js中获取一个日期的时区,可以直接使用 [Date.prototype.getTimezoneOffset()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getTimezoneOffset). ~~~ var dateLocal = new Date(); var date1 = new Date('August 19, 1975 23:15:30 GMT+07:00'); var date2 = new Date('August 19, 1975 23:15:30 GMT-02:00'); console.log(dateLocal.getTimezoneOffset()); console.log(date1.getTimezoneOffset()); console.log(date2.getTimezoneOffset()); // -480 // -480 // -480 ~~~ `getTimezoneOffset`返回的结果,是当前地方时和UTC时间的差值,用分钟表示。上述 `dateLocal` 可以理解为,`( 0时区 - 本地时区(+8) ) * 60min = -480`. 所以想获得标准的时区,例如 +8 或 -8,需要进行以下处理: ~~~ // 使用原生 js var date = new Date().getTimezoneOffset(); var timezone = -date; console.log(timezone); // 480 console.log(timezone / 60); // 8 // 使用 moment (moment是基于local - utc得到的) var date = moment(); var timezone = date.utcOffset(); console.log(timezone); // 480 console.log(timezone / 60); // 8 ~~~ 看到输出结果,大家可能会问为什么 date1 和 date2 的输出结果不是 +7 和 -2? 这个问题后面会为大家解答。 ## 如何设置时区? Date 对象提供了给实例 set 日期、时间的方法,但是并不支持修改实例的时区。 详情可以参考 [Date.prototype 提供的方法](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date)。 ISO标准类型有: * `"2019-06-10"` (date-only form) * `"2019-06-10T14:48:00"` (date-time form) * `"2019-06-10T14:48:00.000+09:00"` (date-time form with milliseconds and time zone) * `"2019-06-10T00:00:00.000Z"` (specifying UTC timezone via the ISO date specification,Z is the same with +00:00) 一些非ISO标准的类型: * `Aug 9, 1995` * `Wed, 09 Aug 1995 00:00:00` * `Wed, 09 Aug 1995 00:00:00 GMT` # 常见问题 ## 实例化 Date 对象时传入了时区,为什么获取的时区是本地时区? ~~~ var date1 = new Date('August 19, 1975 23:15:30 GMT+07:00'); var date2 = new Date('August 19, 1975 23:15:30 GMT-02:00'); console.log(date1.getTimezoneOffset()); console.log(date2.getTimezoneOffset()); // -480 // -480 ~~~ 需要注意,不管你如何实例化一个 Date 对象,js在本地存储时,都会将它转换成本地时区。js 不会帮你存储实例化该日期时的时区信息。 ~~~ new Date('June 15, 2019 23:15:30 GMT+10:00'); // 东10区的时间,实例化成功后,日期被转换成了本地时区 // Sat Jun 15 2019 21:15:30 GMT+0800 (中国标准时间) ~~~ 那怎样才能获得一个携带了指定时区的日期对象呢?答案是,**JS原生日期对象并不支持**。 无法想象RD同学跟PM满脸无辜的解释"JS办不到"之后,被PM追着砍的场景,因为还好[moment](https://momentjs.com/timezone/)支持了。 如下图所示,直接声明一个moment实例,并不会携带任何`offset`信息,因为这是一个 UTC 时间,只不过基于 js Date 的特性,直接`toDate`打印的结果会基于本地时区给你进行展示。 通过调用 `tz()` 方法,我们给一个moment实例指定了时区,这个时区是东京所在的 +9 区。这时能看到,这个moment实例拥有了`offset`属性。继续调用`format('Z')`,可以得到其时区为"+09:00". ## 如何处理 YYYY-MM-DD 这样的日期字符串? 在js中,很多时候需要把日期字符串转换为一个 Date 对象。如果得到的日期字符串有时间还好办,如果就是一个`"2019-10-10"`这样的字符串呢? 大部分人可能什么都没想,直接就调用了 `new Date(datestring)`。可是事情没有想象中那么简单。让我们来对比一下: ~~~ var date1 = new Date('2019-10-10') // Thu Oct 10 2019 08:00:00 GMT+0800 (中国标准时间) var date2 = new Date('2019-10-10 00:00:00') // Thu Oct 10 2019 00:00:00 GMT+0800 (中国标准时间) ~~~ 可以发现,直接输入日期,和输入日期+时间,得到的结果差了整整8个小时! 直接给new Date传入'YYYY-MM-DD'这样的字符串,得到的是一个基于UTC时间的Date实例。前文有说过,UTC时间即是0时区的标准时间。 所以上面的代码例子中,`date1` 实例化时,内部先获取到了一个`2019-10-10 00:00:00 GMT+00:00`这样的时间,再被转为本地时区,就多了8个小时。 而`date2`实例化时,`2019-10-10 00:00:00`被当做`GMT +08:00`的时区,所以得到的时间,就是0点。 这两种方式没有对与错之分,但是使用的时候需要十分注意。个人不建议使用`new Date(YYYY-MM-DD)`这样的方式。 说了一堆理论,到底哪些场景要注意问题呢?Show you the code: ~~~ // code is runningg on GMT +08:00 const d = new Date('2019-10-10'); const date = d.getDate(); // 10 // Looks good! // code is runningg on GMT -10:00 const d = new Date('2019-10-10'); const date = d.getDate(); // 9 // Amazing?! ~~~ 总结上面的代码:在小于0时区的地方,直接用 new Date('YYYY-MM-DD') 这样的方式实例化日期并且获取日期,永远会少一天。但是使用 new Date('YYYY-MM-DD 00:00:00') 就不会。 使用 moment 可以轻松的解决上述问题: ~~~ moment('2019-10-10').toDate() // Thu Oct 10 2019 00:00:00 GMT+0800 (中国标准时间) moment('2019-10-10 00:00:00').toDate() // Thu Oct 10 2019 00:00:00 GMT+0800 (中国标准时间) ~~~ ## 为什么 safari 调用 new Date 老报错? 下面这段代码确实会报错: ~~~ new Date('2019-10-10 00:00:00') // Invalid Date 复制代码 ~~~ 老司机们可能知道safari一直以来都有上述bug,为了解决这个问题,可以使用以下代码: ~~~ new Date('2019/10/10 00:00:00') // Thu Oct 10 2019 00:00:00 GMT+0800 (CST) ~~~ ## 有哪些好用的处理时区与日期的工具库? * [Moment.js](https://momentjs.com/) - Parse, validate, manipulate, and display dates and times in JavaScript * [Moment Timezone](https://momentjs.com/timezone/) - Parse and display dates in any timezone * [DAY.JS](https://github.com/iamkun/dayjs) - A minimalist JavaScript library for modern browsers with a largely Moment.js-compatible API * [date-fns](https://date-fns.org/) - Modern JavaScript date utility library