day.js 与原生 Date 获取当前月份的写法对比

作者:橙子

时间:2026-11-03

浏览:344

深入对比 JavaScript 原生 Date 对象与 Day.js 库在获取当前月份时的 API 设计、返回值索引差异、补零格式化步骤及最佳实践。

文章目录
JavaScript 日期处理 API 对比分析 工程实践指南
day.js 与原生 Date 获取当前月份的写法对比
图 1:原生 Date 与 Day.js 获取月份核心机制与输出形式总览

在 JavaScript 开发中,获取当前月份是一个基础却极其容易踩坑的操作。原生 Date 对象的 getMonth() 方法返回的是基于 0 的索引值(0 代表 1 月,11 代表 12 月),实际业务中几乎都需要手动加 1 并进行补零格式化;而轻量日期库 day.js 虽保持了底层 API 兼容性(其 .month() 方法同样返回 0 到 11),但通过声明式的 .format() 模板方法,可以直接一步返回符合直觉的自然月数字或标准化字符串。本文将围绕返回值索引、数值计算、字符串补零以及场景选型,深入对比两者的具体写法与底层差异。

一、核心痛点:为什么获取月份容易出错?

许多初学者在首次使用 JavaScript 原生日期方法时,会写出类似 new Date().getMonth() 的代码,并直接将其作为当前月份展示在页面上。然而如果在 5 月运行这段代码,得到的返回值却是 4;在 12 月运行,得到的返回值是 11。

这种设计并非 JavaScript 独有,而是有着深厚的历史渊源:JavaScript 最早由 Brendan Eich 在 1995 年设计,当时直接移植了 Java 1.0 的 java.util.Date 规范,而 Java 又是参考了 C 语言标准库中的 struct tm 结构体。在 C 语言中,tm_mon 被定义为自一月以来的月份数,范围即是 [0, 11]。尽管这个设计在现代编程语言中屡遭诟病,但为了保持向后兼容,原生 Date 始终保留了这一设定。

因此,要获取真实业务中的“自然月”,开发者必须牢记以下核心规则:

  • 原生 Date:getMonth() 返回 0 ~ 11,自然月份必须手动 + 1。
  • Day.js 的数值方法:dayjs().month() 同样返回 0 ~ 11(为了完全兼容 Moment.js 和原生惯例)。
  • Day.js 的格式化方法:dayjs().format('M') 返回 1 ~ 12,dayjs().format('MM') 返回 01 ~ 12。
day.js 与原生 Date 获取当前月份的写法对比
图 2:底层 0-index 与业务 1-12 自然月份转换映射模型

二、原生 Date 获取当前月份的具体写法

在不引入任何第三方依赖的原生环境中,获取当前月份主要分为获取“数字类型月份”与“补零字符串月份”两种场景。

1. 获取纯数字月份(1 ~ 12)

最直接的写法就是通过 new Date().getMonth() + 1。这里的 + 1 是必须的运算步骤:

// 示例:获取当前月份数字
const now = new Date();
const currentMonthNumber = now.getMonth() + 1;

console.log(currentMonthNumber); 
// 假设当前为5月,输出结果为数字:5

2. 获取补零对齐字符串('01' ~ '12')

在日期回显、表单提交或与后端接口交互时,通常需要保持两位固定长度(例如 2026-05)。原生写法通常有以下几种方式:

方式 A:ES2017 padStart(现代标准推荐)

通过先将数字转换为字符串,再利用 String.prototype.padStart() 在左侧补齐 '0':

const now = new Date();
const currentMonthPadded = String(now.getMonth() + 1).padStart(2, '0');

console.log(currentMonthPadded); 
// 5月输出字符串:'05';11月输出字符串:'11'

方式 B:截取切片法 slice(-2)(兼容旧环境)

在不支持 padStart 的老旧浏览器环境中,常见的技巧是先在前面拼接 '0',然后截取末尾两位:

const now = new Date();
const currentMonthSlice = ('0' + (now.getMonth() + 1)).slice(-2);

console.log(currentMonthSlice); 
// 5月输出:'05'

方式 C:使用 Intl.DateTimeFormat(国际化标准)

如果业务有复杂的本地化格式诉求,可以使用原生内置的 Intl 对象:

const formatter = new Intl.DateTimeFormat('zh-CN', { month: '2-digit' });
const currentMonthIntl = formatter.format(new Date());

console.log(currentMonthIntl); 
// 输出:'05月' 或 '05'(具体取决于 locale 与格式选项)
注意事项:使用原生 Date 补零时,一定要注意运算优先级。如果误写成 '0' + now.getMonth() + 1,由于字符串拼接优先,在 5 月(getMonth() 为 4)时会得到 '041',引发严重的业务错误。务必加上括号:('0' + (now.getMonth() + 1))。

三、Day.js 获取当前月份的具体写法

Day.js 是一个仅有 2KB 左右的现代轻量时间处理库,其 API 保持与经典库 Moment.js 高度一致,同时所有操作均为不可变数据(Immutable)。在 Day.js 中获取当前月份,写法更加简洁直观。

1. 使用 format() 直接获取(推荐写法)

