day.js 与原生 Date 获取当前月份的写法对比
深入对比 JavaScript 原生 Date 对象与 Day.js 库在获取当前月份时的 API 设计、返回值索引差异、补零格式化步骤及最佳实践。
在 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。
二、原生 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
dayjs().month() 已经自动加过 1。实际上它严格遵循了 Moment.js 的规范,依然是 0 到 11。要想一步获得人类习惯的自然月,应当优先使用 dayjs().format('M') 或 dayjs().format('MM')。
四、操作步骤与流水线对比
为了直观展现两者在工程实现上的步骤复杂度,我们将“获取一个形如 '05' 的标准当前月份字符串”拆解为具体的流水线步骤。
从上方流水线可以看到:
- 原生
Date要求开发者手动承担“索引转自然月”、“类型转换”和“字符串补零”三项额外责任,虽然代码只有一两行,但心智负担较重,极易在团队协作中出现漏写+ 1或拼写错误的问题。 Day.js将底层流水线封装在声明式的format('MM')令牌解析器中,代码不仅短小,且语义极其清晰,阅读代码时无需在大脑中进行运算推导。
五、场景选型建议:何时选原生?何时选 Day.js?
在实际项目架构中,究竟是直接使用原生 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 污染) | ✔ 是 (天然不可变,返回新实例) | - |
综上所述,获取当前月份时:如果仅做轻量计算,掌握原生 getMonth() + 1 的底层原理即可快速解决;如果身处常规 Web 或 Node.js 业务工程,借助 dayjs().format('MM') 能够大幅减少补零逻辑,写出更具健壮性、可读性更高的优雅代码。
JS脚本在App中运行报错怎么解决
2026-11-04 23:11:03
JS怎么使用padStart方法给数字补零
2026-11-04 11:12:03
JS是什么意思?JavaScript全称及基本定义
2026-11-04 08:05:29
JS 使用 toFixed(1) 保留一位小数的基本用法与注意事项
2026-11-03 18:34:57
JS字符串转整数:parseInt与Number的区别及用法
2026-11-03 17:26:54
相关标签:








