JS怎么将13位时间戳转换为YYYY-MM-DD HH:mm:ss格式

作者:清欢时间:2026-10-30 19:13:36浏览:653

详细讲解在 JavaScript 中如何将 13 位毫秒级时间戳转换为标准的 YYYY-MM-DD HH:mm:ss 格式,包含原生 5 步拆解法、月份偏移与补零机制、核心陷阱规避、方案对比与高健壮性封装。

核心做法:直接将 13 位毫秒数值传入 new Date(Number(timestamp)) 构造实例,依次读取年、月、日、时、分、秒各分量,注意月份必须加 1,再配合现代标准方法 String(val).padStart(2, '0') 补齐双位,最后使用模板字符串拼接输出即可。

JS怎么将13位时间戳转换为YYYY-MM-DD HH:mm:ss格式
图 1:13 位时间戳转换为 YYYY-MM-DD HH:mm:ss 格式的全流程概览

一、核心快速实现:轻量标准转换函数

13 位时间戳是 UNIX 时间戳的毫秒级表现形式(例如 1711929600000)。在原生 JavaScript 中,最直接且性能极佳的转换方式是利用内置的 Date 对象读取各时间维度分量,并通过 padStart 实现两位数对齐:

function formatTimestamp(timestamp) {
  // 1. 确保入参转换为数值类型并实例化 Date
  const date = new Date(Number(timestamp));

  // 2. 提取各项分量并补零(注意:getMonth() 必须 +1)
  const Y = date.getFullYear();
  const M = String(date.getMonth() + 1).padStart(2, '0');
  const D = String(date.getDate()).padStart(2, '0');
  const H = String(date.getHours()).padStart(2, '0');
  const m = String(date.getMinutes()).padStart(2, '0');
  const s = String(date.getSeconds()).padStart(2, '0');

  // 3. 按 YYYY-MM-DD HH:mm:ss 格式拼装
  return `${Y}-${M}-${D} ${H}:${m}:${s}`;
}
运行调用与示例输出
formatTimestamp(1711929600000);
// 输出示例: "2024-04-01 08:00:00"(依据宿主时区输出)

该方案无需依赖任何第三方库,在 Chrome、Firefox、Edge、Safari 以及 Node.js 等全平台环境下均可原生直接运行。

二、原生 5 步转换流程拆解

为了让逻辑清晰易懂,在面对不同数据源与兼容性场景时能够举一反三,我们可以将转换过程拆解为 5 个标准步骤:

  1. 步骤一:入参清洗与 Date 实例化:前端常通过接口或 URL 参数获取时间戳,后端返回的字段可能是字符串类型(如 "1711929600000")。使用 Number(timestamp) 确保转化为数字,直接作为参数传入 new Date()。
  2. 步骤二:提取日期分量:调用 date.getFullYear() 获取 4 位年份,调用 date.getDate() 获取当月几号(注意不要误用 getDay(),后者返回的是星期几)。
  3. 步骤三:月份基数校准:JavaScript 的 getMonth() 方法返回值遵循 0 ~ 11 的索引设计(0 代表 1 月,11 代表 12 月)。因此,提取月份后必须执行 +1 操作。
  4. 步骤四:双位数规范对齐:对于 1~9 的单月份、日期或小时,需要补足为两位(如 4 需显示为 04)。现代 ES2017 提供了 String.prototype.padStart(2, '0'),在字符长度小于 2 时会在左侧自动填充 '0'。
  5. 步骤五:组合输出目标格式:通过 ES6 模板字符串语法,将各变量用 -、空格和 : 拼接成符合 ISO 8601 视觉规范的标准日期时间文本。
JS怎么将13位时间戳转换为YYYY-MM-DD HH:mm:ss格式
图 2:原生 JavaScript 转换 5 步流水线流程图

三、底层机制与必须避开的 3 个关键陷阱

在实际业务开发中,时间戳转换看似简单,却极其容易因忽略底层细节而产生线上 Bug。以下是必须重点核查的机制与陷阱:

1. 13 位与 10 位时间戳的区别

UNIX 时间戳存在两种标准计量尺度:10 位(秒级)与 13 位(毫秒级)。JavaScript 的 Date 对象以毫秒为基准单位:

  • 13 位时间戳:代表自 1970 年 1 月 1 日 00:00:00 UTC 以来的毫秒数,直接传给 new Date(ts) 即可。
  • 10 位时间戳:代表秒数。如果直接传入 new Date(10位),会被当成毫秒解析,计算出来的年份会错误地停留在 1970 年。必须显式执行 new Date(ts * 1000)。
避坑提醒:如果你编写的是公共工具函数,建议加入位长判断:若检测到传入数值长度为 10 位,自动乘以 1000 进行容错补偿。

2. 月份索引 0~11 陷阱

这是新手甚至中级开发者最常遗漏的细节。date.getMonth() 返回的是数组索引,若不加 1,四月份会被格式化为 03,一月份会被格式化为 00。请务必牢记 date.getMonth() + 1。

3. 宿主本地时区与 UTC 时间差

getHours()、getMinutes() 取出的是运行代码所在宿主机器的本地时间。在东八区(UTC+8)环境下,同一时间戳的小时数会比 UTC 环境大 8 小时。如果业务需要输出统一的标准时间(例如国际化服务),应改用 getUTCFullYear()、getUTCMonth()、getUTCHours() 等 UTC 对应方法。

JS怎么将13位时间戳转换为YYYY-MM-DD HH:mm:ss格式
图 3:时间戳解析三层体系架构与核心避坑机制

