Unix 时间戳详解 - 计算机如何用一个数字表示时间
什么是 Unix 时间戳?
Unix 时间戳 (也称 POSIX 时间或纪元时间) 是从 1970 年 1 月 1 日 00:00:00 UTC 起经过的秒数。这一时刻被称为 Unix 纪元。例如,时间戳 1,000,000,000 对应的是 2001 年 9 月 9 日 01:46:40 UTC。时间戳 0 就是纪元本身,负值则表示 1970 年之前的日期。
这种表示方式是 1970 年代初期为最初的 Unix 操作系统而选定的,因为它提供了一种简单而无歧义的方式,用单个整数记录任意时刻。与人类可读的日期格式不同,Unix 时间戳没有时区、没有夏令时规则,也无需担心日历上的复杂性。世界上任何两个系统对于同一个时间戳的含义都完全一致,这使其成为分布式计算的理想选择。
将时间戳转换为可读日期
要将 Unix 时间戳转换为当地日期和时间,需要将时间戳加到纪元上,然后应用目标时区的 UTC 偏移量。时间戳 1,715,356,800 表示 2024 年 5 月 11 日 00:00:00 UTC。在东京 (UTC+9),这是 5 月 11 日 09:00;在纽约夏令时 (UTC-4) 期间,则是 5 月 10 日 20:00。同一个时间戳在不同地点会产生不同的本地时间。
大多数编程语言都提供了内置的转换函数。在 JavaScript 中,`new Date(timestamp * 1000)` 会创建一个 Date 对象 (JavaScript 使用毫秒,因此需要乘以 1000)。在 Python 中,`datetime.fromtimestamp(timestamp, tz=timezone.utc)` 返回一个带时区信息的 datetime 对象。这些函数会在内部处理闰年、月份天数等日历细节。
毫秒、微秒与纳秒
经典的 Unix 时间戳以整数秒计数,但许多现代系统使用更高精度。JavaScript 的 `Date.now()` 返回自纪元以来的毫秒数 (13 位而非 10 位)。PostgreSQL 等数据库系统支持微秒精度。高频交易系统和科学仪器可能使用纳秒时间戳。处理来自不同来源的时间戳时,务必确认单位,以避免千倍误差。
一个常见的 bug 来源是混用基于秒和基于毫秒的时间戳。如果把毫秒时间戳传给一个期望秒的函数,得到的日期会是数百万年后的未来;反之,把秒级时间戳当作毫秒处理,则会回到 1970 年 1 月。快速判断方法: 10 位数字是秒 (当前年代),13 位是毫秒,16 位是微秒。
2038 年问题
传统 Unix 系统使用有符号 32 位整数存储时间戳,最大值为 2,147,483,647,对应 2038 年 1 月 19 日 03:14:07 UTC。再过一秒,数值就会溢出并回绕为一个很大的负数,系统会将其解读为 1901 年 12 月 13 日。这类似于 Y2K 问题,但影响的是软件栈更底层的部分。
大多数现代系统已迁移到 64 位时间戳,约 2920 亿年内不会溢出。Linux 在 5.6 版本 (2020 年) 完成了内核级的 64 位时间迁移。然而,嵌入式系统、物联网设备以及运行 32 位代码的遗留软件仍然存在风险。存储 32 位时间戳的文件格式 (如某些旧的归档格式) 也需要在 2038 年之前进行更新。
Unix 时间戳的实际用途
Unix 时间戳在软件开发中无处不在。API 响应中通常包含创建时间、修改时间和过期时间的时间戳。日志文件使用时间戳在分布式系统中排列事件顺序。数据库对时间戳列建索引以实现高效的范围查询。缓存系统使用时间戳判断缓存数据是否已过期。
对于终端用户而言,理解 Unix 时间戳在调试 API 响应、阅读服务器日志或处理数据导出时非常有用。许多在线工具和命令行工具可以在时间戳和可读日期之间互相转换。在终端中,`date -d @1715356800` (Linux) 或 `date -r 1715356800` (macOS) 可将时间戳转换为本地日期字符串。掌握如何读取和转换这些数字,能在排查任何技术系统中的时间相关问题时节省大量时间。
这篇文章对您有帮助吗?