使用Moment.js获取去年同周同日出错,求修正方案及原因解析
解决Moment.js获取去年同月同周指定日期的问题
我来帮你分析问题并修正代码:
为什么你的测试代码会出错?
你写的这段代码:
console.log(moment().subtract(1, 'years').day(moment().day()).format('DD/MM/YYYY'))
核心问题有两个:
- 逻辑偏差:你想要的是去年同月第N周的周一,但这段代码完全没考虑“当月周数”的规则,只是简单把当前日期减一年后,调整成和今天一样的星期几——这和“同周”的需求根本不是一回事。
- 日期错位:由于闰年、不同年份的月份星期分布不同,减一年后的日期的星期几大概率和今天不一样。比如假设你当前是2020年3月2日(周一),减一年后是2019年3月2日(周六),调用
.day(1)会自动跳到最近的周一也就是2019年3月4日,这就是你得到04/03/2019的原因。
修正方案(匹配你的周定义)
根据你描述的规则:周从周日起始,某周只要包含当月一天就算当月的周,当前是3月第三周的周一,目标是去年3月第三周的周一。我们可以分两步实现:
第一步:计算当前是当月的第几周
先确定当前日期在当月的周序号:
const currentDate = moment(); // 你的当前日期,比如2020-03-16 // 获取当月第一天 const firstDayOfCurrentMonth = currentDate.clone().startOf('month'); // 找到当月第一周的起始日(周日) const firstWeekStart = firstDayOfCurrentMonth.clone().day(0); // 找到当前日期所在周的起始日(周日) const currentWeekStart = currentDate.clone().day(0); // 计算当前是当月第几个周 const weekNumInMonth = Math.floor(currentWeekStart.diff(firstWeekStart, 'weeks')) + 1;
第二步:找到去年同月对应周的周一
基于上面得到的周数,计算目标日期:
// 获取去年同月的第一天 const firstDayOfLastYearSameMonth = currentDate.clone().subtract(1, 'years').startOf('month'); // 找到去年同月第一周的起始日(周日) const lastYearFirstWeekStart = firstDayOfLastYearSameMonth.clone().day(0); // 找到去年同月第N周的起始日(周日) const targetWeekStart = lastYearFirstWeekStart.clone().add(weekNumInMonth - 1, 'weeks'); // 该周的周一就是起始日加1天 const targetMonday = targetWeekStart.clone().add(1, 'days'); // 输出结果 console.log(targetMonday.format('DD/MM/YYYY'));
验证你的案例
如果当前是2020年3月16日(第三周周一):
- 当月第一周起始是2020-03-01(周日),当前周起始是2020-03-15(周日),相差2周,所以
weekNumInMonth=3 - 去年3月第一周起始是2019-02-24(周日),加2周后是2019-03-10(周日),加1天就是2019-03-11,正好是你预期的
11/03/2019
简化版(如果用ISO周规则)
如果你的周定义是国际通用的ISO周(周一为一周起始,每年第1周包含1月4日),可以用更简洁的代码:
const currentDate = moment(); const targetDate = currentDate.clone() .subtract(1, 'years') .isoWeek(currentDate.isoWeek()) // 匹配去年的同一ISO周 .startOf('isoWeek'); // 获取该周的周一 console.log(targetDate.format('DD/MM/YYYY'));
这段代码直接定位到去年同一ISO周的周一,对于你的案例同样会返回11/03/2019。
内容的提问来源于stack exchange,提问作者Alexandre Elshobokshy




