JavaScript中10位和13位时间戳转换的区别与处理

作者:清欢

时间:2026-11-03

浏览:529

深入讲解JavaScript中10位(秒级)与13位(毫秒级)时间戳的本质区别、转换计算方法、常见1970年误区以及自适应防御性处理函数。

文章目录

在JavaScript开发中,10位与13位时间戳的根本区别在于计量单位:10位是以“秒”(s)为单位的Unix时间戳,而13位是以“毫秒”(ms)为单位的ECMAScript标准时间戳。JavaScript的内置 Date 构造函数必须接收毫秒级数值;若将10位时间戳直接传入,会导致时间回退至1970年1月。本文将详细解析两者差异、换算方式、常见缺陷以及编写高可靠自适应处理函数的方法。

JavaScript中10位和13位时间戳转换的区别与处理
图 1:10位与13位时间戳核心对照与转换关系缩略图

一、核心差异:秒级与毫秒级的本质区别

时间戳记录的是自协调世界时(UTC)1970年1月1日 00:00:00(即Unix纪元原点)以来的时间累积偏移量。10位和13位时间戳虽然都指向同一个物理时间体系,但在精度和应用生态上有严格划分:

对比维度 10位时间戳 13位时间戳
基本时间单位 秒(Seconds) 毫秒(Milliseconds)
典型数值长度 10 位整数 13 位整数
当前时间数值范围 约 1.7×10⁹(如 1718000000) 约 1.7×10¹²(如 1718000000000)
规范与主用语言 POSIX / Unix 标准、PHP、Python、Go、MySQL ECMAScript 规范、Java (System.currentTimeMillis)
JS 原生支持 需乘以 1000 后传入 new Date() 直接被 new Date(ms) 识别解析
换算关系 ms = s * 1000 s = Math.floor(ms / 1000)

为什么传入10位时间戳会导致日期变成1970年?

JavaScript规范(ECMA-262)定义其内置的 Date 对象必须以毫秒为基准。如果你把一个代表当前时间的10位数字(例如 1718000000)直接塞进 new Date(1718000000),JavaScript引擎会将其当成“纪元原点后过去的 1718000000 毫秒”。

我们做一次简单的单位换算:

1718000000 毫秒 = 1718000 秒
1718000 秒 ≈ 28633 分钟 ≈ 477.2 小时 ≈ 19.88 天

从 1970-01-01 00:00:00 UTC 往后只走不到 20 天,最终解析出来的日期自然是 1970-01-20(在中国标准时间 UTC+8 下则是 1970-01-21 上午)。这就是前端开发中“时间变回1970年”高频Bug的根本根源。

JavaScript中10位和13位时间戳转换的区别与处理
图 2:时间轴刻度比对与 1970 纪元原点误区示意图

二、标准转换操作与代码实现

在日常JavaScript业务中,主要涉及“获取当前指定位数时间戳”、“10位转13位创建Date对象”以及“13位转10位提交后端”这三类基本操作。

1. 获取当前时间的10位与13位时间戳

// 获取 13 位毫秒时间戳(原生方法)
const ts13_v1 = Date.now();            // 推荐,性能最优(返回 Number)
const ts13_v2 = new Date().getTime();   // 传统对象方法
const ts13_v3 = +new Date();            // 一元加运算符快速隐式转换

// 获取 10 位秒级时间戳(需整除 1000)
const ts10_v1 = Math.floor(Date.now() / 1000); // 推荐,向下取整
const ts10_v2 = Math.trunc(Date.now() / 1000); // 去除小数部分
注意:避免使用位运算 (Date.now() / 1000) | 0。在JavaScript中,按位运算会将操作数转换为32位有符号整数。32位有符号整数的最大正值是 2,147,483,647。在2038年01月19日(著名的Unix 2038年问题),10位时间戳将突破该数值并溢出为负数,因此请始终坚持使用 Math.floor()。

2. 10位时间戳转为13位并生成Date对象

处理后端返回的10位秒级时间戳时,必须乘以 1000:

// 假设后端下发的 10 位时间戳
const rawSec = 1718000000;

// 转换为 13 位毫秒数字
const msValue = rawSec * 1000; // 1718000000000

// 构建 Date 实例并输出
const date = new Date(msValue);
console.log(date.toISOString()); // "2024-06-10T00:53:20.000Z"

3. 13位时间戳转换为10位

当客户端采集了毫秒级操作时间,而对接的第三方接口或数据库要求10位Unix时间戳时,应将毫秒除以 1000 并做下舍入:

const currentMs = 1718000000123;
const targetSec = Math.floor(currentMs / 1000);
console.log(targetSec); // 1718000000(丢弃末尾123毫秒)
JavaScript中10位和13位时间戳转换的区别与处理
图 3:时间戳处理的三步操作流

三、防坑指南与自适应工具函数封装

在跨团队、跨端对接(如对接不同微服务、埋点平台或移动端)的实际场景中,接口返回的时间戳常常混杂着字符串类型与数字类型,甚至部分字段为10位、部分字段为13位。如果仅简单做乘除法,极易引发严重故障。

常见陷阱解析

  • 陷阱一:字符串拼接(加号操作符污染)
    若后端返回的是字符串 "1718000000",而开发者试图通过 + "000" 的方式转成13位,一旦某个场景传入的是纯数字 1718000000,代码 ts + "000" 就会执行字符串拼接,得到 "1718000000000";但如果开发者写成 ts + 0,行为就会截然不同。统一的做法是先转纯数值,再进行纯代数计算。
  • 陷阱二:字符串补零被当作八进制或非安全数字
    使用字符串 padEnd(13, '0') 补足13位看似聪明,但若入参本身带有毫秒浮点数(例如后端返回微秒级小数 1718000000.123),直接拼零会生成非法数值字符串,解析后得到错误时间。
  • 陷阱三:浮点数除法未截断
    13位转10位时,如果直接用 ts / 1000 传给后端,会带上小数位。在很多严格校验整数的数据库或后端接口(如 Go 的 int64、MySQL 的 INT)中,会直接触发序列化失败或 400 Bad Request。

工业级自适应防御函数实现

为了在复杂业务中彻底规避此类问题,推荐封装一个统一的时间戳规整函数,能够自动兼容 10 位、13 位、数字型与合法数值字符串:

/**
 * 将任意时间戳(10位或13位,数字或字符串)安全转换为 Date 实例
 * @param {number|string} timestamp 
 * @returns {Date} 成功返回有效的 Date 实例,无效时抛出 TypeError
 */
function parseToDate(timestamp) {
  // 1. 规整为纯数字类型
  const num = Number(timestamp);

  // 2. 防御性校验:排除 NaN、非有限数值及小于等于 0 的异常输入
  if (!Number.isFinite(num) || num <= 0) {
    throw new TypeError(`[parseToDate] 非法的时间戳输入: ${timestamp}`);
  }

  // 3. 自适应判断:以 10^11 为分界线
  // 10位时间戳最大值在 2286 年约为 9.99e9;13位当前在 1.7e12 左右
  // 阈值 1e11 (1000亿) 能在很长历史时期内精准区分秒与毫秒
  const milliseconds = num < 1e11 ? Math.round(num * 1000) : num;

  const targetDate = new Date(milliseconds);

  // 4. 终极有效性检测
  if (Number.isNaN(targetDate.getTime())) {
    throw new RangeError(`[parseToDate] 时间超出有效日期范围: ${timestamp}`);
  }

  return targetDate;
}

// —— 运行示例 ——
console.log(parseToDate(1718000000).toLocaleString());      // 10位数字正常解析
console.log(parseToDate("1718000000").toLocaleString());    // 10位字符串正常解析
console.log(parseToDate(1718000000000).toLocaleString());   // 13位数字正常解析
console.log(parseToDate("1718000000000").toLocaleString()); // 13位字符串正常解析
JavaScript中10位和13位时间戳转换的区别与处理
图 4:自适应时间戳安全转换逻辑与防御分支

四、总结与开发速查清单

掌握时间戳转换的核心在于建立清晰的单位意识和防御性编程习惯。以下为日常编码的核心记忆点与速查清单:

  • 基准法则:JavaScript 原生 Date 内部全是毫秒;看到 10 位必须 * 1000,看到 13 位直接用。
  • 下发与上报对齐:若后端接口定义为 Unix Timestamp,前端提交前务必 Math.floor(Date.now() / 1000),禁止带小数上报。
  • 严禁位运算:不要使用 | 0 进行截断,以避免 2038 年 32 位整数溢出 Bug。
  • 数据类型先转换:对于通过 URL Query 或 JSON 接收的参数,在运算前通过 Number() 显式转为数值类型,杜绝隐式字符串拼接。
JavaScript中10位和13位时间戳转换的区别与处理
图 5:常见操作场景与转换代码速查卡片

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章