时间


本文主要是想总结时间相关的知识,包括基础概念、原生API、流行的时间处理库。

基础概念

GMT:格林威治时间

GMT(Greenwich Mean Time),一般称为格林威治时间或格林尼治时间,也叫世界时(Universal Time)或世界标准时间。是指位于英国伦敦郊区的皇家格林尼治天文台的标准时间,是本初子午线上的地方时,是0时区的区时。

时区

地球自西向东转,处于东边的地方比西边的地方早见到太阳,因此东边比西边时间早。以本初子午线为中心,按照地球自转方向,每隔经度15°划分一个时区的方法,全球共分为24个时区:东1区至东12区,西1区至西12区,其中东西12区跨度都是7.5°也叫半时区。每个时区之间时间相隔1个小时,因此当前时间和GMT时间的相差计算公式为:

本时区时间 = GMT时间 + 时区差(东N时区+N,西N时区-N)

中国时区

中国境内一般统一使用东八区区时,即我们常听到的北京时间。实际上中国在地理上覆盖了东五区到东九区,因此境内有四个小时的时差,可能东部已经深夜,西部才刚傍晚。虽然如此,为了方便沟通,中国统一使用首都北京所在的东八区所在的区时作为统一时间。

HTTP

HTTP传输日期和时间戳信息使用GMT作为标准,浏览器会自动转化。现行HTTP1.1的时间格式为:

date: Mon, 17 May 2021 03:07:34 GMT

对于HTTP来说,GMT和UTC是等价的。

UTC:世界标准时间

UTC(Coordinated Universal Time),一般称为世界标准时间,或协调世界时、国际协调时间、世界统一时间,由于英文(CUT)和法文(TUC)缩写不同,作为妥协,简称UTC。UTC以原子时作为计量时间的单位,计算结果极为精密,误差值必须保持在0.9秒以内,大于0.9秒将通过闰秒来解决。

原子时

IAT(international atomic time),称为原子时,是以物质的原子内部发射的电磁振荡频率为基准的时间计量系统。美国的物理实验市在2014年造出了人类历史上最精确的原子钟,50亿年误差1s。中国的铯原子钟也能确保2000万年误差不超过1s。

与GMT的区别

GMT根据地球自转和公转来计算时间,而地球本身是椭圆,公转的轨道也是椭圆的,造成每天、每年的长短都不一样,误差就容易造成不精准,因此需要一个稳定精准的标准。

在UTC标准里面,一天恒定24小时,即86400秒。因此在UTC出现后,GMT称为格林威治时间而不是世界标准时间更合适,UTC才是新的世界标准时间。

与GMT的联系

GMT实际上只是一个区时,即0时区的时间,在不需要精确到秒的情况下可视为相同,但两者的实际定义和实现是完全不一样的。

UTC偏移量

时间日期联盟组织给世界主要国家和城市都起了一个Time Zone Name 方便沟通,其中中国一般使用CST。而本地时间的计算公式为:

本地时间 = UTC标准时间 + 偏移量N

偏移量可以表示为UTC -UTC + ,后面接小时数分钟数 。如:UTC +9:30表示澳大利亚中央标准时间,UTC +8表示中国标准时间。偏移量常见的表示形式有:±[hh]:[mm]±[hh][mm]±[hh]这三种方式均可。

举个例子:现在UTC时间是10:30z(z表示偏移量=0),那么北京时间现在若是16:30 +0800(下午4点半),对应的纽约时间就是05:30 -0500(早上5点半)。

ISO 8601:国际标准日期时间表示法

ISO(International Standard Organization)国际化标准组织制定的日期和时间的标准, 全称为《数据存储和交换形式·信息交换·日期和时间的表示方法》。目前最新为第三版ISO8601:2004,第一版为ISO8601:1988,第二版为ISO8601:2000。 它规定了日期时间的各种表示方法,它的一般原则:

  • 日期和时间值按从最大到最小的时间单位排序:年,月(或周),日,小时,分钟,秒和秒的分数。因此,表示的字典顺序对应于时间顺序,除了涉及负年份的日期表示。这允许日期自然地由例如文件系统排序。
  • 每个日期和时间值都有一个固定的位数,必须用前导零填充
  • 日期时间表示只能有数字或少数特殊字符组成(如“ - ”,“:”,“T”,“W”和“Z”),不允许出现地方写法,如“1月”或“星期四”等。
  • 表示可以采用两种格式之一完成 - 具有最少数量分隔符的基本格式或添加了分隔符的扩展格式以增强人类可读性。该标准指出“应以纯文本形式避免使用基本格式”。日期值(年,月,周和日)之间使用的分隔符是连字符,而冒号用作时间值(小时,分钟和秒)之间的分隔符。例如,2021年第5个月的第6天可以以扩展格式写为“2021-05-06”,或者以基本格式简称为“20210506”而不含糊不清。
  • 为了降低准确度,可以从任何日期和时间表示中删除任意数量的值,但是从最小到最重要的顺序。例如,“2021-05”是有效的ISO 8601日期,表示2021年5月(第5个月)。此格式永远不会代表2021年未指定月份的第5天,也不代表从2021年进入2022年。
  • ISO 8601使用24小时制。HH:MM:SS.SSS,HH:MM:SS,HH:MM,HH为合规的时间格式。
  • 如果没有指定与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 ”。
  • 用字母T分割日期和时间。如20210517T124426Z或2021-05-17T12:44:26Z 。有些后台返回值会出现这种情况,需要注意。

