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

如何用Day.js实现带工作日逻辑的日期列表添加与时长计算?

基于Day.js计算跨工作日预约结束时间并插入工作日列表

核心需求

  • 使用Day.js库处理时间计算
  • 每日固定工作时段为10:00至18:00
  • 从指定预约起始日期叠加时长,若当日工作时间不足,剩余时长顺延至下一个工作日(需跳过所有周日)
  • 将预约起始日期和计算得到的结束日期插入到对应工作日的startDate与endDate之间

示例数据

请求参数

let duration = "20:00:00" // 总时长20小时
let appointmentDate = '2023-01-21T16:00:00-06:00' // 预约起始时间

原始工作日列表(已修正示例中的日期格式错误)

[
  { startDate: '2023-01-21T10:00:00-06:00'}, // 周六
  { endDate: '2023-01-21T18:00:00-06:00'},
  
  { startDate: '2023-01-23T10:00:00-06:00'}, // 周一
  { endDate: '2023-01-23T18:00:00-06:00'},
  
  { startDate: '2023-01-24T10:00:00-06:00'}, // 周二
  { endDate: '2023-01-24T18:00:00-06:00'},
  
  { startDate: '2023-01-25T10:00:00-06:00'}, // 周三
  { endDate: '2023-01-25T18:00:00-06:00'},
  
  { startDate: '2023-01-26T10:00:00-06:00'}, // 周四
  { endDate: '2023-01-26T18:00:00-06:00'},
]

期望最终结果

[
  { startDate: '2023-01-21T10:00:00-06:00'}, // 周六
  { appointmentDate: '2023-01-21T16:00:00-06:00'}, // 预约起始时间
  { endDate: '2023-01-21T18:00:00-06:00'},
  
  { startDate: '2023-01-23T10:00:00-06:00'}, // 周一
  { endDate: '2023-01-23T18:00:00-06:00'},
  
  { startDate: '2023-01-24T10:00:00-06:00'}, // 周二
  { endDate: '2023-01-24T18:00:00-06:00'},
  
  { startDate: '2023-01-25T10:00:00-06:00'}, // 周三
  { appointmentDate: '2023-01-25T12:00:00-06:00'}, // 预约结束时间(叠加20小时后)
  { endDate: '2023-01-25T18:00:00-06:00'},
  
  { startDate: '2023-01-26T10:00:00-06:00'}, // 周四
  { endDate: '2023-01-26T18:00:00-06:00'},
]

实现方案与代码示例

核心逻辑

  1. 计算结束时间:逐天扣除剩余时长,遇到周日直接跳过,直到时长耗尽
  2. 插入工作日列表:遍历列表,将预约时间插入对应日期的startDate与endDate之间

完整代码

// 引入Day.js及所需插件
const dayjs = require('dayjs');
require('dayjs/plugin/duration');
require('dayjs/plugin/utc');
dayjs.extend(require('dayjs/plugin/duration'));
dayjs.extend(require('dayjs/plugin/utc'));

// 计算预约结束时间
function calculateAppointmentEnd(startDateStr, durationStr) {
  const WORK_START = 10;
  const WORK_END = 18;
  const WORK_MINUTES_PER_DAY = (WORK_END - WORK_START) * 60;

  let remainingDuration = dayjs.duration(durationStr);
  let currentTime = dayjs(startDateStr);

  while (remainingDuration.asMinutes() > 0) {
    // 生成当日工作时段的起止时间
    const dayStart = currentTime.hour(WORK_START).minute(0).second(0);
    const dayEnd = currentTime.hour(WORK_END).minute(0).second(0);

    let availableMinutes;
    if (currentTime.isBefore(dayStart)) {
      // 当前时间早于工作开始,当日可用时长为全天工作时间
      availableMinutes = WORK_MINUTES_PER_DAY;
      currentTime = dayStart;
    } else if (currentTime.isAfter(dayEnd)) {
      // 当前时间晚于工作结束,直接跳转到下一个工作日
      currentTime = getNextWorkDay(currentTime.add(1, 'day'));
      continue;
    } else {
      // 计算当日剩余可用时长
      availableMinutes = dayEnd.diff(currentTime, 'minute');
    }

    if (remainingDuration.asMinutes() <= availableMinutes) {
      // 剩余时长可在当日完成,直接叠加
      currentTime = currentTime.add(remainingDuration);
      remainingDuration = dayjs.duration(0);
    } else {
      // 剩余时长超过当日可用,扣减后跳转下一个工作日
      remainingDuration = remainingDuration.subtract(availableMinutes, 'minute');
      currentTime = getNextWorkDay(currentTime.add(1, 'day'));
    }
  }

  return currentTime.format('YYYY-MM-DDTHH:mm:ssZ');
}

// 获取下一个工作日(跳过周日)
function getNextWorkDay(date) {
  let nextDay = dayjs(date);
  // Day.js中周日为0,周六为6
  while (nextDay.day() === 0) {
    nextDay = nextDay.add(1, 'day');
  }
  return nextDay;
}

// 将预约时间插入工作日列表
function insertAppointmentIntoWorkDays(workDays, startApptStr, endApptStr) {
  const startApptDate = dayjs(startApptStr);
  const endApptDate = dayjs(endApptStr);
  const result = [];

  workDays.forEach(item => {
    result.push(item);
    // 仅在遇到startDate时检查是否需要插入预约时间
    if ('startDate' in item) {
      const currentDay = dayjs(item.startDate).format('YYYY-MM-DD');
      // 插入预约起始时间
      if (currentDay === startApptDate.format('YYYY-MM-DD')) {
        result.push({ appointmentDate: startApptStr });
      }
      // 插入预约结束时间
      if (currentDay === endApptDate.format('YYYY-MM-DD')) {
        result.push({ appointmentDate: endApptStr });
      }
    }
  });

  return result;
}

// 测试示例
const duration = "20:00:00";
const appointmentDate = '2023-01-21T16:00:00-06:00';

// 计算结束时间
const endAppointmentDate = calculateAppointmentEnd(appointmentDate, duration);
// 插入到工作日列表
const originalWorkDays = [
  { startDate: '2023-01-21T10:00:00-06:00'},
  { endDate: '2023-01-21T18:00:00-06:00'},
  { startDate: '2023-01-23T10:00:00-06:00'},
  { endDate: '2023-01-23T18:00:00-06:00'},
  { startDate: '2023-01-24T10:00:00-06:00'},
  { endDate: '2023-01-24T18:00:00-06:00'},
  { startDate: '2023-01-25T10:00:00-06:00'},
  { endDate: '2023-01-25T18:00:00-06:00'},
  { startDate: '2023-01-26T10:00:00-06:00'},
  { endDate: '2023-01-26T18:00:00-06:00'},
];
const finalWorkDays = insertAppointmentIntoWorkDays(originalWorkDays, appointmentDate, endAppointmentDate);

console.log('预约结束时间:', endAppointmentDate);
console.log('最终工作日列表:', finalWorkDays);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 06:20:53