⏰ Unix 时间戳详解:程序员必知的时间处理知识

作者:kaenfsk · 发布于 2026 年 8 月 · 阅读约 8 分钟 · 最后复核 2026 年 10 月 12 日 · 内容与维护标准

什么是 Unix 时间戳

Unix 时间戳(Unix Timestamp)是计算机系统中表示时间的标准方式,定义为从 UTC 时间 1970 年 1 月 1 日 00:00:00(称为 Unix Epoch,Unix 纪元)开始经过的总秒数。这个日期就是计算机世界的时间起点,也就是著名的"时间零点"。

时间戳以整数形式存在,便于计算机存储、比较和计算。它不包含时区信息,是一个绝对的瞬间值——无论在伦敦、北京还是纽约,同一个时间戳代表的时刻完全相同。

为什么需要时间戳

在编程中,使用时间戳而不是日期字符串有几个明显优势:

  • 通用性 — 所有编程语言和数据库都支持时间戳,不存在格式解析问题
  • 可比较性 — 时间戳是整数,可以直接用 <、>、= 运算符比较先后
  • 易计算 — 计算两个时间的差值只需要做一次减法,结果就是秒数
  • 无时区歧义 — 日期字符串如 "2026-08-10 12:00" 在不同时区含义不同,时间戳没有这个问题
  • 存储高效 — 一个整数只占 4-8 字节,比字符串省空间,查询也更快

秒级与毫秒级时间戳

这是初学者最容易踩的坑。时间戳有两种常见精度:

  • 秒级(10 位) — 例如 1754870400,单位为秒
  • 毫秒级(13 位) — 例如 1754870400000,单位为毫秒,是秒级的一千倍

JavaScript 的 Date.now() 和 new Date().getTime() 返回毫秒级时间戳;而 PHP 的 time()、Python 的 time.time()(注意是浮点数)、MySQL 的 UNIX_TIMESTAMP() 默认返回秒级。前后端联调时如果精度不一致,时间会差 1000 倍,表现为"差了大约 33 年"。

各编程语言中的时间戳获取方法

JavaScript

// 毫秒级 Math.floor(Date.now()); // 1754870400000 // 秒级 Math.floor(Date.now() / 1000); // 1754870400

Python

import time int(time.time()) # 秒级: 1754870400

PHP

time(); // 秒级: 1754870400 round(microtime(true) * 1000); // 毫秒级: 1754870400000

Java

System.currentTimeMillis(); // 毫秒级: 1754870400000 System.currentTimeMillis() / 1000; // 秒级: 1754870400

时区问题详解

很多人误以为时间戳有时区,其实时间戳本身是 UTC 时间,没有时区。时区只影响"显示"环节:同一个时间戳 1754870400,在北京显示为 2026-08-11 08:00:00,在伦敦显示为 2026-08-11 00:00:00,但它们是同一个时刻。

最佳实践是:存储和传输统一使用 UTC 时间戳,只有在展示给用户时才转换为本地时区。这样可以避免因为服务器时区配置不同导致的数据不一致问题。

中国标准时间是 UTC+8,因此北京时间比 UTC 时间快 8 小时。在数据库查询或日志分析时,如果发现时间比预期慢 8 小时,通常就是 UTC 与北京时间的差异。

2038 年问题

32 位系统使用有符号 32 位整数存储时间戳,最大值为 2147483647,对应 2038 年 1 月 19 日 03:14:07 UTC。超过这个时间,32 位时间戳会溢出,导致时间跳回 1901 年——这就是著名的"2038 年问题"(Y2038 problem),类似于 2000 年的 Y2K 问题。现代 64 位系统可以安全表示到约 2920 亿年后,无需担心。

常见的时间戳转换需求

  • 调试 API — 接口返回的时间戳字段需要转换为可读日期确认正确性
  • 数据库查询 — 在 SQL 中构造时间戳范围进行查询
  • 日志分析 — 将日志中的时间戳转换为本地时间,定位问题
  • 前后端联调 — 确认双方使用的时间戳精度一致

