什么是 Unix 时间戳?
Unix 时间戳(Unix Timestamp)是从 1970-01-01 00:00:00 UTC(称为 epoch)起经过的秒数(或毫秒数)。它是一个与时区无关的绝对时刻——无论你在北京、伦敦还是纽约,同一瞬间的时间戳数值完全相同。
这种「用一个整数表示时刻」的设计,让时间可以像数字一样被存储、比较、做差值,而不必关心人类日历的复杂规则。
秒级 vs 毫秒级
实际开发中最常踩的坑就是单位混用:
| 形式 | 位数 | 示例(同一时刻) | 常见来源 |
|---|---|---|---|
| 秒级 | 10 位 | 1700000000 |
Linux date +%s、MySQL UNIX_TIMESTAMP()、多数后端 API |
| 毫秒级 | 13 位 | 1700000000000 |
JavaScript Date.now()、Java System.currentTimeMillis() |
关键规则:13 位值 ÷ 1000 ≈ 10 位值。如果前端拿到的 13 位直接当秒存进数据库,时间会错误地跳到几万年后。转换工具应能自动识别秒/毫秒(看位数即可判断),避免手动算错。
时区与本地展示
时间戳是 UTC 绝对时刻。当我们在页面上看到「2023-11-15 06:13:20」,那是把 UTC 时刻按当前时区渲染后的结果:
const ts = 1700000000 // 秒级
const d = new Date(ts * 1000) // 注意 ×1000 转毫秒
console.log(d.toString()) // 本地时区:Wed Nov 15 2023 06:13:20 GMT+0800
console.log(d.toISOString()) // UTC:2023-11-14T22:13:20.000Z
永远用 UTC 存储与传输,只在展示层按用户时区格式化。这是跨时区系统不踩坑的唯一铁律。
夏令时(DST)陷阱
实行夏令时的地区,一年中有两天会出现「不存在的小时」或「重复的小时」。基于本地日历的计算(如「加 24 小时」)在 DST 切换日会偏差 1 小时。正确做法是:在时间戳(UTC 整数)层面做算术,再格式化展示,绝不在本地墙上时间上直接加减。
闰秒
Unix 时间按固定每天 86400 秒线性递增,刻意不感知闰秒。闰秒由操作系统/NTP 在底层做「闰秒补偿」,对绝大多数业务透明。只有金融撮合、卫星授时等极端精度场景需要单独处理。
各语言的正确转换
JavaScript(毫秒 → 可读,注意单位):
const sec = 1700000000
const d = new Date(sec * 1000) // 秒→毫秒
const iso = d.toISOString() // UTC 字符串
const local = d.toLocaleString('zh-CN') // 本地时区字符串
Python:
from datetime import datetime, timezone
ts = 1700000000
print(datetime.fromtimestamp(ts, tz=timezone.utc)) # 明确指定 UTC
Go:
import "time"
t := time.Unix(1700000000, 0) // 秒级;毫秒用 time.UnixMilli
最佳实践
- 统一用 UTC 存储:数据库字段用
TIMESTAMP(UTC)或存整数时间戳,别用「本地时间」列。 - 接口传时间戳或 ISO 8601:避免传「2023-11-15 06:13:20」这种无时区字符串。
- 展示层按用户时区格式化:用
Intl.DateTimeFormat而非手写拼接。 - 单位要显式约定:前后端文档写清是秒还是毫秒,转换工具自动识别兜底。
- 别在墙上时间做算术:差值、定时都在时间戳整数层面算。