到了2038年时间戳溢出了怎么办?

计算机中的时间

看完这篇文章相信你会对计算机中的时间有更系统全面的认识。

我经常自嘲,自己写的程序运行不超过3年,因为大部分项目方就早早跑路了。大多数项目上线后,你跟这个项目就再无瓜葛,关于时间你只需要保证时区正确就不会有太大问题,哈哈。 但是今天我想认真对待时间这个问题,作为一个库作者或基础软件作者,就需要考虑下游项目万一因为你处理时间不当而造成困扰,影响范围就比较广了。

计算机中与时间有关的关键词:时间类型、时间戳(timestamp)、定时器(例如js中setInterval())、时间计算、时间段、超时(setTimeout())、时间片、GMT UTC Unix时间戳 ISO8601 CST EST。

看到这些你可能会疑惑,为何一个时间竟然如此复杂!!

如果下面的问题你都能答上来,那这篇文章对你的帮助微乎其微,不如做些更有意义的事情。

  • 常用的时间格式,他们都遵循哪些标准?
  • 什么是GMT?
  • 什么是UTC?
  • GMT UTC 和ISO8601有什么区别?
  • RFC5322是什么?
  • RFC5322 采用的是GMT还是UTC?
  • ISO8601 使用的是UTC还是GMT?
  • 在ISO8601中 Z可以使用+00:00表示吗?
  • UTC什么时候校准?
  • CST是东八区吗?
  • Z是ISO 8601规定的吗,为什么是Z?
  • 时区划分是哪个标准定义的?
  • 为什么是1970年1月1日呢?
  • 到了2038年时间戳溢出了怎么办?
  • 计算机中时间的本质是一个long类型吗?
  • WEB前后端用哪个格式传输好?
  • '2024-01-01T24:00:00' 等于 '2024-01-02T00:00:00' ??

如果看文章太累,也可以B站搜 程序饲养员 看《计算机中的时间》那期视频。


正文开始

1. 两种时间标准

UTC和GMT都是时间标准,定义事件的精度。它们只表示 零时区 的时间,本地时间则需要与 时区 或偏移 结合后表示。这两个标准之间差距通常不会超过一秒。

UTC(协调世界时)

UTC,即协调世界时(Coordinated Universal Time),是一种基于原子钟的时间标准。它的校准是根据地球自转的变化而进行的,插入或删除闰秒的实际需求在短期内是难以预测的,因此这个决定通常是在需要校准的时候发布。 闰秒通常由国际电信联盟(ITU) 和国际度量衡局(BIPM) 等组织进行发布。由国际原子时(International Atomic Time,TAI) 通过闰秒 的调整来保持与地球自转的同步。

GMT(格林尼治标准时间)

以英国伦敦附近的格林尼治天文台(0度经线,本初子午线)的时间为基准。使用地球自转的平均速度来测量时间,是一种相对于太阳的平均时刻。尽管 GMT 仍然被广泛使用,但现代科学和国际标准更倾向于使用UTC。

2. 两种显示标准

上面我们讨论的时间标准主要保证的是时间的精度,时间显示标准指的是时间的字符串表示格式。我们熟知的有 RFC 5322 和 ISO 8601。

RFC 5322 电子邮件消息格式的规范

RFC 5322 的最新版本是在2008年10月在IETF发布的,你阅读时可能有了更新的版本。

RFC 5322 是一份由 Internet Engineering Task Force (IETF) 制定的标准,定义了 Internet 上的电子邮件消息的格式规范。该标准于2008年发布,是对之前的 RFC 2822 的更新和扩展。虽然 RFC 5322 主要关注电子邮件消息的格式,但其中的某些规范,比如日期时间格式,也被其他领域采纳,例如在 HTTP 协议中用作日期头部(Date Header)的表示。

格式通常如下:

sql 复制代码
Thu, 14 Dec 2023 05:36:56 GMT

时区部分为了可读可以如下表示:

sql 复制代码
Thu, 14 Dec 2023 05:36:56 CST
Thu, 14 Dec 2023 05:36:56 +0800
Thu, 14 Dec 2023 05:36:56 +0000
Thu, 14 Dec 2023 05:36:56 Z

但并不是所有程序都兼容这种时区格式,通常程序会忽略时区,在写程序时要做好测试。标准没有定义毫秒数如何显示。

