← 返回工具首页 10位还是13位?时间戳踩坑完全手册

「10位还是13位?」时间戳踩坑完全手册

为什么你的时间总是差8小时?为什么2038年还有人踩坑?这篇讲透

☘️ Clover · 2026-05-09

1. 那个让我熬到凌晨3点的坑

讲个真实的故事。

去年做的一个用户行为分析系统,上线后客户反馈"数据时间总是不对,晚了8个小时"。我排查了半天,发现是后端用 Node.js 生成的时间戳传给前端,前端用 JavaScript 的 Date 解析,显示出来就差了8小时。

然后我以为是时区问题,加了 toLocaleString() 里的时区参数。结果……还是差8小时。

最后发现,前端那个13位时间戳是毫秒级,后端存的时候用的是秒级(乘了1000存的),解析的时候又除了一次1000,相当于除了两遍,多除了一次,就差了整整8小时——其实不是8小时,是 3600000 × 8 = 28800000 毫秒,差了整整9.6年。

……我对着这个数字愣了10分钟。

这不是时区问题,这是10位和13位混用导致的世纪级精度灾难。

💡 核心教训:时间戳的位数不仅仅是数字长短的问题,它是单位的问题(秒 vs 毫秒)。团队里第一个拿到时间戳处理逻辑的人,应该写一份文档,或者——用工具做标准化。

2. 10位 vs 13位:到底什么区别

先搞清楚最基本的。

10位时间戳:单位是(second),从1970-01-01 00:00:00 UTC开始计算,到现在大概17亿多。写法:1715260800

13位时间戳:单位是毫秒(millisecond),从1970-01-01 00:00:00 UTC开始计算,到现在大概1.7万亿。写法:1715260800000

📐 换算关系:13位 = 10位 × 1000,反过来 10位 = 13位 ÷ 1000

注意,我说的是"大概",因为精确的数值每次都不一样。但你记住这个关系就够了:13位就是10位后面加三个0(乘以1000)。

那么问题来了——为什么会有两种标准?

所以你经常遇到的场景是:后端给你一个10位时间戳,前端当13位处理,或者反过来——这就出事了。

最烦的是,两种处理方式都不会报错。数字还是那个数字,只是差了1000倍。系统跑得好好的,只有当数据需要和时间对应的时候,才发现时间全是错的。

3. 时区问题:UTC时间戳转本地时间总是差8小时

这个坑90%的人都踩过。

你用服务器生成时间戳,是UTC时间。存到数据库没问题。但前端展示的时候,浏览器会把它当成你本地时区的时间来显示。

中国是 UTC+8,所以你北京时间 2026-05-09 08:00:00 的时间戳,转成UTC就是 2026-05-09 00:00:00,差了正好8小时。

但如果你在代码里这样写:

// 错误示例:直接用时间戳创建Date const ts = 1715260800; // 服务器返回的UTC时间戳(秒) const date = new Date(ts); // ❌ JS会把ts当毫秒处理,得到的日期完全错误 console.log(date.toString()); // 输出:Wed Jan 21 1970 04:21:00 GMT+0800 (CST) // 1970年1月!就因为单位搞错了!

JavaScript 的 Date 构造函数,当传入一个数字时,默认单位是毫秒。你传10位秒级时间戳,它会当成毫秒来处理,等于只过了几十万毫秒——1970年。

所以正确写法是:

// ✅ 正确:乘以1000转毫秒 const ts = 1715260800; // 服务器返回的UTC时间戳(秒) const date = new Date(ts * 1000); // 乘以1000转毫秒 console.log(date.toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' })); // 输出:2026/5/9 00:00:00(北京时间)

⚠️ 血的教训:后端返回时间戳时,一定要在接口文档里写清楚是秒级还是毫秒级!不要假设对方会猜到!接口文档是契约,不是猜测游戏。

4. Bash date:精度居然不是你想的那样

很多人用 date 命令生成时间戳,但你可能不知道——默认行为在不同系统上是不一样的。

