JavaScript根据日期范围生成月度周数据:代码输出错误排查
月度周号数组生成代码修正
需求描述
输入一组起止日期,需生成包含月度周号、周开始日期、周结束日期的数组。
输入示例
startDate = "2022-10-21" endDate = "2022-12-05"
期望输出示例
result = [ {weekNo: "Oct 2022 - Week 4", weekStartDate: "2022-10-21", weekEndDate: "2022-10-23"}, {weekNo: "Oct 2022 - Week 5", weekStartDate: "2022-10-24", weekEndDate: "2022-10-30"}, {weekNo: "Oct 2022 - Week 6", weekStartDate: "2022-10-31", weekEndDate: "2022-10-31"}, {weekNo: "Nov 2022 - Week 1", weekStartDate: "2022-11-01", weekEndDate: "2022-11-06"}, {weekNo: "Nov 2022 - Week 2", weekStartDate: "2022-11-07", weekEndDate: "2022-11-13"}, {weekNo: "Nov 2022 - Week 3", weekStartDate: "2022-11-14", weekEndDate: "2022-11-20"}, {weekNo: "Nov 2022 - Week 4", weekStartDate: "2022-11-21", weekEndDate: "2022-11-27"}, {weekNo: "Nov 2022 - Week 5", weekStartDate: "2022-11-28", weekEndDate: "2022-11-30"}, {weekNo: "Dec 2022 - Week 1", weekStartDate: "2022-12-01", weekEndDate: "2022-12-04"}, {weekNo: "Dec 2022 - Week 2", weekStartDate: "2022-12-05", weekEndDate: "2022-12-05"} ];
当前实现代码
constructWeekDataForCustomDates(startDate, endDate) { let currentDay = moment(startDate).day(), addDays, weekArrayData = []; if (currentDay == 0) { addDays = 1; } else if (currentDay == 1) { addDays = 0; } else if (currentDay == 2) { addDays = 6; } else if (currentDay == 3) { addDays = 5; } else if (currentDay == 4) { addDays = 4; } else if (currentDay == 5) { addDays = 3; } else if (currentDay == 6) { addDays = 2; } while(startDate <= endDate){ weekArrayData.push({ checkboxName: this.getweekNoOfMonth(startDate), checkboxStartValue: moment(startDate).format("YYYY-MM-DD"), checkboxEndValue: moment(startDate).add(addDays, 'day').format("YYYY-MM-DD") }); startDate = moment(startDate).add(addDays, 'day').format("YYYY-MM-DD"); addDays = 6; } console.log(weekArrayData) } // Function To get week no based on the date getweekNoOfMonth (date) { let input = moment(date) const firstDayOfMonth = input.clone().startOf('month'); const firstDayOfWeek = firstDayOfMonth.clone().startOf('week'); const offset = firstDayOfMonth.diff(firstDayOfWeek, 'days'); return Math.ceil((input.date() + offset) / 7); }
问题排查
原代码存在以下核心问题:
- 周结束日期逻辑错误:原代码计算的是到下一个周一的天数,而非需求中的本周日(或边界日期)。例如2022-10-21(周五)会被计算到2022-10-24(周一),但期望是到2022-10-23(周日)。
- 周号格式不匹配:
getweekNoOfMonth仅返回数字,未生成需求要求的"月 年 - Week 数字"格式字符串。 - 边界处理缺失:后续循环固定加6天,未考虑周结束日期超过当月最后一天或输入的
endDate的情况,导致跨月时周数据错误(如10月31日会被错误合并到11月的周)。 - 日期比较风险:使用字符串字典序比较日期,跨月时会出现逻辑错误(如
"2022-10-31" > "2022-11-01"字符串比较为true,但实际日期前者更小)。
修正后的代码
constructWeekDataForCustomDates(startDate, endDate) { // 转为moment对象,避免字符串比较错误 const startMoment = moment(startDate); const endMoment = moment(endDate); const weekArrayData = []; let currentStart = startMoment.clone(); while (currentStart.isSameOrBefore(endMoment)) { // 计算本周日的日期 let currentEnd = currentStart.clone().endOf('week'); // 取本周日、当月最后一天、结束日期的最小值作为周结束日期 const monthEnd = currentStart.clone().endOf('month'); currentEnd = moment.min(currentEnd, monthEnd, endMoment); // 生成符合格式的周号 const weekNo = this.getFormattedWeekNo(currentStart); weekArrayData.push({ weekNo: weekNo, weekStartDate: currentStart.format("YYYY-MM-DD"), weekEndDate: currentEnd.format("YYYY-MM-DD") }); // 下一周起始为当前周结束日期+1天 currentStart = currentEnd.clone().add(1, 'day'); } console.log(weekArrayData); return weekArrayData; } // 生成格式化的月度周号字符串 getFormattedWeekNo(dateMoment) { const input = dateMoment.clone(); const firstDayOfMonth = input.clone().startOf('month'); const firstDayOfWeek = firstDayOfMonth.clone().startOf('week'); const offset = firstDayOfMonth.diff(firstDayOfWeek, 'days'); const weekNum = Math.ceil((input.date() + offset) / 7); // 返回"月缩写 年 - Week 数字"格式 return `${input.format('MMM YYYY')} - Week ${weekNum}`; }
修正说明
- 日期处理优化:全程使用moment对象操作和比较日期,避免字符串比较的逻辑错误。
- 周结束日期修正:通过
endOf('week')获取本周日,再与当月最后一天、输入结束日期取最小值,确保周结束日期不超出边界。 - 周号格式修正:修改周号生成函数,返回需求要求的字符串格式,同时保留原正确的周数计算逻辑。
- 循环逻辑调整:每次循环从当前周结束日期的次日开始,直到超过输入的结束日期,确保所有日期区间都被覆盖。
内容的提问来源于stack exchange,提问作者Subha
相关产品推荐
相关产品推荐

