如何优化计算两日期间完整月份数的JavaScript代码?
改进日期差计算代码:消除重复逻辑并优化实现
你的代码里重复的let dateInPlay = zzGetLastDateOfTheMonth(new Date(year, month + 1, 1))逻辑可以通过封装成独立工具函数来解决,同时还能顺便修正原代码里的潜在bug,优化整体逻辑:
核心改进点
- 抽离重复的「获取下一个月末日期」逻辑为单独函数,彻底消除代码重复
- 修正月份判断的bug:原代码中
month == 12是错误的(JS的Date对象月份是0-11的索引,12是无效值),应该判断month === 11(即12月) - 简化循环内的变量声明与逻辑,让代码更清晰
优化后的完整代码
/** * Gets number of full months between dates * * @author me * @version 1.0 * @since 2022/10/24 * @param {Date} start date * @param {Date} end date * @return {number} number of months between dates */ function zzFullMonthsBetween(_startDate, _endDate) { let firstDate = zzGetFirstDateOfTheMonth(_startDate) let lastDate = zzGetLastDateOfTheMonth(_endDate) if (lastDate > firstDate) { let numberOfMonths = 1 // 同月直接返回 if (firstDate.getFullYear() === lastDate.getFullYear() && firstDate.getMonth() === lastDate.getMonth()) { return numberOfMonths } // 初始化当前遍历的月末日期 let dateInPlay = getNextMonthEndDate(firstDate) numberOfMonths++ do { if (lastDate.getTime() === dateInPlay.getTime()) { return numberOfMonths } numberOfMonths++ dateInPlay = getNextMonthEndDate(dateInPlay) } while (lastDate.getTime() >= dateInPlay.getTime()); } return undefined } // 新增:封装获取下一个月末日期的工具函数 function getNextMonthEndDate(date) { let year = date.getFullYear() let month = date.getMonth() // 处理12月(索引11)的跨年情况 if (month === 11) { year++ month = 0 } else { month++ } // 生成下一个月的第一天,再取月末 return zzGetLastDateOfTheMonth(new Date(year, month, 1)) } // function TESTzzFullMonthsBetween() // { // let today = new Date() // let dates = [new Date('1/1/2022'), new Date('10/24/2022'), new Date('11/27/2022'), new Date('12/5/2022'), new Date('1/2/2023'), new Date('2/1/2023'), new Date('2/2/2024'), ] // for (let z = 0; z < dates.length; z++) // Logger.log(`${dates[z]}: ${zzFullMonthsBetween(today, dates[z])}`) // } function zzGetFirstDateOfTheMonth(_date) { return new Date(_date.getFullYear(), _date.getMonth(), 1) } function zzGetLastDateOfTheMonth(_date) { let year = _date.getFullYear() let month = _date.getMonth() // 同样修正这里的月份判断bug if (month === 11) { year++ month = 0 } else { month++ } return zzAddOnDate(new Date(year, month, 1), -1) } function zzAddOnDate(_date, _daysToAdd) { var newDate = new Date(_date); newDate.setDate(newDate.getDate() + _daysToAdd); return newDate; }
细节说明
- 消除重复:新增的
getNextMonthEndDate函数把原来两处重复的日期计算逻辑统一管理,后续修改只需要改这一处即可。 - 修复bug:原代码中判断
month ==12是错误的,因为JS Date的月份是0开始(0=1月,11=12月),改成month ===11后才能正确处理跨年情况。 - 简化循环:循环内不再重复声明
year和month变量,直接调用工具函数生成下一个月末日期,逻辑更简洁。 - 循环条件优化:原
while (lastDate !== dateInPlay)可能因为Date对象的引用问题导致死循环,改成lastDate.getTime() >= dateInPlay.getTime()更可靠,同时避免无限循环风险。
内容的提问来源于stack exchange,提问作者Doug Barense
相关产品推荐
相关产品推荐