需要注意的是,有时候我们会见到这种格式Tue Jan 19 2038 11:14:07 GMT+0800 (中国标准时间),这是js日期对象转字符串的格式,它与标准无关,千万不要混淆了。

ISO 8601

ISO 8601 最新版本是 ISO 8601:2019,发布日期为2019年11月15日,你阅读时可能有了更新的版本。

下面列举一些格式示例:

makefile 复制代码
2004-05-03T17:30:08+08:00
2004-05-03T17:30:08+00:00
2004-05-03T17:30:08Z
2004-05-03T17:30:08.000+08:00

标准并没有定义小数位数,保险起见秒后面一般是3位小数用来表示毫秒数。 字母 "Z" 是 "zero"(零)的缩写,因此它被用来表示零时区,也可以使用+00:00,但Z更直观且简洁。

  1. 本标准提供两种方法来表示时间:一种是只有数字的基础格式;第二种是添加了分隔符的扩展格式,更易读。扩展格式使用连字符"-"来分隔日期,使用冒号":"来分隔时间。比如2009年1月6日在扩展格式中可以写成"2009-01-06",在基本格式中可以简单地写成"20090106"而不会产生歧义。 若要表示前1年之前或9999年之后的年份,标准也允许有共识的双方扩展表达方式。双方应事先规定增加的位数,并且年份前必须有正号"+"或负号"-"而不使用"。依据标准,若年份带符号,则前1年为"+0000",前2年为"-0001",依此类推。
  2. 午夜,一日的开始:完全表示为000000或00:00:00;仅有小时和分表示为0000或00:00
  3. 午夜,一日的终止:完全表示为240000或24:00:00;仅有小时和分表示为2400或24:00
  4. 如果时间在零时区,并恰好与UTC相同,那么在时间最后加一个大写字母Z。Z是相对协调世界时时间0偏移的代号。 如下午2点30分5秒表示为14:30:05Z或143005Z;只表示小时和分,为1430Z或14:30Z;只表示小时,则为14Z或14Z。
  5. 其它时区用实际时间加时差表示,当时的UTC+8时间表示为22:30:05+08:00或223005+0800,也可以简化成223005+08。

日期与时间合并表示时,要在时间前面加一大写字母T,如要表示东八区时间2004年5月3日下午5点30分8秒,可以写成2004-05-03T17:30:08+08:00或20040503T173008+08。

在编写API时推荐使用ISO 8601标准接收参数或响应结果,并且做好时区测试,因为不同编程语言中实现可能有差异。

时区划分和偏移

添加图片注释,不超过 140 字(可选)

全球被分为24个时区,每个时区对应一个小时的时间差。 时区划分由IANA维护和管理,其时区数据库被称为 TZ Database(或 Olson Database)。这个数据库包含了全球各个时区的信息,包括时区的名称、标识符、以及历史性的时区变更数据,例如夏令时的开始和结束时间等。在许多操作系统(如Linux、Unix、macOS等)和编程语言(如Java、Python等)中得到广泛应用。

TZ Database具体见我整理的表格,是从Postgresql中导出的一份Excel,关注公众号"程序饲养员",回复"tz"

添加图片注释,不超过 140 字(可选)

时区标识符采用"洲名/城市名"的命名规范,例如:"America/New_York"或"Asia/Shanghai"。这种命名方式旨在更准确地反映时区的地理位置。时区的具体规定和管理可能因国家、地区、或国际组织而异。

有一些时区是按照半小时或15分钟的间隔进行偏移的,以适应地理和政治需求。在某些地区,特别是位于边界上的地区,也可能采用不同的时区规则。

EST,CST、GMT(另外一个含义是格林尼治标准时间)这些都是时区的缩写。

这种简写存在重复,如CST 可能有多种不同的含义,China Standard Time(中国标准时间),它对应于 UTC+8,即东八区。Central Standard Time(中部标准时间) 在美国中部标准时间的缩写中也有用。中部标准时间对应于 UTC-6,即西六区。因此在某些软件配置时不要使用简称,一定要使用全称,如"Asia/Shanghai"。

采用东八区的国家有哪些

  • 中国(中华人民共和国): 中国标准时间(China Standard Time,CST)是东八区的时区,对应于UTC+8。
  • 中国香港: 中国香港也采用东八区的时区,对应于UTC+8。
  • 中国澳门: 澳门也在东八区,使用UTC+8。
  • 中国台湾: 台湾同样在东八区,使用UTC+8。
  • 新加坡: 新加坡位于东八区,使用UTC+8。
  • 马来西亚: 马来西亚的半岛部分和东马来西亚位于东八区,使用UTC+8。
  • 菲律宾: 菲律宾采用东八区的时区,对应于UTC+8。

