公司开发的门店系统中有这样一个功能,就是在预约模块可以查看某个客户当前月和下个月的预约数据。而这两个月的预约数据是通过传入不同的参数(年,月),请求两次接口拿到的。
3 月份的数据,传入 { year:2025, month: 3 }
4 月份的数据,传入 { year:2025, month: 4 }
前天(2025-3-31)门店同事向我们反馈了一个 BUG,说客户 4 月份的预约数据看不到了。他们发给我的截图,3 月后面展示的是 5 月份的数据,直接跳过了 4 月。这就说明计算当前月的下一个月的逻辑出错了,3 后面是 4,现在却成了 5。其实这个功能上线有一段时间了,近期也没有人改动它,之前运行的好好的,怎么突然就出现 BUG 了呢?
看了下项目中的逻辑代码,挺简单的,就两行
const today = new Date()
today.setMonth(today.getMonth() + 1) // 计算下一个月
乍一看,没毛病呀,计算当前时间的下一个月。可问题就出在这,在浏览器控制台测试的结果如下:
那么具体原因是什么呢?
原因就是 setMonth() 方法与具体的日期是有关系的,特别是当涉及到月末日期时会出现特殊行为。
对于 2025-3-31 这个日期:
3 月有 31 天
4 月只有 30 天
当我们尝试将 2025-3-31 增加 1 个月时,日期就变成了 2025-4-31,而 4 月是没有 31 号的,所以这是一个无效的日期。而 JavaScript 的 Date 对象会自动处理这种 "溢出" 情况,当设置月份后导致日期无效(如 4 月 31 日),Date 对象会自动将日期调整为下个月的第 1 天。
所以正如上面控制台的测试结果一样, 2025-3-31 setMonth 加 1 之后,日期变成了 2025-5-1 。因此想要解决这个问题,我们计算月份的时候,忽略掉具体日期就行了。
const today = new Date()
const Y = today.getFullYear()
const M = today.getMonth()
const target = new Date(Y, M) // 只传入年月,忽略掉具体日期,日期不传:默认则是 1 号
target.setMonth(target.getMonth() + 1)