基于ISO标准的每月整周数计算问题(使用MomentJS)
用MomentJS计算ISO标准下的每月整周数
核心规则回顾
根据ISO日期格式规则:
- 如果当月包含周四,对应的整周数计入该月
- 若当月不包含周四,整周数则计入上月
- 以2018年为例:三月、五月、八月和十一月有5个整周,其余月份为4周
实现代码及说明
我给你调整后的可用代码(结合ISO规则修复后的版本):
function getISOWeeksInMonth(year, month) { // 注意MomentJS的月份是0基的,实际传参要减1(比如3月对应参数2) const monthStart = moment([year, month]); const monthEnd = moment(monthStart).endOf('month'); // 获取当月第一个周四的日期 const firstThursday = monthStart.clone().day(4); // 获取当月最后一个周四的日期 const lastThursday = monthEnd.clone().day(4); // 判断第一周是否属于当前月:若第一个周四在月初之前,则取当月第一周的周数 const startWeek = firstThursday.isBefore(monthStart) ? monthStart.clone().week() : firstThursday.week(); // 判断最后一周是否属于当前月:若最后一个周四在月末之后,则取当月最后一周的周数 const endWeek = lastThursday.isAfter(monthEnd) ? monthEnd.clone().week() : lastThursday.week(); // 处理跨年周数的边界情况(比如1月可能包含上一年最后一周) let weekCount; if (endWeek < startWeek) { weekCount = (52 - startWeek) + endWeek + 1; } else { weekCount = endWeek - startWeek + 1; } return weekCount; } // 测试2018年的情况 console.log(getISOWeeksInMonth(2018, 2)); // 3月,输出5 console.log(getISOWeeksInMonth(2018, 4)); // 5月,输出5 console.log(getISOWeeksInMonth(2018, 7)); // 8月,输出5 console.log(getISOWeeksInMonth(2018, 10)); // 11月,输出5 console.log(getISOWeeksInMonth(2018, 0)); // 1月,输出4
代码关键细节说明
- MomentJS月份特性:MomentJS的月份是0起始的,所以调用函数时要把实际月份减1(比如要查10月就传参数9)
- 周四核心判断:ISO周的定义是包含周四的周属于对应年份,延伸到月份规则就是——只要当月包含周四,该周就计入当月,所以通过定位首尾周四来划分周数归属
- 跨年周处理:年末月份可能出现周数跨到下一年的情况(比如12月最后一周是下一年第1周),这时候需要用52周来做差值计算,避免周数统计错误
常见问题修复提示
如果之前的代码结果不符合预期,大概率是没处理这几个点:
- 忽略了MomentJS月份的0基特性,导致月份定位错误
- 没有准确判断周四是否在当月内,错误划分了周数所属月份
- 没考虑跨年周的边界情况,导致周数计算偏差
内容的提问来源于stack exchange,提问作者tatsu
相关产品推荐
相关产品推荐

