用day.js简化JS时间戳转换与格式化

作者:小满

时间:2026-11-02

浏览:551

本文详细讲解如何使用轻量级库 Day.js 简化 JavaScript 中的时间戳解析、双向转换与常用格式化,涵盖10位秒级与13位毫秒级时间戳处理、时区配置及常见陷阱排查。

文章目录

在前端与 Node.js 业务开发中,接口返回的创建时间、支付时间与日志记录几乎都以数字时间戳(Timestamp)形式存在。原生 JavaScript 的 Date 对象在处理时间戳时,要求开发者手动区分秒与毫秒、手动调用 getFullYear、getMonth() + 1 以及重复编写补零逻辑,极易引发偏移错误与样板代码堆叠。轻量级时间库 Day.js 仅约 2KB 大小,保持不可变(Immutable)设计,并提供极简的链式调用语法。本文将明确讲解如何利用 Day.js 解析 10 位与 13 位时间戳、实现标准格式化与逆向转换,并配合插件解决时区与相对时间需求。

用day.js简化JS时间戳转换与格式化
图 0:Day.js 时间戳转换核心工作流

一、原生 JS Date 处理时间戳的典型痛点

设想一个前端业务场景:后端微服务接口向页面返回了订单记录列表,其中创建时间字段为 10 位 Unix 时间戳 1730433600(单位:秒)。若使用 JavaScript 原生语法将其格式化为标准的 YYYY-MM-DD HH:mm:ss,开发者通常需要经历繁琐的步骤:

// 原生 JavaScript 处理时间戳
const rawTimestamp = 1730433600; // 10位秒级

// 1. 必须手动检查并乘以 1000 转换为毫秒
const date = new Date(rawTimestamp * 1000);

// 2. 手动提取各个分量并补零,注意月份为 0~11 必须加 1
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
const seconds = String(date.getSeconds()).padStart(2, '0');

const formatted = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
// 输出示例: "2024-11-01 12:00:00"

上述原生代码存在三大核心隐患:

  • 单位混淆风险:如果后端有时返回 10 位(秒),有时返回 13 位(毫秒),直接 new Date(1730433600) 会被视作 1970 年初的毫秒数,导致年份直接回退到 1970 年。
  • 月份陷阱:date.getMonth() 返回 0 到 11,疏忽未加 1 将导致日期月份整体错位一个月。
  • 样板代码冗长:每次格式化均需编写 6 次 padStart 与模板字符串拼接,封装不当时在项目中四处散落。
用day.js简化JS时间戳转换与格式化
图 1:原生 Date 与 Day.js 处理时间戳的机制与代码成本对比

二、安装与环境引入

Day.js 支持现代 Node.js、打包工具(Webpack、Vite、Rollup)以及浏览器直接引用环境。由于其核心库仅包含最常用的基础功能,其余高级功能采用插件(Plugin)机制按需载入,保障应用打包体积始终轻量。

1. 包管理器安装(工程化项目)

# 使用 npm
npm install dayjs

# 使用 yarn
yarn add dayjs

# 使用 pnpm
pnpm add dayjs

2. 代码中导入

// ES Module 语法(推荐)
import dayjs from 'dayjs';

// CommonJS 语法(Node.js 环境)
const dayjs = require('dayjs');

在不使用构建工具的传统 HTML 页面中,亦可通过 CDN 脚本直接引入,全局作用域下会自动挂载 dayjs 对象:

<script src="https://cdn.jsdelivr.net/npm/dayjs@1/dayjs.min.js"></script>
<script>
  console.log(dayjs().format());
</script>

三、区分并解析 10 位与 13 位时间戳

时间戳本质是指自 1970 年 1 月 1 日 00:00:00 UTC 起经过的时间量度。在实际开发中,时间戳通常以两种单位存在:

  1. 10 位数字(秒级):常见于 Unix 系统、Linux 底层服务、PHP 及部分 Go/Python 后端接口,例如 1730433600。
  2. 13 位数字(毫秒级):原生 JavaScript Date.now()、Java 默认 System.currentTimeMillis() 输出的格式,例如 1730433600000。