# Linux(GNU date)——默认秒级,加 %3N 得毫秒 date +%s # 10位:1715260800 date +%s%3N # 13位(取前13位):1715260800123(实际输出可能不是这样) date +%s%3N | head -c 13 # 截取13位:1715260800000(但实际上GNU date的%N是纳秒,不完全等于毫秒)

等等,%N 是纳秒(9位),不是毫秒(3位)。你截取前13位的话,得到的是"秒+纳秒前3位",这和真正的13位毫秒时间戳不完全一样。

# 真正精确的毫秒级时间戳(Linux) date +%s%3N # 输出例如:1715260800123(13位) # 但注意:某些精简版Linux没有%N支持
# macOS(BSD date)——根本没有 %N,需要自己算 date +%s # 10位秒级时间戳 # 想要毫秒?只能这样: python3 -c "import time; print(int(time.time()*1000))" # 或者用perl:perl -MTime::HiRes -e 'printf "%d\n", Time::HiRes::time()*1000'

⚠️ 跨平台坑:你在Mac上写的 date +%s%3N 脚本,丢到Linux服务器上跑,%N 可能不支持,或者行为完全不同。生产服务器尽量用Python/Node做时间操作,别依赖Shell的date命令。

还有一个常见坑——时区。

# 系统时区不同,date输出的时间也不同,但时间戳本身是一样的 TZ=Asia/Shanghai date +"%Y-%m-%d %H:%M:%S" # 北京时间 TZ=UTC date +"%Y-%m-%d %H:%M:%S" # UTC时间 # 上面两条命令输出的数字时间部分差8小时,但 +%s 时间戳完全一样

5. 各语言踩坑实录

🟡 JavaScript / TypeScript

// ✅ 获取当前时间戳(毫秒) const now = Date.now(); // 1715260800000 const now2 = new Date().getTime(); // 同上 // ✅ 秒转毫秒(服务器返回秒级时间戳时) const serverTs = 1715260800; // 服务器返回的UTC秒级时间戳 const date = new Date(serverTs * 1000); // ✅ 乘1000转毫秒 // ✅ 毫秒转秒(发给后端时) const tsForBackend = Math.floor(Date.now() / 1000); // 10位秒级
// ❌ 错误做法:直接把秒级时间戳给Date const ts = 1715260800; const date = new Date(ts); // JS默认单位是毫秒! // 结果:得到1970年的某个时间 // ❌ 另一个错误:用 valueOf() const date = new Date(1715260800 * 1000); // 这才对,但别忘了乘1000

🐍 Python

# ✅ 获取当前时间戳(秒,float) import time ts = time.time() # 1715260800.123(float,包含小数) # ✅ 整数秒级时间戳 ts_int = int(time.time()) # 1715260800(10位) # ✅ 时间戳转datetime(UTC转本地,自动处理时区) from datetime import datetime, timezone dt = datetime.fromtimestamp(ts, tz=timezone.utc) # UTC时间 dt_local = datetime.fromtimestamp(ts) # 本地时间(自动用系统时区) # ⚠️ 注意:如果没有时区信息,fromtimestamp会假设时间已是本地时间 # 这在夏令时切换时可能出bug——建议始终用timezone.utc
# ✅ 获取毫秒级时间戳 import time ts_ms = int(time.time() * 1000) # 1715260800000(13位) # ✅ 毫秒转datetime from datetime import datetime, timezone ts_ms = 1715260800000 dt = datetime.fromtimestamp(ts_ms / 1000, tz=timezone.utc)

☕ Java

