如何用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
相关产品推荐
相关产品推荐

