JS怎么将时间戳格式化为YYYY-MM-DD HH:mm:ss

作者:橙子时间:2026-11-03 17:19:06浏览:311

在JavaScript中将时间戳格式化为标准的 YYYY-MM-DD HH:mm:ss。本文详细讲解原生 Date 对象的各分量提取、月份加1与日期陷阱、双位补零机制、10位与13位时间戳自动兼容以及高可用容错封装。

JavaScript / 实用日期处理
类型:操作与原理讲解 环境:浏览器 / Node.js (全环境通用) 核心依赖:零依赖 (原生原生Date与String)
核心解法速览:在 JavaScript 中将时间戳转换为 YYYY-MM-DD HH:mm:ss 格式,最稳妥高效的做法是:先通过长度识别将 10 位(秒)或 13 位(毫秒)时间戳统一转换为毫秒并实例化为 new Date(ms),再分别调用 getFullYear()、getMonth() + 1、getDate()、getHours()、getMinutes() 和 getSeconds() 提取时间分量,最后借助 padStart(2, '0') 实施双位前导补零并拼接成字符串。
JS怎么将时间戳格式化为YYYY-MM-DD HH:mm:ss
缩略概览 // JavaScript 时间戳格式化全处理链路架构概览

一、开箱即用的生产级格式化函数

在日常业务开发中,时间戳通常来源于后端接口数据库记录或前端事件生成。下面这段原生封装函数涵盖了输入清洗、秒级/毫秒级智能识别、有效性校验及前导双位补零,可直接复制到项目中使用:

/**
 * 将时间戳格式化为 YYYY-MM-DD HH:mm:ss
 * @param {number|string} timestamp 10位秒级或13位毫秒级时间戳
 * @returns {string} 格式化时间文本,非法输入返回空字符串 ""
 */
function formatTimestamp(timestamp) {
  // 1. 拦截空值与非法类型(null、undefined、空字符串等)
  if (!timestamp && timestamp !== 0) return '';

  // 2. 清洗为纯数值与判断字符串长度
  const rawStr = String(timestamp).trim();
  const num = Number(rawStr);
  if (isNaN(num)) return '';

  // 3. 自动归一化:若为 10 位 Unix 时间戳则乘 1000 换算为毫秒
  const ms = rawStr.length === 10 ? num * 1000 : num;
  const date = new Date(ms);

  // 4. 安全熔断:检查是否为合法日期,防止产出 "NaN-NaN-NaN"
  if (isNaN(date.getTime())) return '';

  // 5. 双位补零工具函数:不足两位前面自动补 0
  const pad = (n) => String(n).padStart(2, '0');

  // 6. 提取基础分量(注意:月份必须 +1,日期使用 getDate)
  const year = date.getFullYear();
  const month = pad(date.getMonth() + 1);
  const day = pad(date.getDate());
  const hours = pad(date.getHours());
  const minutes = pad(date.getMinutes());
  const seconds = pad(date.getSeconds());

  // 7. 组装符合规范的标准定长字符串
  return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}

// 运行验证示例:
console.log(formatTimestamp(1714521600000)); // 示例输出: 2024-05-01 08:00:00 (根据本地时区转换)
console.log(formatTimestamp(1714521600));    // 示例输出: 2024-05-01 08:00:00 (自动兼容10位秒)
console.log(formatTimestamp('1714521600'));  // 示例输出: 2024-05-01 08:00:00 (兼容纯数字字符串)
console.log(formatTimestamp(null));          // 示例输出: "" (安全拦截空值)

二、完整处理流水线解析

将数值状态的时间戳转化为人类易读的指定格式,并不是简单的字符串相加,而是包含“类型归一、实例构造、属性解构、补零标准化、模板装配”五个连续阶段的流水线操作。

JS怎么将时间戳格式化为YYYY-MM-DD HH:mm:ss
图 1 // 时间戳格式化五步处理流水线工程架构与阶段端口示意图

这五个阶段的工程关注点分别如下:

  1. 校验与单位归一(Stage 01):Web 后端(如 PHP、Python、Go 或特定 MySQL 库)返回的时间戳经常是 10 位的 Unix 秒数,而 JavaScript 内部的 Date 对象必须接收 13 位的毫秒数。若直接把 10 位时间戳喂给 new Date(1714521600),其实际表示的是 1970 年 1 月 20 日的时间点。因此,判断长度为 10 时主动乘 1000 是至关重要的第一道防护。
  2. 实例化与有效性校验(Stage 02):JavaScript 中的 new Date(target) 在接收无法解析的值(如损坏的字符串、NaN)时不会抛出异常,而是会创建一个内部值为 NaN 的非法时间对象。调用 isNaN(date.getTime()) 可以直接检测并拦截非法实例,防止下游生成 NaN-NaN-NaN NaN:NaN:NaN。
  3. 分量提取(Stage 03):通过原生 API 将对象内部保存的时间基准解构为公历对应的离散字段。
  4. 前导双位补零(Stage 04):日期中的 5 月、8 日、9 秒必须规范化为 05、08、09。统一补零能确保整个时间文本固定为 19 个 ASCII 字符,避免在列表或表格中因字体宽度不同而产生抖动。
  5. 模板拼接(Stage 05):采用 ES6 模板字符串按 YYYY-MM-DD HH:mm:ss 形式组合装配。

三、Date 对象原生 API 与两大核心陷阱

JavaScript 的 Date 对象设计源于早期 Java 1.0 的 java.util.Date,其中保留了两个极为容易引发业务 Bug 的历史设计:

JS怎么将时间戳格式化为YYYY-MM-DD HH:mm:ss
图 2 // JavaScript Date 对象原生方法映射与两大易错陷阱排查矩阵

1. 陷阱一:月份从 0 开始计数(Month Indexing)

在所有常用编程语言中,JavaScript Date 的 getMonth() 是最容易让新手困惑的地方。它的返回值区间是 0 ~ 11,其中 0 代表 1 月,11 代表 12 月。如果开发者直接将 getMonth() 得到的值拼接进字符串,格式化出来的月份将会永远比实际时间少 1 个月。

避坑准则:获取月份时,必须显式书写为 date.getMonth() + 1。

2. 陷阱二:日期的获取是 getDate 而不是 getDay

在英文语境中,Day 容易被误认为是“天”。在 JavaScript API 中:

  • date.getDate():返回当前是该月的几号(数值范围 1 ~ 31),这才是我们构建 DD 字段所需要的 API。
  • date.getDay():返回当前是星期几(数值范围 0 ~ 6,0 代表周日,1~6 代表周一至周六)。

如果错误调用了 getDay(),在 2024 年 5 月 25 日执行时,由于当天是周六,返回的将是数字 6,结果会被错误显示为 2024-05-06,产生极为隐蔽的数据差错。

3. 补零方案选型:padStart 与 slice 的权衡

对单数字进行补零,目前业界常用的有两种纯原生实现:

实现写法 原理说明 标准版本 推荐度与场景
String(n).padStart(2, '0') ECMAScript 字符串原生前导补全 ES2017 (ES8) 首选推荐。语义直接,无需做字符串反向截取计算。
('0' + n).slice(-2) 先拼接 0 再通过负索引截取最后两位 ES3 / ES5 经典兼容方案。适合需要兼容非常老旧终端(如 Android 4.x、IE)的场景。

四、多种实现方案对比与选型建议

在实际工程项目中,除了手写原生 Date 拆解外,现代浏览器还提供了原生的国际化 API Intl.DateTimeFormat,以及社区广泛使用的轻量时间库(如 Day.js)。

JS怎么将时间戳格式化为YYYY-MM-DD HH:mm:ss
图 3 // 时间戳格式化三大实现方案特性对比与技术选型权衡

现代浏览器原生方案:Intl.DateTimeFormat

如果你的项目中涉及多语言或需要强制指定特定时区展示时间,可以使用现代浏览器原生的国际化对象。Intl.DateTimeFormat 支持提取各分量零件(parts):

function formatByIntl(timestamp, timeZone = 'Asia/Shanghai') {
  if (!timestamp && timestamp !== 0) return '';
  const ms = String(timestamp).length === 10 ? Number(timestamp) * 1000 : Number(timestamp);
  const date = new Date(ms);
  if (isNaN(date.getTime())) return '';

  // 创建格式化器,开启 24 小时制并指定时区
  const formatter = new Intl.DateTimeFormat('zh-CN', {
    timeZone,
    year: 'numeric',
    month: '2-digit',
    day: '2-digit',
    hour: '2-digit',
    minute: '2-digit',
    second: '2-digit',
    hour12: false
  });

  const parts = formatter.formatToParts(date);
  const map = {};
  parts.forEach(p => { map[p.type] = p.value; });

  return `${map.year}-${map.month}-${map.day} ${map.hour}:${map.minute}:${map.second}`;
}
选型小结:对于 95% 以上的前端与全栈项目,单纯将时间戳格式化为 YYYY-MM-DD HH:mm:ss,手写第一节的原生函数是最佳方案——打包体积为零,单次执行耗时通常低于 0.005 毫秒,且无任何外部引入版本维护负担。

五、工程化自查与决策速查

在将格式化逻辑正式合并至公共工具库或组件前,建议对照以下决策流程与自查清单,确保生产环境免受非法数据与环境差异的冲击。

JS怎么将时间戳格式化为YYYY-MM-DD HH:mm:ss
图 4 // 时间戳格式化决策树分支与生产环境自查清单

六、常见问题排查与速查解答 (FAQ)

Q1:为什么格式化出来的年份变成了 1970 年?

原因:后端接口返回的是 10 位的 Unix 秒级时间戳(例如 1714521600),而 JavaScript 的 new Date(ts) 默认只识别 13 位的毫秒级时间戳。由于缺少三位零,该数值被视作 1714521 秒(约 19.8 天),因此时间会落在 1970 年 1 月 20 日。
解决:在传入前进行长度判断,若为 10 位数则乘以 1000。

Q2:为什么输出的月份总比实际月份少 1 个月?

原因:date.getMonth() 返回的是 0 索引月份(0~11)。
解决:在取值时务必加上 1:date.getMonth() + 1。

Q3:为什么界面上显示出了 "NaN-NaN-NaN NaN:NaN:NaN"?

原因:传入的参数为 undefined、无法解析的字符串或非法数值,导致 new Date() 生成了 Invalid Date,后续执行数值运算全线坍缩为 NaN。
解决:在构造 Date 后加入有效性熔断:if (isNaN(date.getTime())) return '';。

Q4:同一时间戳在不同用户的电脑上显示的小时不一样?

原因:时间戳是基于格林威治标准时间(UTC 0 时区)的绝对物理时刻,而原生 date.getHours() 获取的是运行所在客户端操作系统的本地时区时间。例如北京时间(UTC+8)与伦敦时间(UTC+0)显示会相差 8 个小时。
解决:如果业务强制要求所有终端均展示统一时区(如北京时间),可采用第四节的 Intl.DateTimeFormat('zh-CN', { timeZone: 'Asia/Shanghai' }) 进行固定时区锁定。

作者最新文章
相关文章
更多