核心规则:根据时间戳长度匹配 Day.js 工厂方法

13 位毫秒级时间戳直接传入 dayjs(ms);10 位秒级时间戳必须使用 dayjs.unix(sec)。混用会导致时间被计算为 1970 年或遥远的未来。

1. 处理 13 位毫秒时间戳

const timestampMs = 1730433600000; // 13位

// 直接作为参数传递给 dayjs()
const dateObj = dayjs(timestampMs);

// 输出格式化字符串
console.log(dateObj.format('YYYY-MM-DD HH:mm:ss'));
// 示例输出: "2024-11-01 12:00:00"

2. 处理 10 位秒级时间戳

const timestampSec = 1730433600; // 10位

// 使用 dayjs.unix() 专门解析秒级时间戳
const dateFromUnix = dayjs.unix(timestampSec);

console.log(dateFromUnix.format('YYYY-MM-DD HH:mm:ss'));
// 示例输出: "2024-11-01 12:00:00"

3. 处理字符串格式的时间戳

后端 API 或 JSON 序列化有时会将大整数转为字符串传输(如 "1730433600")。若直接 dayjs("1730433600"),Day.js 会尝试按 ISO 8601 或字符串格式去解析,导致 Invalid Date。必须先将其转换为 Number 类型:

const strTimestamp = "1730433600";

// 先转换为数值类型
const num = Number(strTimestamp);

const formatted = dayjs.unix(num).format('YYYY-MM-DD');
console.log(formatted); // 示例输出: "2024-11-01"
用day.js简化JS时间戳转换与格式化
图 2:时间戳输入、解析、修饰及格式化输出的端到端执行流程

四、常用格式化模板与占位符规范

调用 .format(template) 方法时,Day.js 会将字符串模板中的特定标识符(Tokens)替换为计算后的对应数值。大小写在此具有严格的语义约束(例如大写 MM 代表月份,而小写 mm 代表分钟)。

占位符 输出含义 输出示例 说明与常见易错点
YYYY 四位数完整年份 2024, 2026 如需两位数年份可使用 YY
MM 两位数月份(01~12) 01, 11 自动补零;若写单个 M 则不补零(1~12)
DD 两位数日期(01~31) 05, 28 若写单个 D 则不补零(1~31)
HH 两位数24小时制(00~23) 08, 22 小写 hh 为 12 小时制(01~12)
mm 两位数分钟(00~59) 04, 59 切勿与月份 MM 混淆大小写
ss 两位数秒数(00~59) 00, 45 若写单个 s 则不补零
SSS 三位数毫秒数(000~999) 012, 850 高精微服务日志常用
d 星期几(0~6) 0 代表周日 配合语言包可输出“星期日”等本地文本
用day.js简化JS时间戳转换与格式化
图 3:Day.js 格式化占位符体系与典型场景映射关系

模板中包含固定文字的转义技巧

如果希望在格式化结果中保留纯英文字母(例如包含字母 D、Y、M 的单词),必须使用方括号 [] 进行包裹,否则这些字母会被误当作占位符解析:

const ts = 1730433600000;

// 错误示范:未经中括号转义,字母 'H' 会被解析成小时数值
console.log(dayjs(ts).format('YYYY-MM-DD Hours: HH'));
// 输出可能会出现意料之外的重复解析

// 正确示范:使用方括号包裹纯文本
const safeOutput = dayjs(ts).format('YYYY-MM-DD [Hour:] HH');
console.log(safeOutput);
// 示例输出: "2024-11-01 Hour: 12"

五、将时间对象反向转换回时间戳

在向后端提交表单、执行时间范围比对或缓存判定时,常常需要将某个已有的日期对象、当前时间或编辑后的时间字符串重新转换为纯数字时间戳。Day.js 提供了对称的输出方法:

1. 获取 13 位毫秒级时间戳:.valueOf()

// 获取当前时间的 13 位毫秒时间戳(等价于 Date.now())
const currentMs = dayjs().valueOf();
console.log(currentMs); // 示例输出: 1730433600000