计算机系统中的时间 ------ Unix时间戳

Unix时间戳(Unix timestamp)定义为从1970年01月01日00时00分00秒(UTC)起至现在经过的总秒数(秒是毫秒、微妙、纳秒的总称)。

这个时间点通常被称为 "Epoch" 或 "Unix Epoch"。时间戳是一个整数,表示从 Epoch 开始经过的秒数。

一些关键概念:

  1. 起始时间点: Unix 时间戳的起始时间是 1970 年 1 月 1 日 00:00:00 UTC。在这一刻,Unix 时间戳为 0。

  2. 增量单位: Unix 时间戳以秒为单位递增。每过一秒,时间戳的值增加 1。

  3. 正负值: 时间戳可以是正值或负值。正值表示从 Epoch 开始经过的秒数,而负值表示 Epoch 之前的秒数。

  4. 精度: 通常情况下,Unix 时间戳以整数形式表示秒数。有时也会使用浮点数表示秒的小数部分,以提供更精细的时间分辨率。精确到秒是10位;有些编程语言精确到毫秒是13位,被称为毫秒时间戳。

为什么是1970年1月1日?

这个选择主要是出于历史和技术的考虑。

Unix 操作系统的设计者之一,肯·汤普森(Ken Thompson)和丹尼斯·里奇(Dennis Ritchie)在开发 Unix 操作系统时,需要选择一个固定的起始点来表示时间。1970-01-01 00:00:00 UTC 被选为起始时间。这个设计的简洁性和通用性使得 Unix 时间戳成为计算机系统中广泛使用的标准方式来表示和处理时间。

时间戳为什么只能表示到2038年01月19日03时14分07秒?

在许多系统中,结构体time_t 被定义为 long,具体实现取决于编译器和操作系统的架构。例如,在32位系统上,time_t 可能是32位的 long,而在64位系统上,它可能是64位的 long。 32位有符号long类型,实际表示整数只有31位,最大能表示十进制2147483647(01111111 11111111 11111111 11111111)。

javascript 复制代码
> new Date(2147483647000)
< Tue Jan 19 2038 11:14:07 GMT+0800 (中国标准时间)

实际上到2038年01月19日03时14分07秒,便会到达最大时间,过了这个时间点,所有32位操作系统时间便会变为10000000 00000000 00000000 00000000。因具体实现不同,有可能会是1901年12月13日20时45分52秒,这样便会出现时间回归的现象,很多软件便会运行异常了。

至于时间回归的现象相信随着64为操作系统的产生逐渐得到解决,因为用64位操作系统可以表示到292,277,026,596年12月4日15时30分08秒。

另外,考虑时区因素,北京时间的时间戳的起始时间是1970-01-01T08:00:00+08:00。

好了,关于计算机中的时间就说完了,有疑问评论区相见 或 关注 程序饲养员 公号。

相关推荐
AI大模型8 分钟前
利用腾讯混元大模型搭建Cherry Studio自有知识库,打造“智能第二大脑”
程序员·llm·agent
文心快码BaiduComate20 小时前
弟弟想看恐龙,用文心快码3.5S快速打造恐龙乐园
前端·后端·程序员
大模型教程21 小时前
半小时部署企业智能问答系统!MaxKB让知识管理效率翻倍
程序员·llm·agent
AI大模型21 小时前
告别数据隐私焦虑!我用FastGPT免费私有化部署了AI个人知识管理系统辅助写作
程序员·llm·agent
大模型教程21 小时前
基于Dify的RAG知识库搭建
程序员·llm·agent
AI大模型1 天前
微软AI Agents入门课程爆火!GitHub星标破万,零基础构建AI智能体
程序员·llm·agent
SimonKing1 天前
除了 ${},Thymeleaf 的这些用法让你直呼内行
java·后端·程序员
小小前端_我自坚强1 天前
Tailwind CSS 详解
css·程序员·开源
陈哥聊测试1 天前
各角色如何从DevOps中受益?
程序员·自动化运维·devops
_大学牲1 天前
Flutter 之魂 GetX🔥(一)从零了解状态管理
前端·程序员