快速转换工具

使用我们的 时间戳转换工具,可以实时查看当前秒级和毫秒级时间戳,并支持时间戳与北京时间双向转换。工具会自动识别输入是秒级还是毫秒级,无需手动判断。

实战案例:登录态过期与时间戳精度

假设你的应用需要让用户保持登录 7 天。后端在签发登录令牌时写入过期时间,常见的做法是存储一个时间戳,例如 exp 字段。前端每次请求时,后端用当前时间戳与过期时间戳比较,判断是否让用户继续访问。这里最容易出现的问题就是精度不一致:签发端使用毫秒级时间戳,校验端却按秒级比较,结果登录态提前或延迟约 1000 倍生效。

另一个常见场景是缓存过期。CDN 或浏览器缓存通常使用秒级时间戳,而 Redis 的 TTL 也以秒为单位。如果代码里混用 Date.now()(毫秒)和 time()(秒),缓存可能永远不过期或立即失效。团队可以在接口文档里统一注明"所有时间戳字段使用秒级 UTC 时间戳,如无特殊说明"。

时间戳与 ISO 8601 的取舍

时间戳便于比较和计算,但可读性差,因此很多 API 同时提供 ISO 8601 字符串,例如 2026-08-31T12:00:00Z。两者各有优势:时间戳适合排序、范围查询和存储,ISO 字符串适合日志展示、人工排障和跨语言解析。最佳实践是内部存储和传输以时间戳为主,展示层再转换成本地时间。

如果 API 必须使用字符串,推荐统一使用 ISO 8601 并带时区标识。不要混用 2026/08/31、08-31-2026 等格式,否则不同语言解析出的结果可能相差一天。

SQL 与日志中的时间戳处理

在 MySQL 中,UNIX_TIMESTAMP() 返回秒级时间戳,FROM_UNIXTIME() 把时间戳转换回日期时间。查询一段时间的数据时,可以直接用 WHERE created_at >= 1755000000,比字符串比较更快。但要注意索引字段的类型:如果列是 DATETIME 而查询参数是时间戳,数据库可能无法使用索引,需要先转换。

日志分析时,建议日志统一记录 UTC 时间戳,并在展示层按用户时区格式化。这样即使服务器部署在不同区域,排障时也能直接比较时间先后,不会因为 8 小时时差产生误解。

常见问题速查

Q: 时间戳 0 代表什么?

代表 Unix 纪元,也就是 1970 年 1 月 1 日 00:00:00 UTC。它通常被当作"空时间"或初始值,实际业务中要避免把 0 当作有效时间。

Q: 时间戳可以是负数吗?

可以,1970 年之前的时间用负数表示。少数系统只支持无符号整数,无法表示 1970 年以前的日期,处理历史数据时需要留意。

Q: 怎么判断接口返回的是秒级还是毫秒级?

看位数:秒级约 10 位,毫秒级约 13 位。也可以把数值转换后与当前时间对比,如果结果相差约 1000 倍,就是精度不一致。

Q: 2038 年后 32 位时间戳会怎样?

有符号 32 位整数会在 2038 年溢出。现代系统和数据库基本使用 64 位,无需担心;遗留设备或旧固件需要评估升级方案。

自查清单

  • 接口文档明确时间戳精度和时区
  • 存储与传输使用 UTC 时间戳,展示时再转本地时间
  • 数据库时间戳列与查询参数类型保持一致
  • 缓存、令牌、过期时间统一单位
  • 测试用例覆盖时区变化和夏令时场景

小结

Unix 时间戳是程序员日常开发中的高频知识点。理解它的定义、精度区别和时区特性,能帮助你避免许多隐蔽的时间相关 Bug。遇到转换需求时,用在线工具快速处理即可。

参考资料与延伸阅读