Day.js 提供了极其强大的格式化占位符。获取当前月份时,开发者无需关心底层是否以 0 起始,直接使用 format() 方法即可:

import dayjs from 'dayjs';

// 获取两位补零月份('01' ~ '12')
const monthMM = dayjs().format('MM');
console.log(monthMM); // 5月输出字符串:'05'

// 获取单数字不补零月份('1' ~ '12')
const monthM = dayjs().format('M');
console.log(monthM);  // 5月输出字符串:'5'

2. 使用 month() 方法获取数值

如果后续需要将月份代入数学运算(如计算季度、加减计算),可以使用 .month() 方法。但请注意:dayjs().month() 返回的同样是 0 到 11 的索引:

import dayjs from 'dayjs';

// 获取 0-indexed 月份(用于底层兼容)
const rawMonthIndex = dayjs().month(); 
console.log(rawMonthIndex); // 5月输出:4

// 获取实际自然月份数字
const currentNaturalMonth = dayjs().month() + 1;
console.log(currentNaturalMonth); // 5月输出:5
核心差异提醒:很多从原生切到 Day.js 的开发者会产生误区,以为 dayjs().month() 已经自动加过 1。实际上它严格遵循了 Moment.js 的规范,依然是 0 到 11。要想一步获得人类习惯的自然月,应当优先使用 dayjs().format('M') 或 dayjs().format('MM')。

四、操作步骤与流水线对比

为了直观展现两者在工程实现上的步骤复杂度,我们将“获取一个形如 '05' 的标准当前月份字符串”拆解为具体的流水线步骤。

day.js 与原生 Date 获取当前月份的写法对比
图 3:获取标准化两位补零月份的操作步骤对比流水线

从上方流水线可以看到:

  • 原生 Date 要求开发者手动承担“索引转自然月”、“类型转换”和“字符串补零”三项额外责任,虽然代码只有一两行,但心智负担较重,极易在团队协作中出现漏写 + 1 或拼写错误的问题。
  • Day.js 将底层流水线封装在声明式的 format('MM') 令牌解析器中,代码不仅短小,且语义极其清晰,阅读代码时无需在大脑中进行运算推导。

五、场景选型建议:何时选原生?何时选 Day.js?

在实际项目架构中,究竟是直接使用原生 Date 还是引入 Day.js,需要结合项目规模、运行环境与业务复杂度综合考量。

day.js 与原生 Date 获取当前月份的写法对比
图 4:原生 Date 与 Day.js 在业务开发中的决策参考树

1. 优先选择原生 Date 的情况

  • 编写无依赖的底层工具库或独立 SDK:对包体积(Bundle Size)要求极其严苛,不希望引入任何第三方 npm 依赖。
  • 仅需获取数字月份进行纯算法判断:比如判断当前是不是一季度(month <= 3),此时直接 new Date().getMonth() + 1 足以胜任。
  • 现代 Node.js 服务端脚本或微服务小工具:只需简单几行代码输出日志时间戳,不想维护额外的 package.json 依赖。

2. 优先选择 Day.js 的情况

  • 业务系统已具备 npm 生态:前端 React / Vue 工程或 Node 后台管理系统,通常本就需要展示各种时间格式。Day.js 体积仅 2KB,对首屏加载影响微乎其微。
  • 需要频繁补零与多模板展示:比如同一个月份需要展示为 '05'、'5' 或英文全称 'May',Day.js 提供了完整的掩码支持。
  • 伴随复杂的日期偏移操作:例如不仅要获取当前月份,还要获取“上个月”(dayjs().subtract(1, 'month').format('MM'))或者“本月最后一天”,原生 Date 的可变性(Mutable)极容易产生连锁副作用,而 Day.js 的不可变性(Immutable)天然避免了此类缺陷。

六、总结与速查清单

为了便于日常编码快速查阅,以下将原生 Date 与 Day.js 获取月份的关键语法与行为整理为速查表:

目标输出类型 原生 Date 写法 Day.js 写法 以当前 5 月为例的输出值
底层索引 (0-11) new Date().getMonth() dayjs().month() 4 (Number)
自然月份 (1-12) new Date().getMonth() + 1 dayjs().month() + 1 或 dayjs().format('M') 5 (Number) 或 '5' (String)
标准补零 ('01'-'12') String(new Date().getMonth() + 1).padStart(2, '0') dayjs().format('MM') '05' (String)
旧环境兼容补零 ('0' + (new Date().getMonth() + 1)).slice(-2) dayjs().format('MM') '05' (String)
不可变性保证 ❌ 否 (原生对象易受 setMonth 污染) ✔ 是 (天然不可变,返回新实例) -
day.js 与原生 Date 获取当前月份的写法对比
图 5:原生 Date 与 Day.js 核心特性总结与开发备忘看板

综上所述,获取当前月份时:如果仅做轻量计算,掌握原生 getMonth() + 1 的底层原理即可快速解决;如果身处常规 Web 或 Node.js 业务工程,借助 dayjs().format('MM') 能够大幅减少补零逻辑,写出更具健壮性、可读性更高的优雅代码。

实用工具推荐

电子包浆

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

使用 ›
图片压缩

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

使用 ›
相关文章