Unix时间戳(Unix Timestamp / Epoch Time / POSIX Time)是计算机世界中最基础的时间表示方式之一。它定义为从UTC时间1970年1月1日00:00:00起至目标时刻所经过的总秒数(不计闰秒)。这个看似简单的整数背后,承载着计算机时间系统数十年的发展历史,也隐藏着一些容易被忽视的技术陷阱。
Unix操作系统诞生于1969年,由贝尔实验室的肯·汤普森(Ken Thompson)和丹尼斯·里奇(Dennis Ritchie)开发。最初的Unix时间系统使用32位整数,以1/60秒为单位计数,纪元起点设在1971年1月1日。但这种设计只能覆盖约2.5年的时间范围,很快就不够用了。1973年,开发团队将纪元修改为1970年1月1日,计数单位改为秒,这样32位有符号整数可以覆盖约136年的范围(1901年到2038年)。选择1970年1月1日的原因很务实:它是一个整年的开始,距离当时足够近(不浪费可表示范围),同时又是一个"干净"的时间起点。
| 类型 | 位数 | 精度 | 示例值 | 常用于 |
|---|---|---|---|---|
| 秒级时间戳 | 10位 | 1秒 | 1700000000 | Unix/Linux、PHP、Python、Go、C |
| 毫秒级时间戳 | 13位 | 1毫秒 | 1700000000000 | JavaScript、Java、Dart |
| 微秒级时间戳 | 16位 | 1微秒 | 1700000000000000 | Python(time.time_ns)、数据库 |
| 纳秒级时间戳 | 19位 | 1纳秒 | 1700000000000000000 | Go(time.Now().UnixNano())、Rust |
| 时间戳 | 对应时间(UTC) | 说明 |
|---|---|---|
| -1 | 1969-12-31 23:59:59 | 纪元前一秒,用于测试负时间戳处理 |
| 0 | 1970-01-01 00:00:00 | Unix纪元起点(Epoch) |
| 1000000000 | 2001-09-09 01:46:40 | 十亿秒纪念时刻 |
| 1234567890 | 2009-02-13 23:31:30 | 著名的递增数字时间戳,被程序员庆祝 |
| 1500000000 | 2017-07-14 02:40:00 | 十五亿秒 |
| 2000000000 | 2033-05-18 03:33:20 | 二十亿秒(即将到来) |
| 2147483647 | 2038-01-19 03:14:07 | 32位有符号整数最大值(Y2K38临界点) |
| 4294967295 | 2106-02-07 06:28:15 | 32位无符号整数最大值 |
Y2K38问题(Year 2038 Problem)是计算机领域一个真实且紧迫的威胁。当使用32位有符号整数(int32_t / signed int)存储Unix时间戳的系统运行到2038年1月19日03:14:07 UTC时,时间戳将从2,147,483,647(01111111 11111111 11111111 11111111)增加到2,147,483,648,由于整数溢出,二进制变为10000000 00000000 00000000 00000000,被解释为-2,147,483,648,对应1901年12月13日20:45:52 UTC。
| 语言 | 获取当前时间戳 | 精度 | 时间戳转日期 |
|---|---|---|---|
| JavaScript | Date.now() 或 +new Date() | 毫秒 | new Date(timestamp) |
| Python | import time; time.time() | 秒(浮点) | datetime.fromtimestamp(ts) |
| Java | System.currentTimeMillis() | 毫秒 | new Date(timestamp) |
| Go | time.Now().Unix() | 秒 | time.Unix(ts, 0) |
| PHP | time() | 秒 | date('Y-m-d H:i:s', $ts) |
| Ruby | Time.now.to_i | 秒 | Time.at(ts) |
| C/C++ | time(NULL) | 秒 | localtime(&ts) |
| Rust | SystemTime::now() | 纳秒 | UNIX_EPOCH + Duration::from_secs(ts) |
| Shell | date +%s | 秒 | date -d @timestamp |
时间戳本身是不含时区信息的——它始终表示从UTC纪元起经过的秒数。但在将时间戳转换为人类可读的日期时间时,时区就成为了最容易出错的环节。以下是开发中最常见的时区陷阱:
| 格式名称 | 示例 | 特点 | 适用场景 |
|---|---|---|---|
| Unix时间戳 | 1700000000 | 纯数字,便于计算和比较 | 数据库存储、API传输、日志记录 |
| ISO 8601 | 2023-11-14T22:13:20+08:00 | 国际标准,包含时区,人机皆可读 | API响应、JSON数据、国际化应用 |
| RFC 2822 | Tue, 14 Nov 2023 22:13:20 +0800 | 电子邮件标准格式 | 邮件头、HTTP头(Date字段) |
| RFC 3339 | 2023-11-14T14:13:20Z | ISO 8601的子集,更严格 | Web API、云服务、日志标准 |
| 人类可读格式 | 2023年11月14日 22:13:20 | 直观易懂 | UI展示、报表 |