Day.js与Moment.js格式化当前时间的对比与选择

作者:阿沐

时间:2026-11-13

浏览:276

深入对比Day.js与Moment.js在格式化当前时间时的语法用法、核心机制、打包体积与不可变性差异,提供明确的选型依据与平滑迁移建议。

文章目录
在 JavaScript 开发中,如果需要获取并格式化当前系统时间,最核心的结论十分明确:对于所有新建的前端项目与 Node.js 现代服务,优先选择 Day.js。Day.js 在时间格式化的 API 语法上与 Moment.js 保持了高度一致(均使用 .format('YYYY-MM-DD HH:mm:ss')),但其打包体积压缩后仅约 2KB,远小于 Moment.js 的 70KB+;同时,Day.js 默认采用不可变数据模型,彻底规避了 Moment.js 因原位修改可能引发的时间污染缺陷。而在仍重度依赖大量历史插件且无需考虑打包体积的传统老项目中,继续维持 Moment.js 则是降低全量回归测试成本的稳妥做法。
Day.js与Moment.js格式化当前时间的对比与选择
图 1:Day.js 与 Moment.js 核心特性与格式化当前时间全景对比

一、基础用法对比:如何获取并格式化当前时间

在实际编码中,开发者最常碰到的需求是将当前时间转换成统一的字符串格式,例如日志记录、界面展示或接口传参。从基础代码实现来看,Day.js 与 Moment.js 在获取当前时间并进行格式化时的书写习惯极为贴近。

1. 依赖安装与模块引入

在现代包管理体系下,两者的安装命令与引入方式如下:

# 安装 Day.js
npm install dayjs

# 安装 Moment.js
npm install moment

在业务模块中的引入与调用写法对比如下:

// 方案 A:使用 Day.js
import dayjs from 'dayjs';

// 获取当前时间并输出标准时间格式
const dayjsNow = dayjs().format('YYYY-MM-DD HH:mm:ss');
console.log('Day.js 当前时间:', dayjsNow);
// 示例输出:"2026-11-10 20:55:00"

// 方案 B:使用 Moment.js
import moment from 'moment';

// 获取当前时间并输出标准时间格式
const momentNow = moment().format('YYYY-MM-DD HH:mm:ss');
console.log('Moment 当前时间:', momentNow);
// 示例输出:"2026-11-10 20:55:00"

当两者不传任何参数直接执行 dayjs() 或 moment() 时,底层均会以客户端当前系统的毫秒时间戳构造实例。对于常规的年、月、日、时、分、秒格式化字符串,两者的输出结果完全一致。

Day.js与Moment.js格式化当前时间的对比与选择
图 2:当前时间获取与格式化全流程操作步骤

二、格式化标记(Tokens)与本地化处理

格式化当前时间时,标记(Tokens)的解析规则是开发者最关心的部分。两库对常用占位符定义了相同的语义规范,但在语言包(Locale)和扩展标记的处理上体现出了架构差异。

分类 占位符 Token 说明 当前时间输出示例 Day.js 依赖说明
年份 YYYY / YY 4位 / 2位年份 2026 / 26 原生核心内置
月份 MM / M 两位补零 / 不补零月份 11 / 11 原生核心内置
日期 DD / D 两位补零 / 不补零日期 10 / 10 原生核心内置
24小时制 HH / H 00-23 / 0-23 20 / 20 原生核心内置
12小时制 hh / h 01-12 / 1-12 08 / 8 原生核心内置
分秒 mm / ss 补零分秒(00-59) 55 / 00 原生核心内置
毫秒 SSS 三位毫秒值 321 原生核心内置
星期几 dddd / ddd 星期全称 / 缩写 星期二 / 周二 需载入中文语言包
午前/午后 A / a 大写 / 小写标志 下午 / pm 需载入中文语言包
季度/序数 Q / Do 季度值 / 英文序数 4 / 10th 需加载 advancedFormat 插件

中文语言包的配置差异

如果需要将当前时间格式化为带有“星期几”或“上午/下午”的中文描述,例如 2026年11月10日 星期二 下午 08:55,两者的配置机制存在显著差异:

// 1. Day.js 的按需引入方式(推荐方式,严格控制体积)
import dayjs from 'dayjs';
import 'dayjs/locale/zh-cn'; // 单独载入对应语言包

dayjs.locale('zh-cn'); // 全局切换为中文环境
console.log(dayjs().format('YYYY年MM月DD日 dddd A hh:mm'));
// 示例输出:"2026年11月10日 星期二 下午 08:55"

// 2. Moment.js 的语言包处理
import moment from 'moment';
import 'moment/locale/zh-cn';

moment.locale('zh-cn');
console.log(moment().format('YYYY年MM月DD日 dddd A hh:mm'));
// 示例输出:"2026年11月10日 星期二 下午 08:55"
重点提醒:Moment.js 默认包含了全球数百种语言包,在 Webpack 等常规打包配置下,极容易把所有语言包打包进输出文件,导致体积剧增;而 Day.js 的语言包完全模块化独立,未导入的语言绝不会进入最终产物。
Day.js与Moment.js格式化当前时间的对比与选择
图 3:常用时间格式化占位符(Tokens)对标与支持矩阵

三、核心机制差异:对象可变性与连续格式化陷阱

在很多实际业务中,获取当前时间后,往往会配合简单的时间计算或偏移后再进行格式化(例如“展示当前时间,并预估1小时后到期时间”)。正是在这一常见链路上,Moment.js 与 Day.js 的底层设计产生了根本性分野。

