date类型怎么写

前言

hi,大家国庆节快乐,早读君如期来了。今天要分享的这篇文章是第17号台风来的那晚在宿舍里翻译的。在台灯下敲着文字,那种感觉非常宁静,早读君很喜欢这种的状态。今天这篇文章得到作者@Will保哥的授权,谢谢~

正文从这开始~

今天这篇文章,我想来谈谈Java到底是如何实现[日期字符串]格式解析,日期时间有太多种的表达方式,一般人在刚接触日期格式的时候,都不会想太多跨浏览器的问题,通常都是遇到问题的时候才来埋怨浏览器有多烂多烂。有趣的是,有时候还会错怪对象,例如xxx框架好烂,我写JS这么久都没遇到过这种问题,用了xxx框架才遇到的。现在,我们就开头开始来说对这个说常用不常用,用到时不熟悉的[日期]类型。

我这几年遇到Java的许多灵异事件,除了Number意外,就属Date最诡异了,美国一段时间就会爆出惊人的意外之喜。

基本上我们在建立Date对象的时候,只有4种用法:

  • new Date();

  • new Date(value);

  • new Date(dateString);

  • new Date(year,month[,day,[,hour[,minutes[,seconds[,milliseconds]]]]])

这四种用法中,最安全的用法应该就属第一种与第二种的用法了:

第一种new Date();会产生当下的本地时间。

第二种new Date(value);需传入一个整数值,从数值时从 1970-01-01 00:00:00 UTC ( UTC = GMT ) (格林威治标准时间原由网)到现在的好秒数(milliseconds)。

请注意:

你在任何浏览器开发者工具的Console模式下,只要输出Date对象的结果,一律都会使用[本地时间]来显示该对象的日期时间

第三种 new Date(dateString) 是我们这篇文章讨论的重点,也是最雷的用法。

一般来说,我们比较少会直接用 new Date(dateString)语法来创建日期对象,如果会直接用,通常都是先从Ajax或其他地方读取一个[日期格式的字符串]值,然后才透过new Date(dateString)解析字符串为Date类型的对象。不过,大部分时间都是读取数据后直接输出字符串的,因此大家不用会遇到解析日期的问题。

但如果牵扯到日期的相关计算,例如想要计算两个日期之间的天数,或是想知道从特定时间点算起60天后是几月几号,或是想显示自定义的日期格式,都很有可能会用到日期字符串格式来解析。

这部分较长,我打算先介绍完第四种之后再回头来介绍这种用法。

第四种算是非常浅显易懂的,但这种看似简单的API,大家都要小心。

你直接从下图看看我如何测试几种日期用法的,你有发现奇妙的地方吗?

是的,没错,我们传入的第二个参数为月份,但是你传入的是9,却返回的是10月,因为只有这个月份的参数是从0开始计算的,没人知道为什么

所有0代表一月,而11代表12月。

你知道如果传入12代表哪个月份吗?很神奇的是13月,也就是今年年份的12月自动加上1一个月,如果你执行的是new Date(2016,12,1);的话,你得到的日期对象将会是2017-01-01这个日期,你说雷不?

new Date(dateString)

现在就要进入Date类型最雷的用法了,就是看他如何解析字符串,还有更重要的就是你通用想传入怎么日期格式的字符串?

我们先来看看不同浏览器如何解析不同的[日期格式字符串]:

  • IE6~8

    先别说java Date有多雷,浏览器本身就雷的话,其他就不用说了,请尊重生命,没事不要用ie8上网。

    连用ISO标准格式的2016-09-24都不能用。

  • IE9~11

    这几个较新IE版本真的稍微会比较正常点,我觉得2016-09-24这种格式不接受还算优点道理,各位鞋web api的时候要注意了,不要随便产生这种格式的日期字符串。

  • Edge

    非常好,这几个格式都支持了,大家web api终于可以乱写了。

  • Chrome

    看到下图的执行结果,嘴角总是微微上扬,不枉费我们这么爱用google chrome浏览器。

不过,请不要高兴得太早,魔鬼总是出现在细节里

