[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
- HTML
- 标签
- 超链接
- 列表
- 表格和表单
- h5新增标签
- 快捷方式
- 标签包含
- CSS
- 选择器
- 行内,块元素,链接
- css三大特性
- 盒子模型
- 定位
- css可见性
- emment书写
- 文本元素
- 外观属性
- 背景
- 浮动
- ps
- 用户界面样式
- 显示和隐藏
- 过渡
- 2D,3D变形
- 动画animation
- 伸缩布局(CSS3)
- BFC
- 优雅降级和渐进增强
- 3D旋转
- 双飞翼和圣杯
- JS基础
- 输出消息的几种方式
- 数据类型
- Date对象
- Math对象
- Array对象
- 字符串常用方法
- 数据类型转换
- 等号运算
- 代码调试
- 数组
- 函数
- WebAPI
- webapi简介
- 获取页面元素
- 事件
- 属性操作
- 创建元素
- 节点操作
- 事件详解
- BOM
- 位置相关属性
- 拖拽弹窗
- 弹出层加遮罩
- ES6
- let和const
- 解构表达式变化
- 函数优化
- map和reduce
- nrm
- npm
- npm基础
- package.json
- 淘宝镜像
- webpack
- 介绍
- 多入口文件(Multiple entry files)
- Webpack CSS loader加载器
- webpack Image loader 加载图片
- uglify-js压缩打包JS
- webpack构建本地服务器
- vue内部指令
- v-if,v-show,v-for
- v-text,v-html
- v-on
- v-model
- v-bind
- v-pre,v-cloak,v-once
- vue全局api
- Vue.directive 自定义指令
- vue.extend构造器的延伸
- vue.set全局操作
- Vue的生命周期(钩子函数)
- Template 制作模版
- Component 初识组件
- Component 组件props 属性设置
- Component 父子组件关系
- Component 标签
- vue选项
- propsData Option全局扩展数据传递
- computed Option 计算选项
- Methods Option 方法选项
- watch选项监控数据
- Mixins 混入选项操作
- Extends Option 扩展选项
- delimiters 选项
- vue实例和内置组件
- 实例属性
- 实例方法
- 实例事件
- 内置组件 -slot
- vue-cli
- vue-cli介绍
- 项目目录结构
- vue-cli模板
- vue-router
- 简介
- 配置子路由
- 参数传递
- 单页面多路由区域操作
- url传递参数
- vscode