四、方案对比:原生手写、Intl API 与 Day.js 如何选择

除了纯手动拆解分量外,JavaScript 生态中还有其他主流实现方案。它们在不同项目规模和开发场景下各有优劣:

对比维度 方案 A:原生手动拼装 (推荐) 方案 B:原生 Intl.DateTimeFormat 方案 C:Day.js / date-fns
依赖体积 0 KB(无需任何依赖) 0 KB(浏览器/Node 内置) ~2 KB(需 npm 引入)
运行性能 极高(简单的数值运算与拼接) 良好(构造格式化器有微小开销) 优秀(封装内部有轻微包装层)
时区支持 需手动调用 UTC 方法或算偏移 内置 timeZone: 'Asia/Shanghai' 通过时区插件轻松切换
代码可读性 逻辑直观,但有数行样板代码 配置参数较多,自定义分隔符繁琐 极高:dayjs(ts).format(...)
最佳适用场景 中小型项目、基础工具库、轻量脚本 需原生多语言、严格时区对齐的项目 已有工程化构建、频繁进行日期计算的大型项目
JS怎么将13位时间戳转换为YYYY-MM-DD HH:mm:ss格式
图 4:3 大主流日期格式化方案特性对比与技术选型决策树

方案 B 示例:使用现代内置 Intl.DateTimeFormat

function formatWithIntl(timestamp) {
  const date = new Date(Number(timestamp));
  const formatter = new Intl.DateTimeFormat('zh-CN', {
    year: 'numeric',
    month: '2-digit',
    day: '2-digit',
    hour: '2-digit',
    minute: '2-digit',
    second: '2-digit',
    hour12: false
  });
  // 将分量数组还原为 key-value 映射
  const parts = formatter.formatToParts(date).reduce((acc, p) => {
    acc[p.type] = p.value;
    return acc;
  }, {});
  return `${parts.year}-${parts.month}-${parts.day} ${parts.hour}:${parts.minute}:${parts.second}`;
}

五、生产级通用封装函数(防御式编程)

在企业级开发中,直接暴露裸逻辑容易受到脏数据污染。一个稳健的格式化工具应当具备:空值判断、非法时间戳防御、10/13位自动兼容以及自定义模板支持:

/**
 * 格式化时间戳为指定模板字符串
 * @param {number|string} timestamp 10位或13位时间戳
 * @param {string} format 格式模板,默认为 'YYYY-MM-DD HH:mm:ss'
 * @returns {string} 格式化结果,非法入参返回空字符串或提示
 */
function formatDate(timestamp, format = 'YYYY-MM-DD HH:mm:ss') {
  if (!timestamp) return '';

  // 1. 自动兼容 10 位秒级时间戳
  let ts = Number(timestamp);
  if (String(timestamp).trim().length === 10) {
    ts *= 1000;
  }

  // 2. 防御非法输入(如非纯数字字符串导致的 NaN)
  const date = new Date(ts);
  if (isNaN(date.getTime())) {
    console.warn('[formatDate] 无效的时间戳入参:', timestamp);
    return '';
  }

  // 3. 分量映射表
  const opt = {
    'Y+': String(date.getFullYear()),
    'M+': String(date.getMonth() + 1).padStart(2, '0'),
    'D+': String(date.getDate()).padStart(2, '0'),
    'H+': String(date.getHours()).padStart(2, '0'),
    'm+': String(date.getMinutes()).padStart(2, '0'),
    's+': String(date.getSeconds()).padStart(2, '0')
  };

  // 4. 正则动态替换模板占位符
  let result = format;
  for (const k in opt) {
    const reg = new RegExp(k);
    if (reg.test(result)) {
      result = result.replace(reg, opt[k]);
    }
  }
  return result;
}
测试用例与验证示例
formatDate(1711929600000); // "2024-04-01 08:00:00"
formatDate("1711929600000"); // "2024-04-01 08:00:00"(支持字符串输入)
formatDate(1711929600); // "2024-04-01 08:00:00"(自动识别 10 位并补乘 1000)
formatDate(null); // ""(安全降级,避免应用崩溃)

六、上线自查清单与常见问题排查

在将时间转换函数部署到生产环境之前,可以通过以下清单快速进行代码核对:

JS怎么将13位时间戳转换为YYYY-MM-DD HH:mm:ss格式
图 5:时间戳转换生产环境交付核对清单
  • 页面显示 NaN-NaN-NaN NaN:NaN:NaN 是怎么回事?
    原因是传入的 timestamp 无法解析为有效数字(例如传入了 undefined、"null" 或包含非数字字符的字符串)。通过 isNaN(date.getTime()) 进行前置拦截可有效避免此问题。
  • 转换出来的日期永远比实际少一个月?
    检查是否漏写了 getMonth() + 1。由于历史原因,JavaScript 的月份是从 0 开始计数的。
  • 显示效果为 2024-4-1 8:5:3,如何补齐为标准格式?
    直接在每个分量后链式调用 String(...).padStart(2, '0')。老旧环境若不支持 padStart,可采用三元表达式 num < 10 ? '0' + num : num 达成相同效果。
  • 为什么本地开发显示正常,部署到服务器或用户端时相差数小时?
    因为 getHours() 遵循运行环境的系统本地时区。若服务端 Docker 镜像默认时区为 UTC(0 时区),而国内前端为东八区(UTC+8),便会出现 8 小时的时差。前后端交互时建议统一采用 13 位 UTC 毫秒时间戳传输,展示层再统一根据客户端本地时区进行渲染。
作者最新文章
相关文章
更多