看一个问题:
let a = new Date('4/29/2019')
console.log(a)// Mon Apr 29 2019 00:00:00 GMT+0800 (中国标准时间)
a.valueOf() // 1556467200000
let b = new Date('2019-04-29')
console.log(b)// Mon Apr 29 2019 08:00:00 GMT+0800 (中国标准时间)
b.valueOf() // 1556496000000
a == b // false
为什么看起来是同一个时间的字符串,解析之后却是两个时间,相隔8小时?
这涉及到时间字符串格式的两个标准。前者4/29/2019
是RFC2822格式,后者是ISO 8601格式。
YYYY/MM/DD HH:MM:SS ± timezone(时区用4位数字表示)
// 例如 1992/02/12 12:23:22+0800
Date对象使用toString方法,返回RFC2822格式的完整时间。默认打印Date对象,会调用其toString()方法。如上面的a、b。
国际标准化组织的国际标准ISO 8601,是日期和时间的表示方法。
YYYY-MM-DDThh:mm:ss ± timezone(时区用HH:MM表示,中间有一个T)
1997-07-16T08:20:30Z
// “Z”表示UTC标准时区,即"00:00"
// 所以这里表示零时区的1997年7月16日08时20分30秒
// 转换成位于东八区的北京时间则为1997年7月17日16时20分30秒
1997-07-16T19:20:30+01:00
// 表示东一区的1997年7月16日19时20秒30分
// 转换成UTC标准时间的话是1997-07-16T18:20:30Z
有时在时间字符串会看到GMT。
十七世纪,格林威治皇家天文台为了海上霸权的扩张计画而进行天体观测。1675年旧皇家观测所正式成立,到了1884年决定以通过格林威治的子午线作为划分地球东西两半球的经度零度。观测所门口墙上有一个标志24小时的时钟,显示当下的时间,对全球而言,这里所设定的时间是世界时间参考点,全球都以格林威治的时间作为标准来设定时间,这就是格林威治标准时间(Greenwich Mean Time,简称GMT)的由来。
例如:
“Fri Jul 20 2018 00:00:00 GMT+0800 (中国标准时间)”
GMT在时间字符串中是有特定含义的间隔符。
UTC指的是Coordinated Universal Time- 世界协调时间(又称世界标准时间、世界统一时间),是经过平均太阳时(以格林威治时间GMT为准)、地轴运动修正后的新时标以及以「秒」为单位的国际原子时所综合精算而成的时间,计算过程相当严谨精密,因此若以「世界标准时间」的角度来说,UTC比GMT来得更加精准。其误差值必须保持在0.9秒以内。
UTC时间字符串仍然是带有GMT符号,例如:
new Date().toUTCString()
// "Mon, 29 Apr 2019 09:52:21 GMT"
对于toUTCString方法,以RFC2822格式返回标准时间的时间字符串,UTC是零时区,所以GMT后面是空的。
有4种:
// 不带new操作符,像一个函数一样调用。它将忽略所有传入的参数,并返回当前日期和时间对象。
1,new Date();
// 可接受一个数字参数,该参数表示设定时间与1970年1月1日0点之间的毫秒数。
2,new Date(value);
// 可接受一个字符串参数,参数形式类似于Date.parse()方法。
3,new Date(dateStr);
// Date对象也有一个parse方法,用于解析一个日期字符串,参数是一个包含待解析的日期和时间的字符串,返回从1970年1月1日0点到给定日期的毫秒数。
// 但parse()方法返回的是一个数字,而Date()函数返回的是一个对象。
Data.parse(dataStr)
// 可接受参数形式类似于Date.UTC()方法的参数,但Date.UTC()方法返回是一个毫秒数,且是UTC时间,而Date()函数返回是一个对象,且是本地时间。
4,new Date(year, month[, day[, hour[, minutes[, seconds[, milliseconds]]]]]);
注意:月份month参数,其计数方式从0开始,而天day参数,其计数方式从1开始。另外,getUTCDate()不能替换getUTCDay()。这是因为getUTCDate()返回the day of the month;而getUTCDay()返回the day of the week。
Date对象有valueOf,可以直接加减操作,也可以比大小。
var date1 = new Date(2007,0,1);
var date2 = new Date(2007,1,1);
console.log(date1 > date2);//false
console.log(date1 < date2);//true
有时间做活动时间判断,如果在用户端比较,注意时区加8个小时:
let eventStartTime = new Date('2019/05/01 00:00:00 GMT+0800');
let eventEndTime = new Date('2019/05/05 00:00:00 GMT+0800');
let eventDateNow = new Date()
let showOption = eventStartTime < eventDateNow && eventDateNow < eventEndTime
以上对中国北京时区程序有效。
如果需要从当前的时间对象获取其相应的时间戳,我们可以使用getTime或者valueOf(),返回距离1970年1月1日0点的毫秒数。
在ES5的标准中,没有提供时区的字符串将默认为标准时区。本文开头的问题即由此引起。
在数据库中存储的时间,一定要是UTC时间戳。前端从后台拿到时间戳以后,要转化为本地时间对象,再格式化对人类阅读友好的文本。
涉及时间的格式化,推荐使用 moment,网址:http://momentjs.com
moment()返回当前时间(本地时间),格式化示例:
moment().format('YYYY-MM-DD, h:mm:ss')
转化为人类友好文本:
moment("20111031", "YYYYMMDD").fromNow(); // 7 years ago
以上,不知道写明白没有。