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

JavaScript优化班次时间扣除缺勤时段逻辑及修复结果错误求助

JavaScript优化班次时间扣除缺勤时段逻辑及修复结果错误求助

看起来你目前面临两个核心问题:

  • 当前代码的逻辑有漏洞,漏掉了完全没有被缺勤影响的班次(比如示例里的19:00-20:00),这就是为什么预期结果里有这个时段,但你的输出里没有;
  • 想简化当前的嵌套循环实现,但一直没找到合适的方式。

先帮你拆解现有代码的问题:你的代码只处理了和缺勤有交集的班次,完全没被缺勤覆盖的班次根本没被添加到available_times数组里。而且嵌套循环的逻辑是从缺勤出发去匹配班次,很容易遗漏未被影响的部分。


修复+优化后的实现方案

我推荐换一种思路:先把所有班次作为初始可用时间,然后用每个缺勤时段去「切割」当前的可用时间数组。这种方式逻辑更线性,不容易遗漏,也更易读。

完整代码实现

// 工具函数:将时间字符串转成时间戳(基于1970-01-01的毫秒数)
const toTimestamp = (timeStr) => Date.parse(`1970/01/01 ${timeStr}`);

// 原始数据
const arranged_shifts = [
  { start_time: '08:00', finish_time: '10:00' },
  { start_time: '10:30', finish_time: '16:00' },
  { start_time: '17:00', finish_time: '18:00' },
  { start_time: '19:00', finish_time: '20:00' }
];
const absences = [
  { start_time: '09:00', finish_time: '09:30' },
  { start_time: '11:00', finish_time: '12:30' },
  { start_time: '17:30', finish_time: '18:00' }
];

// 初始可用时间:复制所有班次,确保未被影响的班次不会被遗漏
let availableTimes = [...arranged_shifts];

// 遍历每个缺勤,切割当前的可用时间数组
absences.forEach(absence => {
  const absStart = toTimestamp(absence.start_time);
  const absEnd = toTimestamp(absence.finish_time);
  const newAvailable = [];

  availableTimes.forEach(shift => {
    const shiftStart = toTimestamp(shift.start_time);
    const shiftEnd = toTimestamp(shift.finish_time);

    // 情况1:缺勤和当前班次完全不重叠,直接保留该班次
    if (absEnd <= shiftStart || absStart >= shiftEnd) {
      newAvailable.push(shift);
      return;
    }

    // 情况2:缺勤在班次中间,把班次切成两段
    if (absStart > shiftStart && absEnd < shiftEnd) {
      newAvailable.push({
        start_time: shift.start_time,
        finish_time: absence.start_time
      });
      newAvailable.push({
        start_time: absence.finish_time,
        finish_time: shift.finish_time
      });
      return;
    }

    // 情况3:缺勤从班次开头覆盖到中间,只保留后半段
    if (absStart <= shiftStart && absEnd < shiftEnd) {
      newAvailable.push({
        start_time: absence.finish_time,
        finish_time: shift.finish_time
      });
      return;
    }

    // 情况4:缺勤从中间覆盖到班次结尾,只保留前半段
    if (absStart > shiftStart && absEnd >= shiftEnd) {
      newAvailable.push({
        start_time: shift.start_time,
        finish_time: absence.start_time
      });
      return;
    }

    // 情况5:缺勤完全覆盖整个班次,直接丢弃该班次(无需操作)
  });

  // 更新可用时间为切割后的结果
  availableTimes = newAvailable;
});

console.log(availableTimes);

代码核心逻辑说明

  1. 时间统一转换:用toTimestamp把HH:MM字符串转成时间戳,用数值比较替代字符串比较,逻辑更严谨;
  2. 初始值兜底:一开始就把所有班次加入可用时间,彻底解决了“未被影响的班次被遗漏”的问题;
  3. 线性切割逻辑:每个缺勤只处理当前的可用时间数组,每一步的结果都基于上一步的状态,避免了嵌套循环的混乱;
  4. 覆盖所有重叠场景:把缺勤和班次的重叠情况拆分成5种,每种场景单独处理,逻辑清晰无遗漏。

验证结果

运行这段代码后,输出会和你的预期完全一致:

[
  { start_time: '08:00', finish_time: '09:00' },
  { start_time: '09:30', finish_time: '10:00' },
  { start_time: '10:30', finish_time: '11:00' },
  { start_time: '12:30', finish_time: '16:00' },
  { start_time: '17:00', finish_time: '17:30' },
  { start_time: '19:00', finish_time: '20:00' }
]

这种实现方式不仅解决了你的bug,也比原来的嵌套循环更易读、更易维护~

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.07 12:33:09