JS原生Date范例要领的一些冷学问

一个多月没更新了- -偷懒中。这个东西着实很早之前就在整理了,不过厥后发明自身不少地方没弄邃晓,然后就一向卡那边了(着实就是不想写吧),想了下反恰是给自身熟习js的原生API罢了,所以也没必要太钻牛角尖,也不一定要多完整,因而就当是Date()函数的一个冷门学问点小补充吧。这篇文章主要讲Date()的字符串与时刻戳转换以及用户时刻当地化,能够内容上比较乱(不然也不会卡我一个月时刻了),包涵

ps:由于Date()是js原生函数,差异浏览器的剖析器对着实现体式格局并差异,所以返回值也会有所区分。本文测试未迥殊申明浏览器的状况下,均是指win7 x64+chrome 44.0.2403.155 (正式版本) m (32 位)版本

Date()与new Date()的区分

Date()直接返回当前时刻字符串,不论参数是number照样任何string

Date();
Date('sssss');
Date(1000);
//Fri Aug 21 2015 15:46:21 GMT+0800 (中国规范时刻)

new Date()则是会根据参数来返回对应的值,无参数的时刻,返回当前时刻的字符串情势;有参数的时刻返回参数所对应时刻的字符串。new Date()对参数不论是花样照样内容都要求,且只返回字符串,

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

从上面几个测试效果能够很轻易发明

  1. new Date()在参数平常的状况只会返回当前时刻的字符串(且是当前时区的时刻)

  2. new Date()在剖析一个详细的时刻的时刻,对参数有较严厉的花样要求,花样不正确的时刻会直接返回Invalid Date,比方将number类的时刻戳转换成string类的时刻也会致使剖析失足

  3. 虽然new Date()的返回值是字符串,然则两个new Date()的效果字符串是能够直接相减的,效果为相差的毫秒数。

那末,new Date()能接收的参数花样究竟是什么规范呢?(相关于严厉要求的多参数传值要领。非严厉的单参数(数字日期示意花样)更经常运用且更轻易失足,所以下文只斟酌单参数数字时刻字符串转换的状况)

new Date()剖析所支撑的参数花样规范

时刻戳花样

这个是最简朴的也是最不轻易失足的。固然唯一的瑕玷也许就是对开发者不直观,没法一眼看出详细日期。
须要注重的以下两点:

  1. js内的时刻戳指的是当前时刻到1970年1月1日00:00:00 UTC对应的毫秒数,和unix时刻戳不是一个观点,后者示意秒数,差了1000倍

  2. new Date(timestamp)中的时刻戳必需是number花样,string会返回Invalid Date。所以比方new Date('11111111')这类写法是错的

时刻数字字符串花样

不大清楚这类该怎样形貌,就是相似YYYY/MM/DD HH:mm:SS这类。下文以dateString代指。
new Date(dateString)所支撑的字符串花样须要满足RFC2822规范或许ISO 8601规范
这两种规范对应的花样离别以下:

  1. RFC2822 规范日期字符串

    YYYY/MM/DD HH:MM:SS ± timezon(时区用4位数字示意)
    // eg 1992/02/12 12:23:22+0800

RFC2822另有别的花样,不过上面这个是比较经常运用的(别的这规范太难啃了,着实没耐烦啃完,所以也就没太深切)。RFC2822规范自身另有其他的非数字日期表达体式格局,不过不在这个话题议论范围内了,略过

  1. 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
     
  1. 日期和时刻中心的T不能够被省略,一省略就失足。

  2. 虽然在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.parseDate.prototype.valueOfDate.prototype.getTimeNumber(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次函数的均匀效果。单元为毫秒)

函数chromeIEFirefox
Date.parse()151.208755.5811315.0446
Date.prototype.getTime()19.545221.342314.0169
Date.prototype.valueOf()20.169621.719213.8096
+Date()20.004431.351122.7861
Number(Date)23.090024.883823.3775

从这个表格能够很轻易得出以下结论:

  1. 从盘算效力上来讲,Date.prototype.getTime()Date.prototype.valueOf()>+DateNumber(Date)>>Date.parse()

  2. 从代码誊写效力上来讲,关于少许的时刻花样化盘算,用+Date()或许Number(Date)即可。而若页面内有大批该处置惩罚,则提议用Date原生的函数Date.prototype.getTime()或许Date.prototype.valueOf().只要Date.parse,找不到任何运用的来由。

  3. 这个效果和盘算机的盘算机能以及浏览器有关,所以详细数字能够会有较大偏差,很平常。然则几个函数效果的时刻差大小递次并不会变。

  4. codepen的在线demo限定比较大,关于这个考试个人提议最好将源代码复制到当地文件然后举行测试

