如何读懂和转换 Unix 时间戳(以及把 cron 写对)

1719849600 是一个日期。1719849600000 也是。它们是同一个时刻,只是单位不同——而分清这两者,比软件里几乎任何其他事情都更能解释“日志对不上”“差了一千倍”“为什么这个事件在 1970 年”这类事故。

Unix 时间戳(也叫 epoch 时间、POSIX 时间)数的是从 1970 年 1 月 1 日 00:00:00 UTC 起经过的秒数。概念就这么多。所有让人困惑的地方,都来自两个细节:单位和时区。

为什么用秒数而不是日期

因为日期有歧义,数字没有。

“2026 年 3 月 15 日下午 2:30”在你站的位置不同就指向不同的时刻,而且跨过夏令时切换点之后它就没意义了。存下来的时间戳没有这个问题:它是一个整数,在每台机器、每个时区、任何时刻都完全相同。存数字,展示时再格式化——这就是规则。破坏它(存一个格式化好的本地日期字符串),就是数据库里那些“一年挪两次一小时”的事件的来源。

秒还是毫秒:反复发生的那个 bug

同一个时刻,两种单位:

  • 秒: 1719849600 —— 10 位
  • 毫秒: 1719849600000 —— 13 位

JavaScript 的 Date.now() 返回的是毫秒。Unix 和多数命令行工具用的是秒。一旦你把两者混起来,就会出现两种失败之一:

  • 把秒当成毫秒传进去,所有日期都会塌回 1970 年 1 月——因为 17 亿毫秒只是 epoch 之后大约 20 天。
  • 把毫秒当成秒传进去,你的事件会落到五万多年后。

数位数是最快的区分办法:10 位是秒,13 位是毫秒,其他长度就得仔细看。本站的时间戳转换工具会自动套用这条规则,而当长度有歧义时,它会把两种解释并排显示,让你不会悄悄选错。

时区:时间戳根本没有时区

这一条事实能解开大部分困惑:Unix 时间戳永远是 UTC。 它不带时区,因为它不需要——它是一个计数,而计数在哪里都一样。

只有当你把时间戳渲染成人能读的日期时,时区才登场。1719849600 同时是:

  • 纽约 2026-07-01 16:00(EDT,UTC−4)
  • 伦敦 2026-07-01 21:00(BST,UTC+1)
  • 东京 2026-07-02 05:00(JST,UTC+9)

同一个数字,三个正确答案。这就是为什么一条只写“16:00”的日志在没有时区的情况下毫无用处,也是为什么所有正经的日志系统都存 UTC、只在边界处才转换。转换工具把你的本地时间和 UTC 并排显示,正是为了这个——让你不再猜自己在看哪一个。

顺带说 2038 问题

以有符号 32 位整数存储的时间戳,会在 2038 年 1 月 19 日 03:14:07 UTC 溢出。那一刻它会翻成一个很大的负数,日期跳到 1901 年。

这不是危机,因为现代系统用 64 位整数或浮点,而 64 位的秒数大约 2920 亿年才溢出。但你还是会在老数据库字段、嵌入式设备和 1990 年代的文件格式里遇到 32 位时间戳。如果你今天在定 schema,就存 64 位——不花任何代价,还永久地把这个问题消掉。

转换时间戳

  1. 打开 Unix 时间戳转换工具。
  2. 粘贴一个时间戳,或者用实时时钟取“现在”。
  3. 读结果——你的本地时区和 UTC 并排。
  4. 反方向:选一个日期时间,读回对应的 epoch 值。

所有计算都在页面本地完成。这一点值得一提,理由只有一个:日志里的时间戳旁边,往往就是令牌、会话 ID 和用户标识。把这样一整块粘进一个随机网站,是个值得改掉的习惯。

写出真正符合你本意的 cron

cron 表达式是五个字段,顺序如下:

分钟  小时  日    月    星期
 *     *     *     *     *

所以 0 */6 * * 1-5 读作:在第 0 分钟,每隔 6 小时,任意日、任意月、且星期为周一到周五时执行。cron 解析工具会把它翻译成人话,并列出接下来 10 次运行时间——这是确认你写的就是你想的唯一可靠办法。

四个最容易踩的点:

时区是服务器的,不是你的。 cron 按机器设定的时区跑。你写的“早上 9 点”,在一台 UTC 服务器上就是 UTC 9 点——也就是纽约的凌晨 4 点。这个误解解释了相当大一部分“为什么我的任务在错误时间跑”。信任小时字段之前,先确认服务器的时区。

“日”和“星期”是“或”,不是“与”。 这是 cron 最有名的坑。当两个字段都被限定(比如 0 0 13 * 5),任务会在每月 13 号或者任意一个周五跑,而不是“13 号且是周五”。想要交集,单个表达式表达不了。

*/15 不是“每小时过 15 分”的那个意思。 它是每 15 分钟一次,整个小时都跑::00、:15、:30、:45。这通常正是人们想要的,但值得说清楚。

星期字段里 0 和 7 都表示周日。 标准 cron 两个都接受。选一个,保持一致。

常见问题

怎么区分秒级和毫秒级时间戳? 数位数。10 位是秒,13 位是毫秒。17 亿是合理的秒值,1.7 万亿是合理的毫秒值。

为什么我的时间戳显示 1970 年? 几乎总是单位不匹配。秒被当成了毫秒,于是这个值对应的是 epoch 之后几天,而不是现在。

Unix 时间戳是什么时区的? 没有时区——按定义就是 UTC。时区只在你要格式化展示它的时候才出现。

为什么我的 cron 任务在错误的小时跑了? 因为 cron 用的是服务器的时区。把你想要的本地时间换算到服务器时区,或者显式设置服务器的 TZ。

0 0 13 * 5 到底做什么? 它会在每月 13 号零点,或者任意一个周五运行。当日和星期都被限定时,两者是“或”的关系。

本文提到的工具

← 全部指南