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

如何计算排除周日及节假日的空闲时间?含特殊场景处理

计算两个Datetime间空闲时间的优化方案

需要实现一个计算两个UTC格式datetime之间**空闲时间(idleTime)**的方法,需解决两个特殊场景:

  • 若开始日期是周日或节假日:周日剩余时长 + 次日上午(截至6:30 AM UTC)不计入空闲时间
  • 若结束日期是周日或节假日:当日时长不计入空闲时间

示例说明

startTime = "2024-05-05T12:00:00Z";(UTC格式,当日为周日)
endTime = "2024-05-06T13:00:00Z";(UTC格式)
输出:7小时
计算逻辑:总时差25小时 - 周日需排除的18小时 - 节假日时长(此处为0)= 7小时

你当前的代码

function calculateIdleTimeExcludingSundaysAndHolidays(startTime, endTime) {
var startUtc = new Date(startTime).getTime();
var endUtc = new Date(endTime).getTime();
var totalIdleTime = 0;

    for (var currentTime = startUtc; currentTime < endUtc; currentTime += 60 * 1000) { // 按分钟递增
        var currentDateTime = new Date(currentTime);
        if (currentDateTime.getUTCDay() !== 0 /* 不是周日 */ ) {
            totalIdleTime += 1; // 累计1分钟
        }
    }
    
    return totalIdleTime;

}


// 示例调用
var startTime = "2024-05-13T12:00:00Z"; // UTC格式
var endTime = "2024-05-15T13:00:00Z";   // UTC格式

var idleTimeInMinutes = calculateIdleTimeExcludingSundaysAndHolidays(startTime, endTime);
console.log("空闲时间(分钟,排除周日和节假日):", idleTimeInMinutes);

现有代码的问题

  • 仅简单排除了周日的所有分钟,未处理开始日为周日/节假日时需额外排除次日0-6:30的规则
  • 没有纳入节假日的判断逻辑
  • 逐分钟循环的方式性能低下,时间跨度大时会明显卡顿

优化后的解决方案

首先需要维护一个节假日列表(根据业务需求更新),然后重构计算逻辑:

// 示例节假日列表(UTC格式,仅保留年月日部分)
const HOLIDAYS = new Set([
  "2024-01-01", // 元旦
  "2024-12-25"  // 圣诞节
]);

function calculateIdleTime(startTime, endTime) {
  const start = new Date(startTime);
  const end = new Date(endTime);
  const ONE_MINUTE = 60 * 1000;
  const ONE_HOUR = 60 * ONE_MINUTE;
  
  // 判断当前日期是否为周日或节假日
  function isExcludedDate(date) {
    const utcDateStr = date.toISOString().split('T')[0];
    return date.getUTCDay() === 0 || HOLIDAYS.has(utcDateStr);
  }

  // 获取次日UTC 6:30的时间戳
  function getNextDay630Timestamp(date) {
    const nextDay = new Date(date.toISOString().split('T')[0]);
    nextDay.setDate(nextDay.getDate() + 1);
    nextDay.setUTCHours(6, 30, 0, 0);
    return nextDay.getTime();
  }

  let totalIdleMinutes = 0;
  let currentTimestamp = start.getTime();
  const endTimestamp = end.getTime();
  const startDateStr = start.toISOString().split('T')[0];
  const endDateStr = end.toISOString().split('T')[0];

  while (currentTimestamp < endTimestamp) {
    const currentDate = new Date(currentTimestamp);
    const currentDateStr = currentDate.toISOString().split('T')[0];
    const dayEndTimestamp = new Date(currentDateStr).getTime() + 24 * ONE_HOUR;
    const actualDayEnd = Math.min(dayEndTimestamp, endTimestamp);

    // 处理结束日为排除日期的情况:直接跳过当日所有时间
    if (currentDateStr === endDateStr && isExcludedDate(end)) {
      break;
    }

    // 处理当前日期为排除日期的情况
    if (isExcludedDate(currentDate)) {
      if (currentDateStr === startDateStr) {
        // 开始日是排除日期:跳转到次日UTC 6:30
        const skipTo = getNextDay630Timestamp(currentDate);
        currentTimestamp = skipTo > endTimestamp ? endTimestamp : skipTo;
      } else {
        // 非开始日的排除日期:直接跳转到次日0点
        currentTimestamp = dayEndTimestamp > endTimestamp ? endTimestamp : dayEndTimestamp;
      }
      continue;
    }

    // 计算当日可计入空闲时间的分钟数
    totalIdleMinutes += (actualDayEnd - currentTimestamp) / ONE_MINUTE;
    currentTimestamp = actualDayEnd;
  }

  return Math.floor(totalIdleMinutes);
}

// 测试示例
const testStart = "2024-05-05T12:00:00Z"; // 周日
const testEnd = "2024-05-06T13:00:00Z";
const idleMinutes = calculateIdleTime(testStart, testEnd);
console.log(`空闲时间:${idleMinutes / 60}小时`); // 输出:7小时

逻辑说明

  1. 统一判断规则:用isExcludedDate函数统一处理周日和节假日的判断,方便后续维护
  2. 特殊场景处理:
    • 如果开始日是周日/节假日,直接跳转到次日UTC 6:30,跳过周日剩余时间和次日凌晨时段
    • 如果结束日是周日/节假日,直接终止循环,不计入当日任何时间
  3. 性能优化:不再逐分钟遍历,而是按天或指定时段跳转,大幅提升计算效率
  4. 扩展性:节假日列表可根据业务需求随时添加或修改

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 20:43:16