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

如何用JS基于固定工作时段计算指定工作小时后的对应日期时间

实现方案说明

原有代码问题分析

原有代码存在三处核心逻辑缺陷,是导致结果不准确的主要原因:

  • 阈值逻辑无业务依据:代码中timeRemaining >= 21的跳步判断没有对应业务规则支撑,跳转逻辑混乱,既不符合周末跳过的要求,也会出现时长多算、漏算的问题
  • 时长累加逻辑错误:每次直接累加当日剩余全部工作时长,没有判断剩余待填充的时长是否小于当日剩余工作时长,最终统计的时长必然会超过目标的31.5小时
  • 缺少边界时间校准逻辑:未处理起始时间落在非工作时段(凌晨、下班后、周末)的场景,计算的时间基准本身就存在偏差

原生JS实现方案(无需逐单位迭代)

直接按工作日维度计算,最多循环次数等于需要跨的天数,性能远高于逐分钟/逐秒迭代:

// 工作规则配置,可按需调整
const WORK_RULES = {
  workStart: [6, 0], // 工作开始时间 [时, 分]
  workEnd: [16, 30], // 工作结束时间 [时, 分]
  // 单日总工作时长(毫秒)
  get workDayTotalMs() {
    const endMs = this.workEnd[0] * 3600000 + this.workEnd[1] * 60000;
    const startMs = this.workStart[0] * 3600000 + this.workStart[1] * 60000;
    return endMs - startMs;
  }
};

/**
 * 为指定时间添加指定时长的工作时间
 * @param {Date} startDate 起始时间
 * @param {Number} workHours 需要添加的工作小时数
 * @returns {Date} 计算后的最终时间
 */
function addWorkHours(startDate, workHours) {
  let currentTime = new Date(startDate);
  let remainMs = workHours * 3600000;

  // 工具方法:跳转至下一个工作日的起始时间
  const jumpToNextWorkDay = (date) => {
    do {
      date.setDate(date.getDate() + 1);
    } while (date.getDay() === 0 || date.getDay() === 6);
    date.setHours(...WORK_RULES.workStart, 0, 0);
    return date;
  };

  // 第一步:校准起始时间到合法的工作时间点
  while (true) {
    const weekDay = currentTime.getDay();
    // 周末直接跳转到下一个工作日
    if (weekDay === 0 || weekDay === 6) {
      currentTime = jumpToNextWorkDay(currentTime);
      continue;
    }
    const dayStart = new Date(currentTime);
    dayStart.setHours(...WORK_RULES.workStart, 0, 0);
    const dayEnd = new Date(currentTime);
    dayEnd.setHours(...WORK_RULES.workEnd, 0, 0);
    // 早于当日工作开始时间,校准为当日工作开始时间
    if (currentTime < dayStart) {
      currentTime = dayStart;
      break;
    }
    // 晚于当日工作结束时间,跳转到下一个工作日开始
    if (currentTime > dayEnd) {
      currentTime = jumpToNextWorkDay(currentTime);
      continue;
    }
    // 已经落在工作时段内,直接结束校准
    break;
  }

  // 第二步:逐工作日扣除待计算时长
  while (remainMs > 0) {
    const dayEnd = new Date(currentTime);
    dayEnd.setHours(...WORK_RULES.workEnd, 0, 0);
    const dayRemainMs = dayEnd - currentTime;
    // 剩余时长可在当日用完,直接计算最终时间
    if (remainMs <= dayRemainMs) {
      currentTime.setTime(currentTime.getTime() + remainMs);
      break;
    }
    // 当日时长不够,扣减后跳转到下一个工作日
    remainMs -= dayRemainMs;
    currentTime = jumpToNextWorkDay(currentTime);
  }

  return currentTime;
}

// 测试示例
const testStart = new Date('2021-08-27T12:00:00');
const result = addWorkHours(testStart, 31.5);
console.log(result);

第三方库可选方案

如果需要支持节假日配置、多时区等复杂场景,可以直接使用成熟的第三方库:

  • moment-business-time:基于moment.js的扩展,支持自定义工作时段、节假日,可直接调用addWorkingTime方法实现需求
  • date-fns-business-hours:基于date-fns的轻量化扩展,无额外依赖,适配原生日期对象的使用习惯

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 10:00:01