了解一下ISO 8601是什么

Posted bisal(Chen Liu)

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了了解一下ISO 8601是什么相关的知识,希望对你有一定的参考价值。

上周的组内分享,有朋友介绍一个工具包生成的日期是UTC,需要转成北京时,另外还带了Z,很是不解,组长介绍说这是ISO 8601的日期格式标准。

以前写过一些数据同步的服务,某些客户发送的数据就采用的UTC日期,在程序中我们需要做转换,对日期格式稍微有些研究,但是不系统,借此机会,系统学习一下,究竟什么是ISO 8601?

既然是国际标准,就从国外网站找些资料,看这域名,应该是个公共组织的官网(https://www.iso.org/iso-8601-date-and-time-format.html),

一句话解释了,若需要找到一种国际通用的无歧义的日期和时间格式,ISO 8601就是答案。

这个ISO标准能够帮助消除因不同的日期转换、文化差异、时区等的影响导致对日期时间格式理解上的偏差,他给出了一种无论对人还是机器都清晰定义的日期和时间表示形式。

任何人都可以使用这个ISO 8601标准化地表达如下信息,

  1. Date,日期

  2. Time of day,时间

  3. Coordinated Universal Time (UTC),世界协调时间

  4. Local time with offset to UTC,UTC偏移的本地时

  5. Date and time,日期和时间

  6. Time intervals,时间间隔

  7. Recurring time intervals,重复时间间隔

ISO 8601的中文名称是《数据存储和交换形式·信息交换·日期和时间的表示方法》,第一版为ISO8601:1988,第二版为ISO8601:2000,第三版ISO8601:2004,最新版本应该是ISO8601:2019,

ISO8601:2019有两个文档,

  1. ISO 8601-1:2019 Date and time — Representations for information interchange — Part 1: Basic rules,基础规则,38页的电子版或者纸质版都是售价158瑞士法郎,折合人民币一千多块钱,

  2. ISO 8601-2:2019 Date and time — Representations for information interchange — Part 2: Extensions,扩展规则,

当然网上还是有很多更便宜的资料渠道,这就不多说了,

标准制定的很细,我不是很了解,估计是做一些国际业务人或系统会更关注这些,毕竟他代表了国际通用的日期时间格式,找了一些旧的标准原则,虽然不是最新的,但是原则上,应该比较相近,只是大概了解下,如果要精确的标准定义,建议还是找最新的文档,

  1. 日期和时间值按从最大到最小的时间单位排序:年,月(或周),日,小时,分钟,秒和秒的分数。因此,表示的字典顺序对应于时间顺序,除了涉及负年份的日期表示。这允许日期自然地由例如文件系统排序。

  2. 每个日期和时间值都有一个固定的位数,必须用前导零填充。日期时间表示只能有数字或少数特殊字符组成(如“ - ”,“:”,“T”,“W”和“Z”),不允许出现地方写法,如“1月”或“星期四”等。

  3. 表示可以采用两种格式之一完成 - 具有最少数量分隔符的基本格式或添加了分隔符的扩展格式以增强人类可读性。该标准指出“应以纯文本形式避免使用基本格式”。日期值(年,月,周和日)之间使用的分隔符是连字符,而冒号用作时间值(小时,分钟和秒)之间的分隔符。例如,2009年第1个月的第6天可以以扩展格式写为“2009-01-06”,或者以基本格式简称为“20090106”而不含糊不清。

  4. 为了降低准确度,可以从任何日期和时间表示中删除任意数量的值,但是从最小到最重要的顺序。例如,“2004-05”是有效的ISO 8601日期,表示2004年5月(第5个月)。此格式永远不会代表2004年未指定月份的第5天,也不代表从2004年进入2005年。

  5. ISO 8601使用24小时制。HH:MM:SS.SSS,HH:MM:SS,HH:MM,HH为合规的时间格式。

  6. 如果没有指定与UTC关系则假定是本地时间,为安全的跨时区通讯,应制定与UTC关系。若时间是UTC则在时间后面加Z表示,如“09:30UTC”表示为09:30Z”或“0930Z”。其它时区时间则将与UTC的偏移量附加到时间后面,格式为±[hh]:[mm],±[hh] [mm]或±[hh],如“北京时间09:30”表示为"09:30+08:00”或“ 09:30+0800 ” 或“ 09:30+08 ”。

  7. 用字母T分割日期和时间。如20180703T224426Z或2018-07-03T22:44:26Z 。

再普及几个概念,

  1. 格林威治时间

十七世纪,格林威治皇家天文台为了海上霸权的扩张计画而进行天体观测。到了1884年决定以通过格林威治的子午线作为划分地球东西两半球的经度零度。观测所门口墙上有一个标志24小时的时钟,显示当下的时间,对全球而言,这里所设定的时间是世界时间参考点,全球都以格林威治的时间作为标准来设定时间,这就是我们耳熟能详的「格林威治标准时间」(Greenwich Mean Time,简称G.M.T.)的由来。

明定以英国伦敦格林威治这个地方为零度经线的起点(亦称为本初子午线),并以地球由西向东每24小时自转一周360°,订定每隔经度15°,时差1小时。而每15°的经线则称为该时区的中央经线,将全球划分为24个时区,其中包含23个整时区及180°经线左右两侧的2个半时区。东经的时间比西经要早,也就是如果格林威治时间是中午12时,则中央经线15°E的时区为下午1时,中央经线30°E时区的时间为下午2时;反之,中央经线15°W的时区时间为上午11时,中央经线30°W时区的时间为上午10时。如果两人同时从格林威治的0°各往东、西方前进,当他们在经线180°时,就会相差24小时,所以经线180°被定为国际换日线,由西向东通过此线时日期要减去一日,反之,若由东向西则要增加一日。

格林威治,其实是英国伦敦的一个小镇,位于伦敦东南、泰晤士河南岸,这是作为世界文化遗产的格林威治天文台旧址,

  1. UTC

UTC指的是Coordinated Universal Time- 世界协调时间(又称世界标准时间、世界统一时间),是经过平均太阳时(以格林威治时间GMT为准)、地轴运动修正后的新时标以及以「秒」为单位的国际原子时所综合精算而成的时间,计算过程相当严谨精密,因此若以「世界标准时间」的角度来说,UTC比GMT来得更加精准。其误差值必须保持在0.9秒以内,若大于0.9秒则由位于巴黎的国际地球自转事务中央局发布闰秒,使UTC与地球自转周期一致。所以基本上UTC的本质强调的是比GMT更为精确的世界时间标准,不过对于现行表款来说,GMT与UTC的功能与精确度是没有差别的。UTC时间+时区偏移量就是当地时间,如北京东8区(GMT+8),则UTC时间+08小时就表示北京时间。

  1. 夏令时

夏令时, 「夏日节约时间」Daylight Saving Time(简称D.S.T.),是指在夏天太阳升起的比较早时,将时钟拨快一小时,以提早日光的使用,夏天过去再将时钟调慢一小时,在英国则称为夏令时间(Summer Time)。这个构想于1784年由美国班杰明·富兰克林提出来,1915年德国成为第一个正式实施夏令日光节约时间的国家,以削减灯光照明和耗电开支。

另外在程序中,如果要解析ISO 8601格式的日期,

String datestr1 = "2021-06-01T12:23:00.235+08:00"; //ISO8601
String datestr2 = "2021-06-01 12:23:00";           //Without Millis
String datestr3 = "2021-06-01 12:23:00.235";       //With Millis

使用JDK的API,需要用XXX而不是Z,表示时区,稍微有些别扭,

Date date1 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX").parse(datestr1);
Date date2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(datestr2);
Date date3 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").parse(datestr3);

正因为JDK支持标准的日期和时间功能有些弱,所以出现其他一些开源的项目,例如Joda-Time(https://www.joda.org/joda-time/),其默认格式就是ISO8601,可以直接用DateTime,当然还可以使用日期格式串解析,他还支持其他一些日期时间的便捷操作,另外像Apache-DateUtils,也是这类的项目,有需要的朋友,可以搜下资料,

Date date0 = new DateTime(datestr1).toDate();
date1 = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZZ").parseDateTime(datestr1).toDate();
date2 = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss").parseDateTime(datestr2).toDate();
date3 = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss.SSS").parseDateTime(datestr3).toDate();

近期更新的文章:

Linux系统中的kill -9和-15有什么区别?

Linux系统中的kill -0有什么作用?

主键和唯一约束的索引肯定唯一?

小白学习MySQL - 查询会锁表?

误操作怎么办?试试这个神器-Log Miner

文章分类和索引:

公众号700篇文章分类和索引

以上是关于了解一下ISO 8601是什么的主要内容,如果未能解决你的问题,请参考以下文章

ISO 8601:时间和日期的表示标准

ISO 8601 重复间隔

使用 ISO-8601 格式的 date-fns 获取当前日期

什么是正确的ISO8601格式?

iOS-时间格式ISO 8601

ISO 8601的日的时间表示法