一个多月没更新了- -偷懒中。这个东西其实很早以前就在整理了,不事后来发现本身很多地方没弄明白,而后就一直卡那边了(其实就是不想写吧),想了下反正是给本身熟悉js的原生API而已,因此也不必太钻牛角尖,也不必定要多完整,所以就当是Date()
函数的一个冷门知识点小补充吧。这篇文章主要讲Date()的字符串与时间戳转换以及用户时间本地化,可能内容上比较乱(否则也不会卡我一个月时间了),见谅javascript
ps:因为Date()
是js原生函数,不一样浏览器的解析器对其实现方式并不一样,因此返回值也会有所区别。本文测试未特别申明浏览器的状况下,均是指win7 x64
+chrome 44.0.2403.155 (正式版本) m (32 位)
版本html
Date()
直接返回当前时间字符串,无论参数是number仍是任何stringjava
Date(); Date('sssss'); Date(1000); //Fri Aug 21 2015 15:46:21 GMT+0800 (中国标准时间)
而new Date()
则是会根据参数来返回对应的值,无参数的时候,返回当前时间的字符串形式;有参数的时候返回参数所对应时间的字符串。new Date()
对参数不论是格式仍是内容都要求,且只返回字符串,ajax
new Date(); //Fri Aug 21 2015 15:51:55 GMT+0800 (中国标准时间) new Date(1293879600000); new Date('2011-01-01T11:00:00') new Date('2011/01/01 11:00:00') new Date(2011,0,1,11,0,0) new Date('jan 01 2011,11 11:00:00') new Date('Sat Jan 01 2011 11:00:00') //Sat Jan 01 2011 11:00:00 GMT+0800 (中国标准时间) new Date('sss'); new Date('2011/01/01T11:00:00'); new Date('2011-01-01-11:00:00') new Date('1293879600000'); //Invalid Date new Date('2011-01-01T11:00:00')-new Date('1992/02/11 12:00:12') //596069988000
从上面几个测试结果能够很容易发现chrome
new Date()
在参数正常的状况只会返回当前时间的字符串(且是当前时区的时间)后端
new Date()
在解析一个具体的时间的时候,对参数有较严格的格式要求,格式不正确的时候会直接返回Invalid Date
,好比将number
类的时间戳转换成string
类的时候也会致使解析出错浏览器
虽然new Date()
的返回值是字符串,然而两个new Date()
的结果字符串是能够直接相减的,结果为相差的毫秒数。服务器
那么,new Date()
能接受的参数格式究竟是什么标准呢?(相对于严格要求的多参数传值方法。非严格的单参数(数字日期表示格式)更经常使用且更容易出错,因此下文只考虑单参数数字时间字符串转换的状况)函数
这个是最简单的也是最不容易出错的。固然惟一的缺点大概就是对开发者不直观,没法一眼看出具体日期。
须要注意的如下两点:性能
js内的时间戳指的是当前时间到
1970年1月1日00:00:00 UTC
对应的毫秒数,和unix时间戳不是一个概念,后者表示秒数,差了1000倍
new Date(timestamp)
中的时间戳必须是number
格式,string
会返回Invalid Date
。因此好比new Date('11111111')
这种写法是错的
不大清楚这种该怎么描述,就是相似YYYY/MM/DD HH:mm:SS
这种。下文以dateString
代指。new Date(dateString)
所支持的字符串格式须要知足RFC2822标准或者ISO 8601标准
这两种标准对应的格式分别以下:
RFC2822 标准日期字符串
YYYY/MM/DD HH:MM:SS ± timezon(时区用4位数字表示) // eg 1992/02/12 12:23:22+0800
RFC2822还有别的格式,不过上面这个是比较经常使用的(另外这标准太难啃了,实在没耐心啃完,因此也就没太深刻)。RFC2822标准自己还有其余的非数字日期表达方式,不过不在这个话题讨论范围内了,略过
ISO 8601标准日期字符串
YYYY-MM-DDThh:mm:ss ± timezone(时区用HH:MM表示) 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
日期和时间中间的
T
不能够被省略,一省略就出错。虽然在chrome浏览器上时区也能够用
+0100
这种RFC2822的形式来表示,然而IE上不支持这种混搭写法,因此用ISO8601标准形式表示的时候时区要用+HH:MM
单单从格式上来讲,二者的区别主要在于分隔符的不一样。不过须要注意的是,ISO 8601标准的兼容性比RFC2822差得多(好比IE8和iOS均不支持前者。我知道IE8不少人会无视,不过iOS也有这个坑的话,各位或多或少会谨慎点了吧?),因此通常状况下建议用RFC 2822
格式的。
不过须要注意的是,在未指定时区的前提下,对于只精确到day
的日期字符串,RFC 2822
返回结果是以当前时区的零点
为准,而ISO8601
返回结果则会以UTC时间
的零点为标准进行解析。
例如:
//RFC2822: new Date('1992/02/13') //Thu Feb 13 1992 00:00:00 GMT+0800 (中国标准时间) //ISO8601: new Date('1992-02-13') //Thu Feb 13 1992 08:00:00 GMT+0800 (中国标准时间)
然而上面这个只是ES5的标准而已,在ES6里这两种形式都会变成当前时区的零点
为基准1无论大家崩溃没,反正我是已经想死了
关于跨浏览器的dataString解析状况,还能够参考这个页面:
JavaScript and Dates, What a Mess!
因此对于时间字符串对象,我的意见是要么用RFC2822
形式,要么本身写个解析函数而后随便你传啥格式进来。
这里的时间格式化
值得是将时间字符串转换成毫秒数的过程。js原生的时间格式化函数有Date.parse
、Date.prototype.valueOf
、Date.prototype.getTime
、Number(Date)
、+Date
(还有个Date.UTC
方法,然而对参数要求严格,不能直接解析日期字符串,因此略过)
这5个函数从功能上来讲如出一辙,可是具体的效率如何呢?我写了个检测页面,诸位也能够本身测试下。
http://codepen.io/chitanda/pen/NqeZag/
function test(dateString,times,func){ var startTime=window.performance.now(); // console.log('start='+startTime.getTime()); for (var i = 0; i < times; i++) { func(dateString);//这里填写具体的解析函数 }; var endTime=window.performance.now(); // console.log('endTime='+endTime.getTime()); var gapTime=endTime-startTime; console.log('一共耗时:'+gapTime+'ms'); // console.log('时间字符串'+dateString); return gapTime; }
之因此这里用
window.performance.now()
而不用new Date()
,是由于前者精确度远比后者高。后者只能精确到ms。会对结果形成较大影响
单次执行50W次时间格式化函数,并重复测试100次,最后的结果以下:
(表格中的数字为单次执行50W次函数的平均结果。单位为毫秒)
函数 | chrome | IE | Firefox |
---|---|---|---|
Date.parse() | 151.2087 | 55.5811 | 315.0446 |
Date.prototype.getTime() | 19.5452 | 21.3423 | 14.0169 |
Date.prototype.valueOf() | 20.1696 | 21.7192 | 13.8096 |
+Date() | 20.0044 | 31.3511 | 22.7861 |
Number(Date) | 23.0900 | 24.8838 | 23.3775 |
从这个表格能够很容易得出如下结论:
从计算效率上来讲,
Date.prototype.getTime()
≈Date.prototype.valueOf()
>+Date
≈Number(Date)
>>Date.parse()
从代码书写效率上来讲,对于少许的时间格式化计算,用
+Date()
或者Number(Date)
便可。而若页面内有大量该处理,则建议用Date原生的函数Date.prototype.getTime()
或者Date.prototype.valueOf()
.只有Date.parse
,找不到任何使用的理由。这个结果和计算机的计算性能以及浏览器有关,因此具体数字可能会有较大误差,很正常。然而几个函数结果的时间差大小顺序并不会变。
codepen的在线demo限制比较大,对于这个测验我的建议最好将源代码复制到本地文件而后进行测试
这个不是啥重要东西,单纯当课外知识吧。
GMT即「格林威治标准时间」(Greenwich Mean Time,简称G.M.T.),指位于英国伦敦郊区的皇家格林威治天文台的标准时间,由于本初子午线被定义为经过那里的经线。然而因为地球的不规则自转,致使GMT时间有偏差,所以目前已不被看成标准时间使用。
UTC是最主要的世界时间标准,是通过平均太阳时(以格林威治时间GMT为准)、地轴运动修正后的新时标以及以「秒」为单位的国际原子时所综合精算而成的时间。UTC比GMT来得更加精准。其偏差值必须保持在0.9秒之内,若大于0.9秒则由位于巴黎的国际地球自转事务中央局发布闰秒,使UTC与地球自转周期一致。不过平常使用中,GMT与UTC的功能与精确度是没有差异的。
协调世界时区会使用“Z”来表示。而在航空上,全部使用的时间划一规定是协调世界时。并且Z在无线电中应读做“Zulu”(可参见北约音标字母),协调世界时也会被称为“Zulu time”。
首先须要注意一点,浏览器获取当前用户所在的时区等信息只和系统的日期和时间
设置里的时区以及时间有关。区域和语言
设置影响的是浏览器默认时间函数(Date.prototype.toLocaleString等)显示的格式,不会对时区等有影响。以window为例,控制面板\时钟、语言和区域
中的两个子设置项目的区别以下:
日期和时间
:设置当前用户所处的时间和时区,浏览器获取到的结果以此为准,哪怕用户的设置时间和时区是彻底错误的。好比若东八区的用户将本身的时区设置为东9区,浏览器就会将视为东9区;时间数据上同理。这里的设置会影响Date.prototype.getTimezoneOffset
、new Date()
的值
区域和语言
:主要是设置系统默认的时间显示方式。其子设置的格式
会影响Date.prototype.toLocaleString
方法返回的字符串结果
Date有个Date.prototype.toLocaleString()
方法能够将时间字符串返回用户本地字符串格式,这个方法还有两个子方法Date.prototype.toLocaleDateString
和Date.prototype.toLocaleTimeString
,这两个方法返回值分别表示日期
和时间
,加一块儿就是Date.prototype.toLocaleString
的结果。
这个方法的默认参数会对时间字符串作一次转换,将其转换成用户当前所在时区的时间,并按照对应的系统设置时间格式返回字符串结果。然而不一样浏览器对用户本地所使用的语言格式的判断依据是不一样的。
IE:获取系统当前的区域和语言
-格式
中设置的格式,依照其对应的格式来显示当前时间结果;IE浏览器实时查询该系统设置(即你在浏览器窗口打开后去更改系统设置也会引发返回格式变化)
FF:获取方式和结果与IE浏览器相同,区别在于FF只会在浏览器进程第一次启动的时候获取一次系统设置,中间无论怎么系统设置怎么变化,FF都没法获取到当前系统设置。除非重启FF浏览器。
Chrome:获取方式和以上两个都不一样。chrome无视系统的区域和语言
-格式
格式,只依照本身浏览器的界面设置的菜单语言来处理。(好比英文界面则按系统'en-US'格式返回字符串,中文界面则按系统'zh-CN'格式返回结果)
综上可得:
chrome下浏览器语言设置优先系统语言设置。而IE和FF则是系统语言设置优先浏览器语言设置,无论浏览器界面语言是什么,他们只依照系统设置来返回格式。(没有MAC,因此不知道safari是啥状况,等之后看状况补充吧)
另外,不一样浏览器对toLocaleString
返回的结果也是不一样的,IE浏览器严格遵照系统设置,而chrome和FF会有本身内置的格式来替换。
这小节貌似有点跑题,然而不说明下的很容易和上面提到的浏览器设置的语言混淆,因此也拿出来讲一下。
须要注意浏览器的语言设置和界面语言设置不是一回事。浏览器的语言设置
设置的是浏览器发送给服务器的Request Header
里的Accept-Language
的值,这个值能够告诉服务器用户的喜爱语言,对于某些跨国网站,服务器能够以此为依旧来返回对应语言的页面(不过实际应用上这个限制比较大,大部分网站仍是根据IP来判断用户来源的,或者直接让用户本身选择)
对于各大浏览器而言,这个设置的更改也是比较显性,容易找到的。
IE: Internet选项
-语言
FF: 选项
-内容
-语言
chrome:设置
-显示高级设置
-语言
-语言和输入设置...
上面这里的设置不会影响到浏览器的界面语言设置,以国内大部分用户而言,即无论你怎么设置这里的语言选项,浏览器菜单等默认都会是以中文显示的.
而浏览器的界面语言设置
通常来讲则藏的深得多,没那么容易找到。
IE:
卸载前面安装过的浏览器语言包,去微软官网下载对应的IE浏览器语言包安装。(和安装的语言包有关。系统界面语言和该语言包相同的状况下,变为该语言。不然以安装的语言包为准。)
FF:地址栏输入about:config
,而后找到general.useragent.locale
字段,修改对应字段便可。
chrome:设置
-显示高级设置
-语言
-语言和输入设置...
对于获取这两种设置,js原生方法支持度都比较通常:
IE下的navigator
方法有四种和language
有关的方法,区别以下:
假设系统语言为 ja-JP
,系统unicode语言为zh-CN
日期格式为nl-NL
,浏览器语言设置(accept-language)为de
,浏览器界面语言为en-US
(其余条件不变,浏览器界面语言改成zh-CN
的时候结果也是同样),
window.navigator.language //"nl-NL" window.navigator.systemLanguage //"zh-CN"(设置中的非unicode程序所使用语言选项) window.navigator.userLanguage //"nl-NL" window.navigator.browserLanguage //"ja-JP"(系统菜单界面语言) window.navigator.languages //undefined
chrome下,当浏览器界面语言为zh-CN
,accept-language
首位为en-US
的时候:
window.navigator.language //'zh-CN' window.navigator.languages //["en-US", "en", "zh-CN", "zh", "ja", "zh-TW", "de-LI", "de", "pl"] //当界面语言改成"en-US"时 window.navigator.language //'en-US'(浏览器界面语言)
FF下,当浏览器界面语言为zh-CN
,accept-language
首位为en-US
的时候:
window.navigator.language //'en-US' window.navigator.languages //["en-US", "zh-CN", "de", "zh", "en"] //当界面语言改成"en-US",`accept-language`首位为`zh-CN`的时候 window.navigator.language //'zh-CN'(`accept-language`首选值) window.navigator.languages //["zh-CN", "de", "zh", "en-US", "en"]
从上面的测试结果能够很明显的发现IE浏览器的这几个函数都是获取系统信息的,没法获取到前面提到的两个浏览器层面上的设置。(这几个函数具体含义还有疑问的能够参考MSDN官方文档)
window.navigator.language
这个函数虽然三个浏览器均可以兼容,然而表明的意义彻底不一样。IE下该函数返回系统设置的时间显示格式所遵照的标准的地区代码;chrome下返回浏览器界面语言;FF下返回accept-language
的首选语言值
由此:
浏览器设置的语言
即accept-language
值,IE浏览器没法利用JS获取。chrome和FF浏览器均可以利用window.navigator.languages
来获取,而FF还能够直接用window.navigator.language
直接获取accept-language
的首选语言值。因此对于accept-language
,兼容性最好的获取方法应该是利用后端,发起一个ajax请求,分析header。而不是直接js来处理。
浏览器界面语言
,IE和FF都没法利用js来获取,chrome能够用window.navigator.language
来获取系统级别的语言设置(系统菜单界面语言,系统设置的时间显示格式),chrome和FF都没法用JS获取到
这篇文章断断续续地写了一个多月,不过因为对Date()
函数的掌握不足所以我的感受其实仍是思路有点乱,因此文章看起来可能稍微有点跳跃性。不过用户本地化那块内容确实用了很多心思去写,但愿对看到这篇文章的人有点帮助。