JavaScript实现跳过节假日的小时累加日期计算:现有脚本逻辑缺陷排查与功能扩展
解决工作时间累加的两个问题:跨天逻辑修复 + 节假日支持
咱们一步步拆解你的核心问题,重构代码来彻底解决它们:
一、先修复跨天计算的逻辑错误
你的现有脚本在处理跨天(尤其是需要跳过多个工作日)的场景时逻辑不够严谨,比如17:00累加10小时的情况:当天剩余工作时间只有1小时(17到18点),剩下的9小时需要放到下一个工作日的9点开始累加,最终应该是次日18:00。咱们改成逐天扣减剩余时长的方式,逻辑会更可靠:
- 先把当前时间调整到工作时间范围内(如果在上班前,跳到上班时间;如果在下班后,跳到下一个工作日的上班时间)
- 循环处理剩余要添加的小时数:
- 计算当天还剩多少工作时间可用
- 如果剩余时长≤当天剩余工作时间,直接累加后结束
- 如果剩余时长更多,就把剩余时长减去当天剩余时间,然后跳到下一个工作日(自动跳过周末),重复这个过程
二、添加节假日支持
要从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
相关产品推荐
相关产品推荐