请看一下下图第一个案例(2016-09-24)与第三个案例(2016/09/24),如果你仔细会发现,返回显示的日期时间,两者相差了8个小时。

这时因为第一个案例被chrome解析为GMT格林威治标准时间的日期,我们的[本地时间]是GMT+8,因此显示时间会自动加上8个小时来显示。

我们再来看看第三个案例,它显示的就是[本地时间]的2016/09/24,这个小差别你必须特别注意,因为你打开网页的人不见的都位于台湾时区,因此显示的七日有可能不是2016/09/24,如果你的电脑时区设置在其他地区,也有可能会显示2016/09/23.

  • Safari 9.1.2(Mac OS X/EI Caption)

    人们都说Safari就是另一个IE浏览器不是没有道理的,连特征都跟IE~11很像,可惜现在大部分ios9跑的也是safari9的版本

  • Safari 10 ( Mac OS X / Sierra )

接着我们再加上[时间]部分的字符串,看看各浏览器之间如何解析[日期时间]字符串格式的执行结果。

  • IE6~8

    非常好,没有意外,不支持的日期格式还是不支持

  • IE9~11

    差别又出现了,什么?2016-09-24 12:21:00 这种格式你也不接受,你在开玩笑吗?

  • Edge

    微软的Edge浏览器在很多地方的支持度,却是比IE好很多了。

  • Chrome

    我们加上时间之后,原来第一种案例与第三种案例,不再会相差8个小时了,而是通通解释为本地时间

  • Safari 9.1.2 ( Mac OS X / El Capitan )

    哎,UCCU~safari是不是真的跟IE9~11很像!是不是~

  • Safari 10 ( Mac OS X原由网 / Sierra )

    即便到了safari10最新版本,第一种格式不支持就是不支持,脾气很硬啊。

上面列了这几种日期格式,应该算是在台湾比较常见的日期格式吧。

如果深在台湾,一般人都不习惯用欧美习惯的日期表示法(9 September, 2016 12:21:00)来创建日期时间字符床,因为从上述测试的情况来看,这种格式反而是最没问题的。不过,也不是真的那么[没问题],请各位想想,如果上网的人不在台湾,而你的日期时间代表的是[台湾时区]的时间,这时透过java解析出来的时间,就是错误的。因为浏览器预设会将这个日期格式的字符串解析为[用户目前浏览器的本地时间],如果你又刚好降日期显示出来,那么时间就很有可能出现误差,除非你在页面上很明确地说这个时间就是台湾时区的时间。

我最常看到的日期格式应该是2016-09-24 12:@1:22这种,但你可以发现,从上述测试的案例来看,在IE6~8以及它的兄弟safari并不支持这种用法,这包含iPhone/iPad内置的safari版本,因此移动版网页遇到这种日期格式,通通完蛋。

真正万无一失的日期字符串格式

接着就要进入重点了,事实上在ECMA Language Specification - ECMA-262 Edition 5.1规范中,有对Date Time String Format 作出了非常明确的定义,意思就是说,要使用Date.parse()或new Date(dateString)来解析日期格式字符串,有一套标准的格式定义,规范中定义了要用简化版的 ISO 8601延aZPTw伸的格式。

这个 ISO 8601 Extended Format格式大概是这样:

YYYY-MM-DDTHH:mm:ss.sssZ

一个实际的日期时间规范如下(以下是格林威治标准时区的时间)

2016-09-25T02:24:39.385Z

事实上,这种标准的日期格式,原由网也可以允许只有日期部分,而且还不一定要写完整的日期格式,只有年份也可以当成合法有效的日期格式。

例如一下日期格式都是合法的、有效的跨浏览器、跨平台的日期字符串格式。

new Date(‘2016’);

new Date(‘2016-09’);

new Date(‘2016-09-25’);

date类型怎么写

至于时间部分,日期的部分也不能省略,而日期与时间部分回固定用一个T来分隔。时间的部分,从[秒]开始也是可以省略,不一定要完整的时间格式,而且时间格式最后的Z代表的是Time zone的意思,这个字段也是可以省略的。

