JS怎么获取当前月份的最后一天

作者:纸飞机时间:2026-11-11 15:39:38浏览:444

在 JavaScript 中获取当前月份最后一天,最简便可靠的标准解法是 new Date(year, month + 1, 0)。本文通过图文与完整代码,深入解析下月第0天的借位回退机制、平闰年与跨年自适应、格式化字符串生成以及数据库查询边界等业务高频考点。

在 JavaScript 中获取当前月份最后一天的最简便且健壮的标准做法,是利用原生 Date 构造函数的天数借位机制:执行 new Date(year, month + 1, 0)。这里的关键在于向天数参数传入 0,JavaScript 引擎会自动将其解析为“次月第 1 天的前一天”,也就是当前月份的自然最后一天,且能全自动处理平闰年二月(28天或29天)及大小月变化。
JS怎么获取当前月份的最后一天
图 0:JavaScript 获取当前月份最后一天核心解法概览

一、核心解决方案与一行代码写法

在日常开发中,如果我们只需要快速取得当前月份的最后一天的日期(例如本月是 31 号、30 号还是 28/29 号),可以直接使用以下标准单行实现:

// 快速获取当前月份最后一天的日期号数(28~31)
const now = new Date();
const lastDayNumber = new Date(now.getFullYear(), now.getMonth() + 1, 0).getDate();

console.log(lastDayNumber); // 示例输出:31

这段代码分为三个紧密衔接的调用:

  • now.getFullYear():获取当前年份(四位数,例如 2026)。
  • now.getMonth():获取当前月份索引。在 JavaScript 规范中,月份索引从 0 开始计数(0 代表一月,11 代表十二月)。
  • new Date(year, month + 1, 0):构造目标日期。我们将月份参数设置为 month + 1(即下一个月),而天数参数设置为 0。
  • .getDate():从构造出的完整 Date 实例中,读取出当天对应的具体天数。

二、核心原理解析:“下月第 0 天”为什么有效?

初次接触此写法的读者常常会疑惑:自然日历中只有 1 号到 31 号,根本不存在“第 0 天”,为什么传入 0 不会抛出异常或返回 NaN?

这是由 ECMAScript 规范中对 Date(year, monthIndex, date, ...) 构造函数的溢出处理机制决定的。当我们在日期位置传入非标准范围的值时,JavaScript 引擎会执行自动算术进位或借位:

  • 如果传入的天数大于当月最大天数(例如 1 月传入 32),引擎会自动向后进位为 2 月 1 日。
  • 如果传入的天数等于 1,则代表该月的第 1 天。
  • 如果传入的天数小于 1(例如传入 0),引擎会将时间从“该月第 1 天”基准向前减去 1 天,从而自动借位回退到前一个月的最后一天。
JS怎么获取当前月份的最后一天
图 1:JavaScript 原生 Date 对象的“参数溢出借位”与回退机制示意

巧合的是,因为 now.getMonth() 得到的就是基于 0 计数的当月索引,当我们要表示“当前月份的下一个月”时,参数直接就是 now.getMonth() + 1。紧接着向天数传入 0,引擎便精准回退到了当前月份的末尾。

自动规避闰年与月份长短差异
不论当年是否为闰年,二月份究竟是 28 天还是 29 天,也不论当月是 30 天的大月还是 31 天的小月,底层的日历时间转换算法都会由浏览器和 Node.js 运行时自行完成,开发者完全不需要手写任何平闰年计算公式。

三、操作步骤与常见输出格式实现

实际业务中,我们往往不仅仅需要数字 31,还常常需要完整的 Date 实例、形如 YYYY-MM-DD 的日期字符串,或者是用于后端 API 数据库区间检索的精确毫秒时间戳。

JS怎么获取当前月份的最后一天
图 2:获取月末日期标准操作与输出流程图

1. 获取完整的月末 Date 对象

如果后续需要进行复杂的日期比较或时间增减,可以直接保留构造出来的 Date 对象:

function getCurrentMonthLastDateObject() {
  const now = new Date();
  // 构造出的 Date 对象的时分秒默认是当地时间的 00:00:00
  return new Date(now.getFullYear(), now.getMonth() + 1, 0);
}

2. 格式化为标准 YYYY-MM-DD 字符串

