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

如何用JavaScript/Moment计算排除非工作时间的DateTime时间差?

当然可以实现!我来给你分享几种靠谱的方案,不管是用原生JavaScript还是Moment.js(包括它的衍生工具库)都能轻松搞定这个需求——只计算每日9:00-18:00的工作时长,自动排除非工作时间。

方案1:原生JavaScript实现

如果你不想引入额外的库,纯原生JS就能完成这个计算。核心思路是把时间拆成三部分:开始日期当天剩余的工作时长、结束日期当天的工作时长,以及中间完整工作日的总时长,最后把这三部分加起来就是最终的工作时间差。

下面是完整的代码实现:

function calculateWorkTimeDiff(startDate, endDate) {
  // 工作时间配置:每天9点到18点,每天工作9小时(32400000毫秒)
  const workStartHour = 9;
  const workEndHour = 18;
  const workDayDuration = (workEndHour - workStartHour) * 60 * 60 * 1000;

  // 复制日期对象,避免修改原数据
  const start = new Date(startDate);
  const end = new Date(endDate);

  // 如果开始时间晚于结束时间,返回0
  if (start >= end) return 0;

  // 处理开始时间:如果在工作时间之前,调到当天9点;如果在工作时间之后,调到第二天9点
  const startWorkDay = new Date(start.getFullYear(), start.getMonth(), start.getDate(), workStartHour);
  const startWorkEnd = new Date(start.getFullYear(), start.getMonth(), start.getDate(), workEndHour);
  let startRemaining = 0;
  if (start < startWorkDay) {
    start.setTime(startWorkDay.getTime());
  } else if (start > startWorkEnd) {
    start.setTime(startWorkDay.getTime() + 24 * 60 * 60 * 1000);
  } else {
    startRemaining = startWorkEnd.getTime() - start.getTime();
  }

  // 处理结束时间:如果在工作时间之前,调到当天9点;如果在工作时间之后,调到当天18点
  const endWorkDay = new Date(end.getFullYear(), end.getMonth(), end.getDate(), workStartHour);
  const endWorkEnd = new Date(end.getFullYear(), end.getMonth(), end.getDate(), workEndHour);
  let endDuration = 0;
  if (end < endWorkDay) {
    end.setTime(endWorkDay.getTime());
  } else if (end > endWorkEnd) {
    end.setTime(endWorkEnd.getTime());
  } else {
    endDuration = end.getTime() - endWorkDay.getTime();
  }

  // 计算中间完整的工作日数量
  const oneDay = 24 * 60 * 60 * 1000;
  let fullWorkDays = 0;
  const current = new Date(start);
  while (current < end) {
    const nextDay = new Date(current.getTime() + oneDay);
    if (nextDay <= end) {
      // 若需排除周末,可添加判断:current.getDay() !== 0 && current.getDay() !== 6(0=周日,6=周六)
      fullWorkDays++;
    }
    current.setTime(nextDay.getTime());
  }

  // 如果开始日期和结束日期是同一天,直接计算当天的工作时长差
  if (start.toDateString() === end.toDateString()) {
    return Math.max(0, end.getTime() - start.getTime());
  }

  // 总工作时长 = 开始当天剩余 + 结束当天时长 + 完整工作日总时长
  const totalDuration = startRemaining + endDuration + (fullWorkDays - 1) * workDayDuration;
  return Math.max(0, totalDuration);
}
方案2:使用Moment.js实现

如果你的项目已经在使用Moment.js,那用它来实现会更简洁,代码可读性也更高。同样遵循原生的思路,只是用Moment的API来处理日期时间:

// 确保已经引入Moment.js
function calculateWorkTimeDiffWithMoment(startMoment, endMoment) {
  const workStartHour = 9;
  const workEndHour = 18;
  const workDayDuration = (workEndHour - workStartHour) * 60 * 60 * 1000;

  let start = startMoment.clone();
  let end = endMoment.clone();

  if (start.isAfter(end)) return 0;

  // 调整开始时间到工作时间范围内
  const startWorkDay = start.clone().hour(workStartHour).minute(0).second(0);
  const startWorkEnd = start.clone().hour(workEndHour).minute(0).second(0);
  let startRemaining = 0;
  if (start.isBefore(startWorkDay)) {
    start = startWorkDay;
  } else if (start.isAfter(startWorkEnd)) {
    start = startWorkDay.clone().add(1, 'day');
  } else {
    startRemaining = startWorkEnd.diff(start);
  }

  // 调整结束时间到工作时间范围内
  const endWorkDay = end.clone().hour(workStartHour).minute(0).second(0);
  const endWorkEnd = end.clone().hour(workEndHour).minute(0).second(0);
  let endDuration = 0;
  if (end.isBefore(endWorkDay)) {
    end = endWorkDay;
  } else if (end.isAfter(endWorkEnd)) {
    end = endWorkEnd;
  } else {
    endDuration = end.diff(endWorkDay);
  }

  // 计算中间完整工作日数量
  let fullWorkDays = 0;
  const current = start.clone();
  while (current.isBefore(end)) {
    const nextDay = current.clone().add(1, 'day');
    if (nextDay.isBefore(end) || nextDay.isSame(end)) {
      // 若需排除周末,可添加判断:current.day() !== 0 && current.day() !== 6
      fullWorkDays++;
    }
    current.add(1, 'day');
  }

  if (start.isSame(end, 'day')) {
    return Math.max(0, end.diff(start));
  }

  const totalDuration = startRemaining + endDuration + (fullWorkDays - 1) * workDayDuration;
  return Math.max(0, totalDuration);
}

更省心的第三方库方案

如果你想少写代码,可以用专门处理工作时间的moment-business-hours库,它支持直接配置工作时段,一键计算工作时长差:

// 先安装依赖:npm install moment-business-hours
const moment = require('moment');
require('moment-business-hours');

// 配置工作时间:周一到周五,9:00-18:00
moment.updateLocale('en', {
  workinghours: {
    0: null, // 周日不工作
    1: ['09:00', '18:00'],
    2: ['09:00', '18:00'],
    3: ['09:00', '18:00'],
    4: ['09:00', '18:00'],
    5: ['09:00', '18:00'],
    6: null // 周六不工作
  }
});

// 计算工作时间差(毫秒)
const start = moment('2024-02-19 19:00');
const end = moment('2024-02-20 11:00');
const workDiff = end.diff(start, 'businesshours');
console.log(workDiff); // 输出7200000,也就是2小时
验证你的示例

用你给出的测试案例验证:

  • 开始时间:2月19日19:00(已过当天工作结束时间,自动调整到2月20日9:00)
  • 结束时间:2月20日11:00(在工作时间内)

使用上面任意一种方案计算,结果都是2小时(7200000毫秒),完全符合你的预期。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 09:16:41