1. Moment.js 的原位修改(Mutable)及其副作用

Moment.js 对象是可变的(Mutable)。调用其时间增减方法(如 .add() 或 .subtract())会直接修改当前对象本身的内部时间戳。

import moment from 'moment';

const currentTime = moment(); // 记录当前时间,假设为 20:00
console.log('格式化当前时间:', currentTime.format('HH:mm')); // "20:00"

// 业务需求:计算下一次执行时间(加1小时)
const nextTime = currentTime.add(1, 'hour');

// 致命陷阱:此时再次使用 currentTime 格式化当前时间
console.log('再次格式化当前时间:', currentTime.format('HH:mm')); // 输出:"21:00" ❌
console.log('两者是否指向同一对象:', currentTime === nextTime); // 输出:true

在这个例子中,原本用于代表“当前时间”的 currentTime 变量,在执行完 .add() 之后其自身的时间被直接篡改。如果该变量在后续逻辑或子组件中被再次用于展示当前时间,就会引发非常隐蔽的业务 Bug。为了避免此问题,开发者必须时刻牢记手动调用 .clone():

// 必须繁琐地显式克隆
const nextTime = currentTime.clone().add(1, 'hour');

2. Day.js 的不可变设计(Immutable)

Day.js 在设计之初就吸取了这一教训,采用了不可变(Immutable)架构。对 Day.js 对象执行的任何时间操作,都会生成并返回一个全新的 Day.js 实例,原有实例绝对保持不变。

import dayjs from 'dayjs';

const currentTime = dayjs(); // 记录当前时间,假设为 20:00
console.log('格式化当前时间:', currentTime.format('HH:mm')); // "20:00"

// 业务需求:计算下一次执行时间(加1小时)
const nextTime = currentTime.add(1, 'hour');

// 安全输出:currentTime 内部状态保持完全只读
console.log('再次格式化当前时间:', currentTime.format('HH:mm')); // 依然稳定输出:"20:00" ✓
console.log('nextTime 格式化:', nextTime.format('HH:mm')); // 输出:"21:00" ✓
console.log('两者是否指向同一对象:', currentTime === nextTime); // 输出:false

不可变性使得 Day.js 可以安全地在组件树、状态管理(如 Redux、Pinia)以及工具函数之间自由传递,开发者无须担心当前时间对象在某处被意外修改。

Day.js与Moment.js格式化当前时间的对比与选择
图 4:对象可变性与时间格式化副作用机制对比

四、容易混淆的认知与辨析

在技术社区中,关于 Day.js 与 Moment.js 的替代关系常有一些流传甚广的看法,有必要进行针对性的辨析与修正:

1. 误区一:“Day.js 是 Moment.js 的 100% 完整平替,无须任何改动”

辨析与修正:这种说法在“格式化当前时间”这一常用场景下基本成立,因为基本的 .format('YYYY-MM-DD HH:mm:ss') 语法完全兼容。但是,Day.js 采用了插件化架构,并非所有 Moment.js 的高级特性都内置在 2KB 的核心包中。

例如,如果你的格式化模板使用了季度(Q)、英文序号(Do)或严格模式解析,直接调用 Day.js 会出现解析缺失或告警。此时必须先显式声明插件:

import dayjs from 'dayjs';
import advancedFormat from 'dayjs/plugin/advancedFormat';

dayjs.extend(advancedFormat);
console.log(dayjs().format('YYYY年 第Q季度 Do天')); 
// 示例输出:"2026年 第4季度 10th天"

2. 误区二:“Moment.js 已经被废弃,现存老项目必须立刻全部重写”

辨析与修正:官方声明的是 Moment.js 进入“维护状态(Maintenance Mode)”,不再新增功能,但依然会修复关键安全漏洞。对于规模庞大、深度整合了 Moment 各种私有方法或旧版组件库的既有后台项目,如果不面临严格的首屏加载限制,盲目进行全局重构反而会带来非预期回归的风险。只有在确实存在网络加载瓶颈或重构契机时,进行平滑替换才是合理做法。

五、选型与迁移建议

综合性能、安全性与维护成本,针对不同项目场景的决策路径如下:

  1. 新建立项的前端或 Node.js 服务:坚决选择 Day.js
    当前时间格式化作为最基础的高频需求,Day.js 仅 2KB 的包体积对首屏性能极度友好,同时天生的不可变性消除了团队协作中的隐性 Bug。
  2. 正处于维护期、面临打包体积优化的既有项目:平滑迁移至 Day.js
    可先从时间格式化的通用工具函数着手,用 Day.js 替换 Moment.js;对于常规格式化代码,几乎只需要将 moment(...) 文本替换为 dayjs(...)。
  3. 短期内无维护计划或依赖旧UI框架的历史系统:保持 Moment.js
    若项目依赖了像旧版 Ant Design(3.x)等强绑定 Moment 的组件库,强行替换往往成本过高。此时可通过配置构建工具(如 ContextReplacementPlugin)移除多余语言包,以缓解体积负担。
Day.js与Moment.js格式化当前时间的对比与选择
图 5:工程选型与重构迁移决策树
迁移小结:格式化当前时间是日常开发中最常见、最基础的操作。Day.js 凭借对 Moment.js 语法的极高兼容度、极致轻量的工程体积以及现代不可变数据规范,已经成为这一场景下的现代标准解法。

实用工具推荐

电子包浆

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

使用 ›
图片压缩

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

使用 ›
相关文章