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

JavaScript实现跳过节假日的小时累加日期计算:现有脚本逻辑缺陷排查与功能扩展

解决工作时间累加的两个问题:跨天逻辑修复 + 节假日支持

咱们一步步拆解你的核心问题,重构代码来彻底解决它们:

一、先修复跨天计算的逻辑错误

你的现有脚本在处理跨天(尤其是需要跳过多个工作日)的场景时逻辑不够严谨,比如17:00累加10小时的情况:当天剩余工作时间只有1小时(17到18点),剩下的9小时需要放到下一个工作日的9点开始累加,最终应该是次日18:00。咱们改成逐天扣减剩余时长的方式,逻辑会更可靠:

  1. 先把当前时间调整到工作时间范围内(如果在上班前,跳到上班时间;如果在下班后,跳到下一个工作日的上班时间)
  2. 循环处理剩余要添加的小时数:
    • 计算当天还剩多少工作时间可用
    • 如果剩余时长≤当天剩余工作时间,直接累加后结束
    • 如果剩余时长更多,就把剩余时长减去当天剩余时间,然后跳到下一个工作日(自动跳过周末),重复这个过程

二、添加节假日支持

要从Google表格读取节假日列表,我们可以用SpreadsheetApp获取指定表格的某列数据,把这些日期转换成Date对象后,就能在判断工作日时额外检查是否是节假日了。

完整修复后的代码

function calculateWorkTime(startDate, addHours) {
  // 配置工作时间参数
  const WORK_START = 9; // 上班时间
  const WORK_END = 18; // 下班时间
  const WORK_HOURS_PER_DAY = WORK_END - WORK_START; // 每天工作时长

  // 1. 从Google表格获取节假日列表(替换成你的表格ID和列范围)
  function getHolidays() {
    const spreadsheetId = "你的Google表格ID";
    const range = "Sheet1!A:A"; // 假设节假日存在Sheet1的A列,每行一个日期
    const sheet = SpreadsheetApp.openById(spreadsheetId).getRange(range).getValues();
    // 把表格日期转为Date对象,过滤空行
    return sheet
      .filter(row => row[0] !== "")
      .map(row => {
        const date = new Date(row[0]);
        // 统一日期格式为yyyy-MM-dd,避免时间部分干扰判断
        return new Date(date.getFullYear(), date.getMonth(), date.getDate());
      });
  }

  // 2. 判断某个日期是否是工作日(非周末+非节假日)
  function isWorkDay(date) {
    const day = date.getDay();
    // 周六(6)或周日(0)是周末
    if (day === 0 || day === 6) return false;
    // 检查是否在节假日列表里
    const holidays = getHolidays();
    const targetDate = new Date(date.getFullYear(), date.getMonth(), date.getDate());
    return !holidays.some(holiday => holiday.getTime() === targetDate.getTime());
  }

  // 3. 获取下一个工作日的上班时间
  function getNextWorkDayStart(currentDate) {
    let nextDay = new Date(currentDate);
    nextDay.setDate(nextDay.getDate() + 1);
    // 跳过所有非工作日
    while (!isWorkDay(nextDay)) {
      nextDay.setDate(nextDay.getDate() + 1);
    }
    // 设置到当天上班时间
    nextDay.setHours(WORK_START, 0, 0, 0);
    return nextDay;
  }

  // 4. 初始化处理起始时间
  let currentTime = new Date(startDate);
  let remainingHours = addHours;

  // 先把起始时间调整到工作时间范围内
  if (currentTime.getHours() < WORK_START) {
    currentTime.setHours(WORK_START, 0, 0, 0);
  } else if (currentTime.getHours() >= WORK_END) {
    currentTime = getNextWorkDayStart(currentTime);
  }

  // 5. 循环累加剩余时长
  while (remainingHours > 0) {
    // 计算当天剩余的工作时长(小时)
    const todayEnd = new Date(currentTime);
    todayEnd.setHours(WORK_END, 0, 0, 0);
    const remainingToday = (todayEnd.getTime() - currentTime.getTime()) / (1000 * 60 * 60);

    if (remainingHours <= remainingToday) {
      // 剩余时长能在当天完成,直接累加
      currentTime.setTime(currentTime.getTime() + remainingHours * 60 * 60 * 1000);
      remainingHours = 0;
    } else {
      // 剩余时长需要跨天,扣掉当天剩余时间后跳到下一个工作日
      remainingHours -= remainingToday;
      currentTime = getNextWorkDayStart(currentTime);
    }
  }

  return currentTime;
}

// 示例调用:比如2024-05-17 17:00累加10小时
// const testDate = new Date("2024-05-17T17:00:00");
// console.log(calculateWorkTime(testDate, 10)); // 返回2024-05-18T18:00:00

关键说明

  • 跨天逻辑修复:通过循环逐天计算剩余工作时间,彻底解决了大时长累加时的逻辑错误,不管累加多少小时都能正确顺延到工作日。
  • 节假日支持:getHolidays函数从Google表格读取节假日列表,isWorkDay函数同时判断周末和节假日,getNextWorkDayStart会自动跳过所有非工作日。
  • 使用时记得把spreadsheetId和range替换成你自己的Google表格信息,并且给脚本授权访问Google表格的权限。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 08:07:50