// 将特定日期字符串反解为 13 位时间戳
const specificMs = dayjs('2024-11-01 12:00:00').valueOf();
console.log(specificMs); // 示例输出: 1730433600000

2. 获取 10 位秒级 Unix 时间戳:.unix()

// 获取当前时间的 10 位 Unix 时间戳
const currentSec = dayjs().unix();
console.log(currentSec); // 示例输出: 1730433600

// 将特定日期反解为 10 位时间戳
const specificSec = dayjs('2024-11-01 12:00:00').unix();
console.log(specificSec); // 示例输出: 1730433600

六、实际工程场景扩展:时区与相对时间

Day.js 核心保持极小体积的原因在于插件架构。在涉及跨时区业务或社交动态“刚刚/x分钟前”的场景中,只需按需载入对应插件。

1. 时区转换(UTC 与指定时区)

时间戳是绝对的 UTC 秒数,但格式化展现依赖客户端时区。如果用户在伦敦(UTC+0),而业务要求统一以北京时间(UTC+8)展示,可以配合 utc 和 timezone 插件:

import dayjs from 'dayjs';
import utc from 'dayjs/plugin/utc';
import timezone from 'dayjs/plugin/timezone';

// 载入插件
dayjs.extend(utc);
dayjs.extend(timezone);

const ts = 1730433600000;

// 强制使用 Asia/Shanghai 时区进行格式化输出
const shanghaiTime = dayjs(ts).tz('Asia/Shanghai').format('YYYY-MM-DD HH:mm:ss');
console.log(shanghaiTime);

// 输出为 UTC 零时区字符串
const utcTime = dayjs(ts).utc().format('YYYY-MM-DD HH:mm:ss');
console.log(utcTime);

2. 相对时间计算(如“3分钟前”)

对于评论区、通知列表,显示精确时间往往不如“几分钟前”直观。通过引入 relativeTime 插件及中文语言包可直接完成:

import dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime';
import 'dayjs/locale/zh-cn'; // 引入中文包

dayjs.extend(relativeTime);
dayjs.locale('zh-cn'); // 切换全局语言环境

const pastTs = Date.now() - 1000 * 60 * 15; // 15分钟前的时间戳

console.log(dayjs(pastTs).fromNow());
// 示例输出: "15 分钟前"
用day.js简化JS时间戳转换与格式化
图 4:时间戳处理全周期决策树与生产避坑排错图

七、生产环境常见注意事项与排查建议

  1. 有效性验证(.isValid()): 在解析来自外部或 URL 参数的时间戳前,调用 dayjs(val).isValid() 校验数据。如果输入非法值,可及时返回兜底展示内容(例如 "--"),避免页面渲染出 Invalid Date。
  2. 不可变对象(Immutability): 与原生 Date 直接在自身上修改分量不同,Day.js 的所有增减计算(例如 .add(7, 'day')、.startOf('month'))都会返回一个全新的 Dayjs 实例,原时间对象不受任何影响。若需要后续复用,请确保将计算结果赋予新变量。
  3. 统一封装工具函数: 建议在前端工程的 utils/time.js 中对时间戳格式化进行轻量封装,自动根据数值位数分支处理,彻底杜绝人工判断失误:
    // 推荐的工程化健壮封装
    export function formatTimestamp(raw, template = 'YYYY-MM-DD HH:mm:ss') {
      if (raw === null || raw === undefined || raw === '') return '--';
      const num = Number(raw);
      if (Number.isNaN(num)) return '--';
    
      // 根据数值长度自动分流:10位按秒,13位按毫秒
      const d = String(num).length === 10 ? dayjs.unix(num) : dayjs(num);
      return d.isValid() ? d.format(template) : '--';
    }

掌握以上核心要点后,时间戳在 JavaScript 中的解析、展示与逆向转换即可收敛为简短直观的代码调用,既提升了代码的可读性,也消除了原生日期运算中频发的边界缺陷。

实用工具推荐

电子包浆

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

使用 ›
图片压缩

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

使用 ›
相关文章