← 返回博客首页

时间戳转换原理与常见坑:Unix 秒、毫秒与本地时区

什么是 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

最佳实践

  1. 统一用 UTC 存储:数据库字段用 TIMESTAMP(UTC)或存整数时间戳,别用「本地时间」列。
  2. 接口传时间戳或 ISO 8601:避免传「2023-11-15 06:13:20」这种无时区字符串。
  3. 展示层按用户时区格式化:用 Intl.DateTimeFormat 而非手写拼接。
  4. 单位要显式约定:前后端文档写清是秒还是毫秒,转换工具自动识别兜底。
  5. 别在墙上时间做算术:差值、定时都在时间戳整数层面算。

常见问题

10 位和 13 位时间戳有什么区别?

10 位是秒级(Unix epoch 秒),13 位是毫秒级。同一时刻 13 位值 ≈ 10 位值 × 1000。JavaScript 的 Date.now() 返回毫秒,很多后端接口用秒,混用会差 1000 倍。

为什么同一时间戳在不同时区显示不同?

时间戳本身是 UTC 绝对时刻,与时区无关;显示出的日期时间是按你所在时区渲染的结果。转换工具应允许选择目标时区再展示。

前端和后端的时区要对齐吗?

不需要在「时区」上对齐,而要在「使用 UTC 存储、本地展示」上对齐。数据库和接口统一传 UTC(或时间戳),展示层按用户时区格式化,避免服务器时区漂移导致错乱。

闰秒会影响时间戳吗?

Unix 时间戳按固定 86400 秒/天线性递增,不感知闰秒;闰秒由 NTP/操作系统在底层平滑处理。业务系统一般无需特殊处理,但金融高频场景要知悉此差异。

2038 年问题还存在吗?

32 位有符号整数存秒级时间戳会在 2038-01-19 溢出。现代语言(64 位)已规避,但老系统、嵌入式设备、部分 C 库仍可能踩坑,跨系统传时间建议用 64 位或 ISO 8601 字符串。

← 返回博客首页