// ✅ Java 8+ 的正确做法 import java.time.*; import java.time.format.DateTimeFormatter; // 当前毫秒时间戳 long tsMs = System.currentTimeMillis(); // 1715260800000 // 当前秒时间戳 long ts = Instant.now().getEpochSecond(); // 1715260800 // 毫秒时间戳转LocalDateTime(UTC转本地) LocalDateTime ldt = LocalDateTime.ofInstant( Instant.ofEpochMilli(tsMs), ZoneId.systemDefault() // 自动用系统时区 ); // 格式化输出 DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); System.out.println(ldt.format(fmt)); // 2026-05-09 00:00:00
// ⚠️ Java 7 及之前的坑爹做法(知道就行,别用) // Date.getTime() 返回毫秒 long tsMs = new Date().getTime(); // 毫秒时间戳 // ❌ 易错:直接 new Date(long) 时,参数是毫秒,不是秒 // Date.setTime(long) 也是毫秒 // 但很多旧代码把秒级时间戳直接传给 Date,会出1970年问题

🐹 Go

// ✅ 秒级时间戳(Unix内置) ts := time.Now().Unix() // int64: 1715260800 // ✅ 时间戳转时间(自动UTC转本地) t := time.Unix(ts, 0) // time.Time(本地时区) fmt.Println(t.Format("2006-01-02 15:04:05")) // 2026-05-09 00:00:00 // ✅ 指定UTC时区 utc := time.Unix(ts, 0).In(time.UTC) fmt.Println(utc.Format("2006-01-02 15:04:05")) // 2026-05-09 00:00:00(UTC,数字不变但输出差8小时)
// ✅ 毫秒级时间戳(需要手动算) tsMs := time.Now().UnixNano() / 1e6 // int64: 1715260800000 // ✅ 毫秒时间戳转时间(注意参数是纳秒,第二个位置) t := time.Unix(0, tsMs*1e6) // 毫秒转纳秒 // ⚠️ 易错:time.Unix(秒, 纳秒) 的第二个参数是纳秒,不是毫秒 // 写成 毫秒 就会差1000倍:time.Unix(0, tsMs) ❌ 错误! // 正确:time.Unix(0, tsMs*1e6) ✅

6. 2038年问题:你以为离你很远?

2038年问题(Y2038 Bug)和经典的2000年问题齐名,但知道的人少得多。

问题的根源是:32位系统的有符号整数(int32)最大值是 2147483647,即 2^31 - 1。如果用这个整数存储秒级时间戳,能表示的最大时间是:

# 2038-01-19 03:14:07 UTC const max32 = 2147483647; const maxDate = new Date(max32 * 1000); console.log(maxDate.toString()); // 输出:Tue Jan 19 2038 11:14:07 GMT+0800 (CST) // (本地时间比UTC快8小时)

过了这个时间,32位系统会整数溢出,变成负数,日期会跳到 1901-12-13(或者更早)。

🚨 谁会中招:

怎么避免:

好消息是,13位毫秒时间戳的最大值是 9,223,372,036,854,775,807(2^63-1),对应大约 292,278,994年——所以只要你用毫秒级的64位时间戳,暂时不用担心2038年问题。

7. 在线工具推荐

说了这么多,最实用的还是——别自己算,用工具。

你可能在各种时间戳转换网站之间来回切换,有时候复制错了,有时候格式不对。我整理了一个在线工具,功能全,支持10位/13位互转,支持时区切换:

如果你觉得这篇文章有用,欢迎收藏。需要批量转换也可以用这个工具搞定。

💡 遇到同类问题?用工具快速解决

试试这些配套工具,无需注册,打开即用

时间戳转换

常见问题

Q: 如何使用 时间戳10位13位踩坑完全手册 相关工具?
A: 这类工具一般有明确的输入框和输出框,按提示输入内容,点击对应按钮即可得到结果。建议先用简单示例测试功能是否正常,再处理实际数据。
Q: 时间戳10位13位踩坑完全手册 适合在什么场景使用?
A: 根据具体工具类型决定。格式转换工具适合处理第三方数据,编码工具适合加密传输,压缩工具适合文件上传前处理。多积累工具使用经验,遇到问题时能快速判断用哪个工具解决。
Q: 有没有更好的替代工具?
A: 不同工具有不同侧重,重点是理解原理。可以同时安装多个类似工具,实际使用中对比效果,选择最顺手的一个。随着使用经验增加,你也能判断工具的好坏。