UTC,GMT时刻的区分

这个不是啥主要东西,纯真当课外学问吧。

格林威治规范时刻GMT

GMT即「格林威治规范时刻」(Greenwich Mean Time,简称G.M.T.),指位于英国伦敦郊区的皇家格林威治天文台的规范时刻,由于本初子午线被定义为经由过程那边的经线。然则由于地球的不规则自转,致使GMT时刻有偏差,因而现在已不被看成规范时刻运用。

天下谐和时刻UTC

UTC是最主要的天下时刻规范,是经由均匀太阳时(以格林威治时刻GMT为准)、地轴活动修正后的新时标以及以「秒」为单元的国际原子时所综合精算而成的时刻。UTC比GMT来得越发精准。其偏差值必需保持在0.9秒之内,若大于0.9秒则由位于巴黎的国际地球自转事件中心局宣布闰秒,使UTC与地球自转周期一致。不过一样平常运用中,GMT与UTC的功能与准确度是没有差异的。
谐和天下时区会运用“Z”来示意。而在航空上,一切运用的时刻整齐规定是谐和天下时。而且Z在无线电中应读作“Zulu”(可拜见北约音标字母),谐和天下时也会被称为“Zulu time”。

浏览器猎取用户当前时刻以及喜欢言语

起首须要注重一点,浏览器猎取当前用户地点的时区等信息只和体系的日期和时刻设置里的时区以及时刻有关。区域和言语设置影响的是浏览器默许时刻函数(Date.prototype.toLocaleString等)显现的花样,不会对时区等有影响。以window为例,控制面板\时钟、言语和区域中的两个子设置项目的区分以下:

日期和时刻:设置当前用户所处的时刻和时区,浏览器猎取到的效果以此为准,哪怕用户的设置时刻和时区是完整毛病的。比方若东八区的用户将自身的时区设置为东9区,浏览器就会将视为东9区;时刻数据上同理。这里的设置会影响Date.prototype.getTimezoneOffsetnew Date()的值

区域和言语:主如果设置体系默许的时刻显现体式格局。其子设置的花样会影响Date.prototype.toLocaleString要领返回的字符串效果

浏览器推断用户当地字符串花样

Date有个Date.prototype.toLocaleString()要领能够将时刻字符串返回用户当地字符串花样,这个要领另有两个子要领Date.prototype.toLocaleDateStringDate.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猎取用户浏览器言语喜欢

关于猎取这两种设置,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"]
  1. 从上面的测试效果能够很明显的发明IE浏览器的这几个函数都是猎取体系信息的,没法猎取到前面提到的两个浏览器层面上的设置。(这几个函数详细寄义另有疑问的能够参考MSDN官方文档

  2. window.navigator.language这个函数虽然三个浏览器都能够兼容,然则代表的意义完整差异。IE下该函数返回体系设置的时刻显现花样所恪守的规范的区域代码;chrome下返回浏览器界面言语;FF下返回accept-language的首选言语值

由此:

  1. 浏览器设置的言语accept-language值,IE浏览器没法应用JS猎取。chrome和FF浏览器都能够应用window.navigator.languages来猎取,而FF还能够直接用 window.navigator.language直接猎取accept-language的首选言语值。所以关于accept-language,兼容性最好的猎取要领应该是应用后端,提议一个ajax要求,剖析header。而不是直接js来处置惩罚。

  2. 浏览器界面言语,IE和FF都没法应用js来猎取,chrome能够用window.navigator.language来猎取

  3. 体系级别的言语设置(体系菜单界面言语,体系设置的时刻显现花样),chrome和FF都没法用JS猎取到

总结

这篇文章断断续续地写了一个多月,不过由于对Date()函数的控制不足因而个人感觉着实照样思绪有点乱,所以文章看起来能够轻微有点腾跃性。不过用户当地化那块内容确切用了不少心机去写,愿望对看到这篇文章的人有点协助。

参考文献

  1. Date and Time Formats

  2. Date and Time Specification(RFC2822)

  3. Date.parse()-Differences in assumed time zone

  4. JavaScript and Dates, What a Mess!

  5. navigator object(IE浏览器私有language函数的剖析)

    原文作者:chitanda
    原文地址: https://segmentfault.com/a/1190000003710954
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