
前几天飞书群里有朋友发来一串数字问我“帮我看下这个日志时间1791945000是啥时候”我说“2026-10-14 上午 10:30。”他又问“那1791945000000呢”我说“同一时刻只不过单位是毫秒。”他沉默了三秒“……我昨天为这事排查了两个小时的接口一直以为是数据错了。”说实话这个问题我以前也踩过。明明只是“一串数字 ↔ 一个日期”的来回换算却总能在最关键的时候掉链子SQL 查出来的时间和运营说的对不上 8 小时、前端页面显示 1970 年、定时任务早跑或晚跑一天、面试被问“时间戳是什么”卡了半天。这篇文章就把时间戳这件事一次性讲清楚它的本质是什么、常见的坑有哪些、离线怎么快速转、在线工具该怎么用。一、三个最扎心的真实场景场景 1日志排查时间对不上后端日志里全是1791945000123这种数字肉眼完全看不出是几点。等终于换算出来发现和用户反馈的时间差了 8 小时——因为日志打的是 UTC你看的是北京时间。场景 2SQL 查询范围写错想查“昨天一整天”的数据随手写了个时间戳区间结果查出来是空的或者多出一堆前天的数据。原因很简单秒和毫秒搞混了或者区间端点的时区算错了。场景 3前端显示 1970 年页面上出现1970-01-21基本可以断定后端返回的是秒前端当成毫秒传给了new Date()或者反过来。这三个场景背后其实是同一组知识点。二、时间戳的本质一个从 1970 年开始的计数器**Unix 时间戳Unix Timestamp**的定义只有一句话从UTC 时间 1970-01-01 00:00:00这个时刻叫 Epoch纪元起到某个时刻所经过的秒数或毫秒数不包含闰秒。它的设计哲学非常朴素把“时间”变成一个纯粹的整数。整数意味着可以直接比大小a b就是a更晚可以直接做加减相差多少秒一目了然存储只占 4 字节秒级或 8 字节毫秒级跨语言、跨时区、跨数据库都没有歧义这也是为什么几乎所有系统内部都用时间戳存储只在展示层才转成人类可读的日期字符串。一个关键认知时间戳本身没有时区。1791945000在全世界任何地方都是同一个瞬间只是不同地区把它“翻译”成不同的墙上时间。三、六个必须记住的坑坑 1秒10 位vs 毫秒13 位这是最高频的错误没有之一。单位位数示例秒 s10 位1791945000毫秒 ms13 位1791945000000微秒 μs16 位1791945000000000纳秒 ns19 位1791945000000000000判断技巧很简单看位数。10 位 → 秒级正常13 位 → 毫秒级正常16 / 19 位 → 微秒 / 纳秒Go 的time.Now().UnixNano()、部分数据库驱动常见如果把毫秒当秒用会得到公元 58000 多年把秒当毫秒用会得到1970 年 1 月下旬。看到这两个离谱年份不用怀疑就是单位错了。坑 2时区永远差那 8 小时同一个时间戳两种写法1791945000 → UTC : 2026-10-14T02:30:00.000Z → 北京时间: 2026-10-14 10:30:00各语言的默认行为还不一样这是最容易翻车的地方JavaScriptnew Date(ts)得到本地时间toISOString()强制输出 UTCJavaSimpleDateFormat/DateTimeFormatter默认用系统时区Instant.toString()输出 UTCPythondatetime.fromtimestamp(ts)用本地时区utcfromtimestamp(ts)用 UTC新版已废弃推荐显式传tzGotime.Unix(ts, 0)用本地时区UTC()切到 UTCMySQLFROM_UNIXTIME(ts)使用会话时区time_zone和global.time_zone可能不一致Hive / Spark SQL受spark.sql.session.timeZone影响改一个参数结果能差 8 小时结论任何时候写“日期字符串 ↔ 时间戳”的转换代码都要显式指定时区不要依赖默认值。坑 3字符串转时间戳时的隐式解析2026-10-14 10:30:00这种字符串在不同解析器里可能被当成本地时间也可能被当成 UTC。带Z后缀的 ISO 86012026-10-14T02:30:00Z才是无歧义的。坑 4跨天的边界“今天”到底从几点开始北京时间 2026-10-14 00:00:00 → 1791936000 UTC 2026-10-14 00:00:00 → 1791964800两者差 8 小时。分区表按天切分、日报统计口径、定时任务的触发窗口全都会被这个差值影响。坑 52038 问题32 位有符号整数能表示的最大秒数是2147483647对应UTC 2038-01-19 03:14:07。超过这一刻就会溢出变成负数时间“穿越”回 1901 年。现代系统用 64 位bigint/long就没问题但一些老设备、老协议、老字段类型仍要留意。坑 6夏令时中国不实行夏令时但美国、欧洲实行。业务涉及海外用户时“本地时间字符串”在夏令时切换那一天会出现重复的一小时或不存在的一小时。用时间戳存储可以完全绕开这个问题——这也是它的最大优势。四、离线怎么快速转4.1 命令行一行搞定最快macOS# 时间戳 → 日期macOS 的 date 用 -rdate-r1791945000%Y-%m-%d %H:%M:%S# 2026-10-14 10:30:00# 日期 → 时间戳date-j-f%Y-%m-%d %H:%M:%S2026-10-14 10:30:00%s# 1791945000# 强制按 UTC 查看TZUTCdate-r1791945000%Y-%m-%d %H:%M:%S %Z# 2026-10-14 02:30:00 UTCLinuxGNU date# 时间戳 → 日期date-d1791945000%Y-%m-%d %H:%M:%S# 日期 → 时间戳date-d2026-10-14 10:30:00%s通用兜底有 Python 就行python3-cimport datetime;print(datetime.datetime.fromtimestamp(1791945000))python3-cimport datetime,time;print(int(time.mktime(datetime.datetime(2026,10,14,10,30).timetuple())))当前时间戳date%s# 秒date%s%3N# 毫秒LinuxmacOS 不支持 %N可用 python3 -c import time;print(int(time.time()*1000))4.2 各语言的官方 APIJavaScript / TypeScript// 获取当前时间戳毫秒constnowMsDate.now();// 1791945000000constnowSMath.floor(nowMs/1000);// 时间戳 → 日期newDate(1791945000000).toLocaleString(zh-CN,{timeZone:Asia/Shanghai});// 2026/10/14 10:30:00newDate(1791945000000).toISOString();// 2026-10-14T02:30:00.000Z ← 注意这是 UTC// 日期 → 时间戳Date.parse(2026-10-14T02:30:00Z);// 1791945000000newDate(2026-10-14T10:30:0008:00).getTime();// 1791945000000⚠️ JS 里Date.now()、getTime()、Date.parse()返回的全是毫秒没有例外。Java// 当前时间戳longmsSystem.currentTimeMillis();// 毫秒longsInstant.now().getEpochSecond();// 秒// 时间戳 → 日期显式指定时区DateTimeFormatterfDateTimeFormatter.ofPattern(yyyy-MM-dd HH:mm:ss);StringtxtInstant.ofEpochMilli(1791945000000L).atZone(ZoneId.of(Asia/Shanghai)).format(f);// 2026-10-14 10:30:00// 日期 → 时间戳longtsLocalDateTime.parse(2026-10-14 10:30:00,f).atZone(ZoneId.of(Asia/Shanghai)).toInstant().toEpochMilli();Pythonimporttimefromdatetimeimportdatetime,timezone,timedelta CSTtimezone(timedelta(hours8))# 当前时间戳int(time.time())# 秒 1791945000int(time.time()*1000)# 毫秒# 时间戳 → 日期datetime.fromtimestamp(1791945000,tzCST).strftime(%Y-%m-%d %H:%M:%S)# 2026-10-14 10:30:00datetime.fromtimestamp(1791945000,tztimezone.utc).isoformat()# 2026-10-14T02:30:0000:00# 日期 → 时间戳int(datetime(2026,10,14,10,30,tzinfoCST).timestamp())# 1791945000Gonow:time.Now()now.Unix()// 秒now.UnixMilli()// 毫秒now.UnixNano()// 纳秒19 位loc,_:time.LoadLocation(Asia/Shanghai)t:time.Unix(1791945000,0).In(loc)t.Format(2006-01-02 15:04:05)// 2026-10-14 10:30:00⚠️ Go 的格式化模板是固定的2006-01-02 15:04:05对应 1、2、3、4、5、6、7不是yyyy-MM-dd。SQLMySQL / Hive / Spark-- 时间戳 → 日期SELECTFROM_UNIXTIME(1791945000,yyyy-MM-dd HH:mm:ss);-- Hive / SparkSELECTFROM_UNIXTIME(1791945000);-- MySQL-- 日期 → 时间戳SELECTUNIX_TIMESTAMP(2026-10-14 10:30:00);-- 毫秒级要先除 1000这是最常见的 SQL 报错来源SELECTFROM_UNIXTIME(CAST(1791945000000/1000ASBIGINT));-- 按天分区注意时区先转成本地时间再截断SELECTDATE_FORMAT(FROM_UNIXTIME(event_time),yyyy-MM-dd)ASdt;五、在线工具怎么用以及它到底解决了什么命令行和代码是“生产环境”的解法但日常查一个时间戳最顺手的还是一个网页工具。我平时用得比较多的是 Leowh 的这个页面https://leowh.com/tools/timestamp/index.html之所以留着没删书签是因为它把我上面提到的几个坑基本都覆盖到了。简单说下它的结构和实际用法5.1 顶部三块实时时钟页面上方并排显示UTC 时间、北京时间和Unix 时间戳秒 毫秒每秒自动刷新。这个设计的价值在于同一瞬间的三种表达同时摆在眼前时区差和位数差一目了然不用脑补。点任意卡片就能复制对应的值适合“我现在就要一个当前时间戳塞进 curl 里”的场景。5.2 左侧时间戳 → 日期时间输入框支持10 位秒和13 位毫秒模式切换顶部有滑动指示器不会像某些工具那样自动猜错单位按Enter或点「转换」同时输出本地时间和ISO 8601两种格式有「当前时间」按钮一键填入此刻实际用起来就是把日志里那串1791945000粘进去回车直接得到2026-10-14 10:30:00以及带Z的 UTC 版本。两种格式都给省去了“这是本地还是 UTC”的猜测。5.3 右侧日期时间 → 时间戳选择本地日期时间点「转换」后同时输出秒级10 位和毫秒级13 位。这一点对写 SQL 特别有用——Hive 要秒、JS 接口要毫秒一次转换两个都拿到不用自己乘 1000。5.4 格式参考标签页提供 8 种格式模板Unix 秒、Unix 毫秒、ISO 8601、UTC、本地时间、日期、时间、带星期。输入任意时间戳就能看到它在所有格式下的样子。写接口文档、定字段规范、和前端对齐格式的时候直接截图比口述清楚得多。5.5 代码片段标签页内置JavaScript、Java、Python、C#、Go五种语言的“获取当前时间戳”和“时间戳转日期”示例可直接复制。而且它会用你当前输入的时间戳生成代码不是写死的示例。这意味着你可以直接把它当“这段逻辑该怎么写”的参考粘到项目里改改就能用。5.6 几个容易被忽略的细节✅纯前端计算所有转换都在浏览器本地完成数据不上传服务器。这一点对排查生产环境敏感日志很重要——你不会想把带业务信息的时间戳贴到一个会留日志的网站上✅ 每个结果右侧都有独立的复制按钮✅ 输入框支持Enter快捷转换连续查多个值时不用挪鼠标5.7 一次完整的排查流程拿开头那个例子走一遍1. 从日志里复制1791945000 2. 粘进左侧输入框确认模式是「秒 (10位)」 3. 回车 → 本地时间2026-10-14 10:30:00 ISO 86012026-10-14T02:30:00.000Z 4. 切到「毫秒」模式粘 1791945000000 → 得到同一时刻 5. 切到「代码片段」→ JavaScript → 复制确认前端拿到的是不是毫秒 6. 结论后端返回秒前端 new Date() 当毫秒用 → 1970 年从“看不懂一串数字”到“定位到单位不一致”大概两分钟。六、选型建议什么时候用什么场景推荐方式临时查一个时间戳在线工具最快无需环境服务器上排查日志date -d ts/date -r ts写业务代码语言原生 API 显式时区SQL 取数、分区FROM_UNIXTIME 确认会话时区批量转换一整列脚本Python / awk别手点敏感数据本地命令或纯前端工具不要上传一个原则能自动化的别手点能手点的别硬算。七、常见坑清单建议对照自查❌ 把 13 位毫秒直接传给FROM_UNIXTIME结果全是 1970 或空值❌ 用toISOString()的结果当本地时间展示凭空少 8 小时❌ Go 里用UnixNano()的 19 位值存进bigint秒级字段溢出❌ Java 里new SimpleDateFormat()不设置setTimeZone()部署到 UTC 容器后全错❌ Python 用已废弃的utcfromtimestamp()升级版本后报警告❌ 前端new Date(2026-10-14)和new Date(2026-10-14 10:30:00)解析规则不同前者按 UTC后者按本地❌ 按天分区用 UTC 截断导致国内业务的“一天”从早上 8 点开始❌ 字段类型用int32 位存秒级时间戳2038 年后溢出八、速查表单位对照名称位数当前量级示例秒 s101791945000毫秒 ms131791945000000微秒 μs161791945000000000纳秒 ns191791945000000000000几个好记的锚点时间戳秒UTC北京时间01970-01-01 00:00:001970-01-01 08:00:0017356608002024-12-31 16:00:002025-01-01 00:00:0017671968002025-12-31 16:00:002026-01-01 00:00:0021474836472038-01-19 03:14:072038-01-19 11:14:07常用格式Unix 秒 : 1791945000 Unix 毫秒 : 1791945000000 ISO 8601 : 2026-10-14T02:30:00.000Z 带时区偏移 : 2026-10-14T10:30:0008:00 北京时间 : 2026-10-14 10:30:00 UTC : 2026-10-14 02:30:00九、总结时间戳转换这件事技术上一点都不难难的是它太容易被忽略。真正要记住的就三句话先数位数确定是秒、毫秒还是纳秒再定时区任何转换都显式写清楚不依赖默认值展示层再转字符串存储和计算一律用整数工具只是帮你把这三步做得更快、更不容易错。命令行适合服务器上应急代码 API 适合写进项目在线工具适合日常随手一查——三者不冲突按场景挑就行。下次再有人甩给你一串1791945000希望你可以两秒钟回他2026 年 10 月 14 号上午十点半。