DST:夏令时

DST(Daylight Saving Time)夏令时,表示为了节约能源,人为规定时间的意思。也叫夏时制,夏时令,又称“日光节约时制”和“夏令时间”,在这一制度实行期间所采用的统一时间称为“夏令时间”。一般在天亮早的夏季人为将时间调快一小时,可以使人早起早睡,减少照明量,以充分利用光照资源,从而节约照明用电。各个采纳夏时制的国家具体规定不同。全世界有近110个国家每年要实行夏令时。有一定节约能源效果,但是繁琐,对低纬度无意义。

Timestamp:时间戳

时间戳一般指的UNIX时间,或类UNIX系统(比如Linux、MacOS等)使用的时间表示方式。定义为:从UTC时间的1970-1-1 0:0:0起到现在的总秒数(秒是毫秒、微妙、纳秒的总称)。

当闰秒发生时,就极有可能出现同一个时间戳表示两个时刻的情况(类似时钟回拨),而且闰秒还没规律所以无法程序式的避免。因此需要一种专门的对时协议来确保:网络时间协议。

NTP:网络时间协议

NTP(Network Time Protocol),网络时间协议,是用来使计算机时间同步化的一种协议,它可以使计算机对其服务器或时钟源(如石英钟,GPS等等)做同步化,它可以提供高精准度的时间校正(LAN上与标准间差小于1毫秒,WAN上几十毫秒),且可介由加密确认的方式来防止恶毒的协议攻击。NTP的目的是在无序的Internet环境中提供精确和健壮的时间服务,各大操作系统(windows/Linux)对NTP都有实现。

原生API:Date对象

参考:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Date

创建Date对象

Date对象只能通过new 操作符创建,若作为普通函数调用则只会返回一个字符串。

new Date();
new Date(value);
new Date(dateString);
new Date(year, monthIndex [, day [, hours [, minutes [, seconds [, milliseconds]]]]]);

无参数

不传参数,则表示创建当前的时间对象。

Unix时间戳

返回时间戳对应的时间对象。

时间戳字符串

一个符合 RFC2822 或 ISO 8601 日期格式的字符串(其他格式也许也支持,但结果可能与预期不符)。

注意: 由于浏览器之间的差异与不一致性,强烈不推荐使用Date构造函数来解析日期字符串 (或使用与其等价的Date.parse)。对 RFC 2822 格式的日期仅有约定俗称的支持。 对 ISO 8601 格式的支持中,仅有日期的串 (例如 “1970-01-01”) 会被处理为 UTC 而不是本地时间,与其他格式的串的处理不同。

分别提供日期与时间的每一个成员

  • year

表示年份的整数值。 0到99会被映射至1900年至1999年,其它值代表实际年份。

  • monthIndex

表示月份的整数值,从 0(1月)到 11(12月)

  • date可选

表示一个月中的第几天的整数值,从1开始。默认值为1。

  • hours 可选

表示一天中的小时数的整数值 (24小时制)。默认值为0(午夜)。

  • minutes 可选

表示一个完整时间(如 01:10:00)中的分钟部分的整数值。默认值为0。

  • seconds 可选

表示一个完整时间(如 01:10:00)中的秒部分的整数值。默认值为0。

  • milliseconds 可选

表示一个完整时间的毫秒部分的整数值。默认值为0。

常用静态方法

Date.now()

返回当前时间戳

Date.UTC(year, monthIndex [, day [, hours [, minutes [, seconds [, milliseconds]]]]])

转化时间为时间戳

常用实例方法

Date.prototype.getTime()

获取时间戳

Date.prototype.getFullYear()

返回四位数年份

Date.prototype.getMonth()

返回第几月份(0-11),0代表1月

Date.prototype.getDate()

返回月份中的第几天(1-31)

Date.prototype.getHours()

返回小时数(0-23)

Date.prototype.getMinutes()

返回分钟(0-59)

Date.prototype.getSeconds()

返回秒数(0-59)

Date.prototype.Milliseconds()

返回毫秒数(0-999)

Date.prototype.getDay()

返回星期中的第几天(0-6),0代表周日

Date.prototype.valueOf()

返回时间戳

流行时间处理库

date-fnsday.jsmoment.js作为三个最流行的时间处理库,他们的对比结果如下:NPMCompare

结论:

  1. moment.js已确认不再高强度维护:https://momentjs.com/docs/#/-project-status/,因此不推荐继续在项目中使用。
  2. day.jsmoment.js 有相同的API,能快速从moment.js 迁移,学习成本低,支持不可变数据、链式操作、国际化,全浏览器兼容,且仅有2kb大小,推荐使用。
  3. date-fns 支持模块化按需加载,体积可以最小化,若在某个工具库里面或只用到某个功能,推荐使用date-fns
  4. day.js 适合项目中使用,特别是替换常见UI组件库的moment.jsdate-fns 适合单独使用时间工具函数的场景。

文章作者: 禅宗
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 禅宗 !
评论
  目录