例如以下时间格式都是合法的。

THH:mm

THH:mm:ss

THH:mm:ss.sss

如果把日期与时间组合在一起,就有非常多钟可能的变化,以下我举的几个例子,这些都是合法有效的日期格式字符串:

new Date(‘2016T02:34’);

new Date(‘2016-09T02:34:34’);

new Date(‘2016-09-25T02:34:33’);

new Date(‘2016-09T02:34:33.346’);

结论

“java 啊 java,枉费我跟你相处这么久,为什么你总是让人搞aZPTw不懂啊”这句话不知道在多少web开发人员心中出现过,我的[前端工程研究]系列就是试图解决大家长久以来最搞不懂的坑。

请记得一件事,解析日期时间字符串格式时,在ES3规范中根本没有定义应该的日期时间字符串格式,到了ES5才有了明确的ISO-8601格式规范。

在那个没有明确定义日期时间字符串格式的ES3年代(IE6~8),当时各浏览器都职能各自实现自己的日期时间格式解析代码,因此跨浏览器之间的兼容问题自然会有。但当初毕竟浏览器都是美国人做的,所以用美国时间常见的日期时间格式来解析,肯定是没有问题的。比如:Sat, 24 Sep 2016 20:42:16 、 Sat, 24 Sep 2016 20:42:16 GMT 或 Sat, 24 Sep 2016 20:42:16 GMT+0800 等等。

而到了ES5规范问世之后(IE9+),因为必须向前兼容早起的实现,所以只要不是ISO-8601的日期格式出现,不同浏览器之间,还是会有可能出现不同的解析结果,像是safari对于2016-09-24 20:42:16这种格式就一直不支持的,你也不能说他错,他们就是遵照ES5规范去实现而已,所以大家也不用抱怨了,多一点包容与理解,世界才有可能更加祥和。

如果你的网站还是必须支持ie8或以下浏览器的话,因为ie8以下的java runtime并没有实现es5规范,所以当你的web api响应iso-8601日期格式,旧版ie浏览器还是无法解析,这个问题还是必须要考虑进去。

如果你要我给建议的话,我可以说兼容性最高的应该就是Sat, 24 Sep 2016 20:42:16 GMT这种日期时间格式,但请注意这种格式的缺点是[如果你没有加上GMT时区,浏览器预设酒会变这种格式解析为用户电脑的本地时间],如果没注意到时区部分,对于全球性或跨国浏览用户来说可能会出现错误的时间差,否则请一律使用ISO-8601标准日期时间格式( 2016-09T02:34:33.346Z ),这种格式的优点就是[浏览器只会将这种格式解析为GMT/UTC标准时区的时间],这样反而可以强迫你用具有时区的思维来开发代码,出现时差错误的问题也会减少。

下次大家在抱怨浏览器或框架之前,建议先查过java的权威文件,我心目中的java权威文件是java mdn网站,上面对java的介绍与说明一致都是最精华也是最完整的,大家可以多多利用。

补充说明

以下补充在写.NET/c#的DateTime格式时,方便转换成ISO-8601日期时间格式代码范例:

var dt = new DateTime(2016, 9, 25, 17, 57, 43);

Console.WriteLine(dt.ToUniversalTime().ToString(“s”));

// 2016-09-25T09:57:43

相关链接
  • Date - Java | MDN

  • 到底是 GMT+8 还是 UTC+8 ? - PanSci 泛科学

  • ECMA Language Specification - ECMA-262 Edition 5.1 - 15.9.1.15 Date Time String Format

  • ECMA - Wikipedia, the free encyclopedia

  • java - Safari JS cannot parse YYYY-MM-DD date format? - Stack Overflow

  • Standard Date and Time Format Strings - MSDN

关于本文

作者:@Will保哥

原文:

简体译者:@情封

欢迎投稿到前端早读课

投稿邮箱:181422448@qq.com

内容版权声明:除非注明原创否则皆为转载,再次转载请注明出处。

文章标题: date类型怎么写

文章地址: www.58yuanyou.com/jiqiao/328199.html

相关推荐