You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何优化计算两日期间完整月份数的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;
}

细节说明

  1. 消除重复:新增的getNextMonthEndDate函数把原来两处重复的日期计算逻辑统一管理,后续修改只需要改这一处即可。
  2. 修复bug:原代码中判断month ==12是错误的,因为JS Date的月份是0开始(0=1月,11=12月),改成month ===11后才能正确处理跨年情况。
  3. 简化循环:循环内不再重复声明year和month变量,直接调用工具函数生成下一个月末日期,逻辑更简洁。
  4. 循环条件优化:原while (lastDate !== dateInPlay)可能因为Date对象的引用问题导致死循环,改成lastDate.getTime() >= dateInPlay.getTime()更可靠,同时避免无限循环风险。

内容的提问来源于stack exchange,提问作者Doug Barense

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 05:35:17