前端表单或接口请求中最常用的是标准日期字符串。在格式化时,需要注意月份从 0 开始必须先加 1,并使用 String.prototype.padStart() 补充前导零:

function getCurrentMonthLastDayString() {
  const now = new Date();
  const lastDate = new Date(now.getFullYear(), now.getMonth() + 1, 0);

  const year = lastDate.getFullYear();
  // 注意:getMonth() 取出的值需要 + 1 才是人类习惯的 1~12 月
  const month = String(lastDate.getMonth() + 1).padStart(2, '0');
  const day = String(lastDate.getDate()).padStart(2, '0');

  return `${year}-${month}-${day}`;
}

console.log(getCurrentMonthLastDayString()); // 示例输出:"2026-03-31"

3. 生成月末闭区间查询时间戳(23:59:59.999)

当编写日志过滤、订单对账等范围检索功能时(如 createdAt >= startTime AND createdAt <= endTime),仅仅取 00:00:00 会遗漏月末白天产生的所有数据。此时可以通过传入时分秒参数构造精确的月末截止时间:

function getCurrentMonthEndTime() {
  const now = new Date();
  // new Date(year, month, date, hours, minutes, seconds, ms)
  const endMoment = new Date(
    now.getFullYear(),
    now.getMonth() + 1,
    0,
    23, 59, 59, 999
  );
  return endMoment;
}

四、不同处理方案的对比与考量

除了 new Date(year, month + 1, 0) 之外,在社区或老旧项目中可能还会见到其他几种写法。我们将它们进行横向比对,帮助读者在选型时具备明确的判断依据:

JS怎么获取当前月份的最后一天
图 3:常见月末获取方案综合特性与评估对比
实现方案 典型代码 优点 缺点 / 风险
构造参数借位法(推荐) new Date(y, m + 1, 0) 一行代码、无外部依赖、全自动适配闰年与大小月 需理解月份 0 索引与天数 0 的借位机制
实例方法 setDate(0) d.setMonth(m + 1); d.setDate(0); 基于现有实例操作 代码较啰嗦(3行),容易对原变量产生意外修改(副作用)
静态天数表查表法 [31, isLeap?29:28, ...][m] 逻辑直观,直接查数组 必须额外手写整除 4、100、400 的闰年公式,代码冗长且易出错
现代 Temporal API(提案) Temporal.Now.plainDateISO().daysInMonth 语法现代清晰、不可变数据结构、防时区陷阱 尚未完全在所有旧版浏览器中原生普及,旧环境需 Polyfill

五、业务落地必须留意的四大避坑要点

在真实业务工程中,处理时间日期往往最容易引发偶发性 Bug。以下列出获取月末日期时最关键的四个自检项:

JS怎么获取当前月份的最后一天
图 4:月末日期计算要点与高频避坑自检清单

1. 记住 getMonth() 的 0 索引规则

Date.prototype.getMonth() 返回的是 0~11,其中 0 代表一月,11 代表十二月。初学者常犯的错误是在构造下个月第 0 天时误以为要减 1,写成了 new Date(year, month, 0),这样算出来的实际上是上个月的最后一天。牢记:当月用 month,下个月就是 month + 1。

2. 12 月跨年无需额外编写 if 分支

当处于 12 月份时,now.getMonth() 返回的是 11。此时 month + 1 等于 12。在 JavaScript 规范中,月份传入 12 会自动向年份进位 1 年,同时变成次年 1 月;接着天数参数 0 又使其从次年 1 月 1 日倒退 1 天,恰好回到了当年的 12 月 31 日。因此,完全不需要专门写 if (month === 11) 这类冗余判断。

3. 注意字符串补零(padStart)

在拼接 YYYY-MM-DD 格式时,如果直接用数字拼接,遇到单数月份或单数天数(例如 3 月 5 日),会产生 2026-3-5,这不符合 ISO 8601 标准规范,在部分前后端解析框架中可能会解析失败。始终记得使用 .padStart(2, '0') 保证两位格式。

4. 区分“日期号数”与“查询区间”

如果是用来作为日历表格的渲染格子总数,使用 .getDate() 取得数值即可;如果是用于后端数据库接口传参,务必确认后端所需的时间格式(是只包含年月日的纯日期字符串,还是精确到 23:59:59.999 的 ISO 8601 UTC 字符串),避免因时区或未覆盖全天引发查询偏差。

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