前阵子联调一个第三方接口,返回的 JSON 里有个字段长这样:"expireTime":1787097600000。我问同事这到底啥时候过期,他头也不抬丢给我一句"自己算去"。盯着这串 13 位数字,我愣了半天——后来才搞明白,它叫 Unix 时间戳,是程序员眼里最常用的时间格式。

时间戳是什么

Unix 时间戳,指从 1970 年 1 月 1 日 00:00:00 UTC 到某个时刻经过的秒数(或毫秒数)。它不关心你在北京还是纽约,不区分东八区还是西五区——同一个时刻,全世界的时间戳数值完全一样。

为什么从 1970 年算起?因为 Unix 操作系统当年就是从这一刻开始计时的,大家沿用至今。1970 年之前的时刻会得到负数,程序同样支持。

秒级和毫秒级,别搞混

Unix 时间戳示意图:2026-08-19 08:00:00 北京时间等于秒级时间戳 1787097600 和毫秒级时间戳 1787097600000,时间轴从 1970 年 1 月 1 日算起
图:同一时刻的三种表示,秒级 10 位、毫秒级 13 位,数值相差 1000 倍

时间戳有两位"表亲",位数不一样。秒级是 10 位数字,如 1787097600,PHP 的 time()、MySQL 的 UNIX_TIMESTAMP() 返回这种。毫秒级是 13 位数字,如 1787097600000,JavaScript 的 Date.now()、Java 的 System.currentTimeMillis() 返回这种。

判断方法很简单:数位数,10 位是秒、13 位是毫秒。接口联调里最常见的坑,就是把毫秒当秒用或者反过来,导致时间差了 1000 倍,约 17 分钟,排查起来非常迷惑。

怎么手动换算

公式一句话:时间戳 = 目标时刻 − 1970-01-01 00:00:00 UTC 的差值(秒或毫秒)。以 2026-08-19 08:00:00 北京时间为例(即 2026-08-19 00:00:00 UTC),秒级是 1787097600,毫秒级是 1787097600000,正好乘 1000。反过来,秒级时间戳除以 86400(一天秒数)得到天数,加上 1970 年就能反推日期。手算容易错,日常直接用站里的时间戳转换工具,任输一边自动出另一边,秒级毫秒级自动识别。

为什么大家都爱用时间戳

它跟语言无关,不管什么编程语言、前端后端,都是同一个整数,没有格式差异。天然可比较,数字越大时间越晚,排序、范围查询直接比大小,比字符串日期可靠。不受时区影响,存储和传输都不带时区,展示时再转本地时间。还省空间,一个 4 或 8 字节整数,比"2026-08-19 08:00:00"这种字符串小得多。

常见使用场景

接口签名用毫秒时间戳标记请求时间,防止重放攻击;缓存过期时 Redis 给 key 设过期时间用的就是秒级时间戳;数据库建表存 BIGINT 时间戳,比 datetime 省空间、排序更快;日志统计按时间戳分段统计访问量、算接口耗时。

顺带提下 2038 年问题

32 位有符号整数最大是 2147483647,对应的时刻是 2038 年 1 月 19 日 03:14:07 UTC。也就是说,还在用 32 位整数存秒级时间戳的老系统,到那一刻会溢出。好在现代系统普遍用 64 位或直接存毫秒,2038 问题更像一个历史遗留提醒,而不是眼前危机。

几个误区澄清一下:时间戳没有"北京时间"和"世界时间"之分,它就是个数字,全球统一,差别只发生在"显示成日期"这一步;13 位也不比 10 位更精确,数据本来就是秒级的话硬乘 1000 不会增加任何精度,只是数字吓人;基准是 UTC 时间,对应北京时间 1970-01-01 08:00:00,换算时别把基准搞错。时间戳是每个开发者迟早要打交道的暗号,记住两条:10 位是秒、13 位是毫秒,转换的活儿交给工具。想补点开发常识可以接着读Base64 是什么?一文看懂编码原理与在线转换。