
最近在做项目总结写周报的时候,无意中发现一个神奇的现象,当网站后台获取时间戳的值为0时,或者当前端的某个日期值未正确初始化时,拉到的数据总为 1/1/1970 。十分好奇,在摸鱼的时候了解了一下这个神秘日期背后的故事,感觉它涉及到的与计算机系统与时间定义方式的知识都挺有意思的,在博客里分享下。
UTC:

在了解1970年1月1日的故事以及相关计算机系统中的时间之前,我们可以先补习一下有关现实生活中时间标准的相关知识,即我们所熟悉的:Coordinated Universal Time (UTC)。
UTC 是目前全球范围内用于同步时间的主要标准,其精确性由原子钟维持。原子钟基于国际原子时的秒长,为全球提供一致的时间标准。然而,由于地球自转速度并非恒定,需要通过不规则地加入闰秒来进行校正。例如,2016年便增加了一秒,以补偿地球自转的逐渐变慢。换句话说,这是为了调整人为设定的一天长度与实际地球自转时间之间的差异,因为地球自转并不精确为24小时。类似地,闰年的设置是为了弥补人类历法与地球公转周期之间的差异。
相比之下,Greenwich Mean Time(GMT)是一个较为传统的时间标准,虽然与UTC在理论上等同,但现在已经逐步被UTC取代。UTC是最接近GMT的替代系统之一,但其属于较旧的时间标准。作为对GMT的替代,UTC在现代应用中被广泛使用,尤其在分布式系统和实时处理系统中,时间同步至关重要。
在原子钟发明之前,人类依靠天文观测校准时间,但这种方法不够稳定且不便于操作。原子钟的发明则提供了一种更为精确和可靠的时间基准。时间的同步最早应用于无线电广播,通过协调时间步长和频率变化,使得全球通信和系统同步变得高效和精准。
Unix Time:
类比于UTC,Unix Time,又称POSIX time或epoch time,也是一种用于记录时间流逝的定义系统。它定义为从 UTC 1970年1月1日00:00开始所经过的秒数,不考虑闰秒。因此,Unix时间仅代表自Unix纪元以来的累计秒数,与地理位置无关,无论你身处何地,Unix时间的值都是一致的。
在Unix系统中,计算机内部通常使用Unix时间来处理时间数据。这种方式便于计算机进行时间比较和运算。然而,为了方便使用,使时间信息对用户更加友好和直观,系统需要将Unix时间转换为常见的日期和时间格式,供用户查看和理解。这种转换过程在后台自动完成。
我们可以用代码来简单可视化一下这个Unix时间的样式以及转换过程:
import time
# 当前Unix时间(秒)
unix_time = time.time()
# 将Unix时间转换为人类可读的日期时间格式
human_readable_time = time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(unix_time))
print(f"当前Unix时间(秒):{unix_time}")
print(f"转换后的人类可读时间:{human_readable_time}")
#输出结果
当前Unix时间(秒):1736496009.4649348
转换后的人类可读时间:2025-01-10 08:00:09
Unix Epoch
Unix Epoch (Unix纪元) 是Unix及类Unix系统(如Linux、macOS)以及一些编程语言(如C、C++、Java)中用于表示时间的起始点。它定义为从1970年1月1日00:00:00 UTC开始的时间点,之后的时间都以秒为单位进行递增。因此,Unix时间是从这个纪元点起的秒数,纪元之后的时间为正值,而纪元之前的时间则为负值。
值得注意的一点是,其他操作系统和编程语言会采用不同的纪元。例如,Microsoft C/C++ 7.0使用的是从1899年12月31日00:00:00开始的时间起点。在这些系统中,时间的计算方法与Unix纪元有所不同,导致时间的表示方式存在一定差异。
在以有符号 32 位数字表示 Unix 时间的系统上,表示将在 231 - 1 秒后结束,即 2038 年 1 月 19 日 UTC 时间 3:14:08。这即是著名的 2038 年问题。
Year 2038 problem(2038年问题)

在使用有符号32位整数表示Unix时间的系统中,时间的表示必然是有限的。由于32位有符号整数的最大值为2,147,483,647秒(即2^31 - 1秒),这意味着从Unix纪元(1970年1月1日00:00:00 UTC)起,最大可表示的时间为2038年1月19日03:14:07 UTC。当系统时间继续递增时,超出了这一值,32位有符号整数将发生溢出,导致时间回绕到负值,即1970年1月1日的时间点。这个现象被称为Year 2038 problem。
2038问题的根源在于Unix时间的表示方式,它使用的是从1970年1月1日00:00:00 UTC开始计算的秒数,并且在许多系统中使用32位有符号整数来存储这个秒数。由于32位有符号整数的范围从-2,147,483,648到2,147,483,647,这样的表示方法在2038年将无法继续有效,系统会因为溢出而无法正确处理时间。
而为了解决2038年问题,许多系统已经开始转向64位整数表示Unix时间。使用64位整数可以大大扩展时间的表示范围,理论上可以支持到292亿年以后,远超目前任何已知的实际应用需求。因此,2038年问题是当前一些老旧系统面临的挑战,但在现代计算机系统中,这个问题已经得到了有效的解决。
为什么是1/1/1970?
Unix纪元时间的选择来源于Unix的创始人Ken Thompson和Dennis Ritchie在系统设计初期做出的决定。最初版本的Unix系统并未从1970年开始计算时间,而是选择了1971年1月1日00:00:00作为起点。在第一版Unix程序员手册中,Unix时间被定义为从1971年1月1日00:00:00开始,并且使用每秒60次的频率来递增时间计数器。这意味着,Unix时间的最早版本是以60Hz的频率递增,也就是每隔1/60秒,计数器就加一,这种设计直接与当时计算机硬件的频率(芯片的振荡器)相关。
然而,这种设计方式存在显著的局限性。由于当时采用的是32位整数来表示时间,理论上它只能表示大约2.3年的时间跨度。随着对系统需求的深入了解,Unix的开发者意识到这个时间范围远远不能满足实际使用需求。因此,Unix时间的定义经过了几次修改,最终将时间计数频率调整为1Hz,每秒递增一次,时间起点也正式定为1970年1月1日00:00:00 UTC。这一变更使得Unix时间能够以更加简洁和稳定的方式表示系统时间。
至于Unix系统本身的诞生,它其实也并不是在1970年突然出现的。事实上,Unix的概念最早出现在1969年左右,当时Ken Thompson和Dennis Ritchie正在贝尔实验室工作。在这个时期,他们开始构思并开发Unix系统的雏形。
Unix时间纪元的选择不仅仅是一个技术决定,它体现了当时计算机硬件和操作系统设计的局限性,以及后续对系统需求的逐步改进。Unix时间的演变历程也反映了计算机技术的发展,从最初的简化计时方法,到今天精确且全球统一的时间标准。
Reference
- https://en.wikipedia.org/wiki/Unix_time
- https://en.wikipedia.org/wiki/Year_2000_problem
- https://www.quora.com/Why-do-computers-revert-back-to-1st-January-1970-when-they-encounter-an-error-when-calculating-dates-Ive-seen-many-applications-revert-back-to-1-1-1970-at-12-00-am-when-they-are-longer-longer-able-to-calculate-the
- https://stackoverflow.com/questions/72800683/whats-the-difference-between-epoch-timestamp-and-unix-time