如何在JavaScript中借助Moment.js计算两个日期的日历周差值?
计算两个日期的日历周差值(含跨年处理)
这个问题我太熟悉了!Moment.js默认的diff('week')是按7天为一个周期计算,完全不考虑实际的日历周边界,所以会和你想要的结果对不上。而直接减周数又会在跨年时翻车——比如2023年最后一周和2024年第一周,直接减会得到负数,完全不符合预期。下面给你两种靠谱的解决方案,根据你的需求选:
先明确你的日历周定义
首先得确定你用的是哪种日历周规则,这很关键:
- ISO周:周一为一周起始,每年第1周是包含该年1月4日(或周四)的那周(每年最少52周,最多53周)
- 地区周:比如美国常用周日为起始,第1周是包含当年1月1日的周
方案1:计算两个日期所在日历周的差值(周数差,如周19到周20差1)
如果你的“差值”指的是周数的绝对差,这个方法能完美处理跨年:
function getWeekDiff(dateA, dateB, useISO = false) { const momentA = moment(dateA, 'DD-MMM-YYYY'); const momentB = moment(dateB, 'DD-MMM-YYYY'); const getWeekInfo = (m) => { if (useISO) { return { year: m.isoWeekYear(), week: m.isoWeek(), totalWeeks: moment(m.isoWeekYear()).isoWeeksInYear() }; } else { return { year: m.year(), week: m.week(), totalWeeks: moment(m.year()).weeksInYear() }; } }; const { year: yearA, week: weekA, totalWeeks: weeksA } = getWeekInfo(momentA); const { year: yearB, week: weekB, totalWeeks: weeksB } = getWeekInfo(momentB); let diff; if (yearA === yearB) { diff = Math.abs(weekB - weekA); } else if (yearB > yearA) { // 从A的周数到当年年底的周数 + 中间年份的总周数 + B当年的周数 diff = (weeksA - weekA); for (let y = yearA + 1; y < yearB; y++) { diff += useISO ? moment(y).isoWeeksInYear() : moment(y).weeksInYear(); } diff += weekB; } else { // 反过来计算跨年前的差值 diff = (weeksB - weekB); for (let y = yearB + 1; y < yearA; y++) { diff += useISO ? moment(y).isoWeeksInYear() : moment(y).weeksInYear(); } diff += weekA; } return diff; }
方案2:计算两个日期跨越的日历周数量(含起止周,如周19到周20算2)
看你的例子需要得到差值2,应该是要统计包含起止周的总数量。这个方案基于方案1,额外处理了同周的情况:
function getWeekCount(dateA, dateB, useISO = false) { const diff = getWeekDiff(dateA, dateB, useISO); // 判断两个日期是否在同一周 const momentA = moment(dateA, 'DD-MMM-YYYY'); const momentB = moment(dateB, 'DD-MMM-YYYY'); const sameWeek = useISO ? momentA.isoWeek() === momentB.isoWeek() && momentA.isoWeekYear() === momentB.isoWeekYear() : momentA.week() === momentB.week() && momentA.year() === momentB.year(); return sameWeek ? 1 : diff + 1; } // 测试你的例子(默认用周日为起始的地区周) const a = '09-May-2018'; const b = '14-May-2018'; console.log(getWeekCount(a, b)); // 输出2,完全符合你的需求!
关键注意点
- 一定要明确周的起始规则,不同地区的日历周起始不同,用
useISO参数切换即可 - 如果需要自定义周起始(比如周六为起始),可以用
moment.updateLocale设置:moment.updateLocale('en', { week: { dow: 6 // 周六为一周的第一天 } });
内容的提问来源于stack exchange,提问作者Ashish Bisht
相关产品推荐
相关产品推荐

