接口返回一串 1710000000000,直接丢给 new Date 显示正常;换成 1710000000 就变成了 1970 年。前端天天跟时间戳打交道,10 位和 13 位的区别先记住:前者是秒,后者是毫秒。

Date.now 拿到的是毫秒

浏览器里 Date.now() 返回 13 位毫秒数,new Date() 不带参数也是当前时间。要传给只收秒的后端,用 Math.floor(Date.now() / 1000)。别用 parseInt 截字符串,遇到负数或超大值容易出偏差。js 时间戳的换算就这一条主线,先确定单位再谈格式化。

把时间戳变成本地时间

const ms = Date.now(); const d = new Date(ms); console.log(d.toLocaleString('zh-CN'));

toLocaleString 会按运行环境的时区输出,用户在国外看到的就是当地时间。如果业务固定用北京时间,别依赖客户端时区,可以在服务端格式化成字符串,或者用 Intl.DateTimeFormat 指定 timeZone 为 Asia/Shanghai。

解析日期字符串的坑

new Date('2024-03-10') 这种只有日期的写法,多数浏览器按 UTC 零点解析,在东八区打印出来可能变成 3 月 10 日 08:00,边界日期就会串天。更稳的写法是分别传年、月、日,注意月份从 0 开始:new Date(2024, 2, 10)。带时区的 ISO 字符串则按字面偏移解析。

比较和存储别混用单位

两个时间相减得到的是毫秒,除以 1000 才是秒;数据库存 bigint 时统一存毫秒,展示层再转。接口文档要写清单位,字段名用 createdAtMs 之类,比只写 time 少很多争论。js 时间戳本身没有时区,出问题的往往是格式化那一步。

还有一种情况:只表示「某一天」的生日、账单日,用 YYYY-MM-DD 字符串更合适,转成时间戳反而会引入时区。需要精确到毫秒的日志、订单,再用 13 位数字。拿到一个值先数位数,10 位按秒处理,13 位按毫秒处理,剩下的交给 Date 和格式化函数。