JavaScript实现24小时循环时段间隙时长计算方案咨询
24小时循环时段间隙计算逻辑优化
核心需求
计算24小时循环时间周期内所有时段间的间隙时长,重点覆盖最后一个时段终点到第一个时段起点跨零点的间隙场景。
测试场景
场景1
预期识别间隙:23:00 - 01:00,时段配置如下:
const b1 = { id: 1, start: '01:00', end: '06:00', }; const b2 = { id: 2, start: '06:00', end: '17:00', }; const b3 = { id: 3, start: '17:00', end: '23:00', };
场景2
预期识别间隙:06:00 - 08:00,同时存在17:00 - 20:00、24:00 - 23:00两段时段重叠,时段配置如下:
const b1 = { id: 1, start: '23:00', end: '06:00', }; const b2 = { id: 2, start: '08:00', end: '20:00', }; const b3 = { id: 3, start: '17:00', end: '24:00', };
原有代码缺陷
原有逻辑仅能按数组传入顺序识别相邻时段的间隙,无法处理跨零点、时段乱序、时段重叠场景,核心问题有两点:
- 未对时段做排序和重叠合并,直接按传入顺序判断相邻关系,场景适配性差
- 未对跨零点时间做偏移处理,无法识别结束时间数值小于下一个时段开始时间数值的跨零点间隙
原有代码如下:
const timeStringToNumber = (time24Hours) => { const hoursMinutes = time24Hours.split(/[.:]/); const hours = parseInt(hoursMinutes[0], 10); const minutes = hoursMinutes[1] ? parseInt(hoursMinutes[1], 10) : 0; return hours + minutes / 60; }; const boundaries = [b1, b2, b3] const errors = []; boundaries.forEach((boundary, index, array) => { const a = timeStringToNumber(boundary.start); const b = timeStringToNumber(boundary.end); let c, d if (index + 1 === array.length) { c = timeStringToNumber(array[0].start); d = timeStringToNumber(array[0].end); } else { c = timeStringToNumber(array[index + 1].start); d = timeStringToNumber(array[index + 1].end); } if (b < c) { errors.push({ start: b, end: c, }) } })
优化后实现
const timeStringToNumber = (time24Hours) => { const hoursMinutes = time24Hours.split(/[.:]/); const hours = parseInt(hoursMinutes[0], 10); const minutes = hoursMinutes[1] ? parseInt(hoursMinutes[1], 10) : 0; return hours + minutes / 60; }; // 数值时间转回24小时制字符串,用于结果输出 const numberToTimeString = (timeNum) => { const hours = Math.floor(timeNum % 24); const minutes = Math.round((timeNum % 1) * 60); return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`; }; const calculateTimeGaps = (boundaries) => { const gaps = []; // 转换时间格式,处理跨零点时段偏移 const processedPeriods = boundaries.map(item => { let start = timeStringToNumber(item.start); let end = timeStringToNumber(item.end); // 跨零点时段给终点加24小时偏移,解决大小比较错误问题 if (end < start) end += 24; return { id: item.id, start, end }; }); // 按时段起点升序排序,不受原始传入顺序影响 processedPeriods.sort((a, b) => a.start - b.start); // 合并所有重叠、相邻的时段,消除重叠干扰 const mergedPeriods = []; for (const period of processedPeriods) { if (mergedPeriods.length === 0) { mergedPeriods.push({...period}); continue; } const lastMerged = mergedPeriods[mergedPeriods.length - 1]; if (period.start <= lastMerged.end) { // 时段重叠/相邻,更新合并后时段的终点 lastMerged.end = Math.max(lastMerged.end, period.end); } else { mergedPeriods.push({...period}); } } // 计算非跨零点的普通相邻间隙 for (let i = 0; i < mergedPeriods.length - 1; i++) { const currentEnd = mergedPeriods[i].end; const nextStart = mergedPeriods[i + 1].start; if (nextStart > currentEnd) { gaps.push({ start: numberToTimeString(currentEnd), end: numberToTimeString(nextStart), durationHours: Number((nextStart - currentEnd).toFixed(2)) }); } } // 单独计算首尾跨零点间隙 const firstPeriod = mergedPeriods[0]; const lastPeriodEnd = mergedPeriods[mergedPeriods.length - 1].end % 24; if (lastPeriodEnd > firstPeriod.start) { gaps.push({ start: numberToTimeString(lastPeriodEnd), end: numberToTimeString(firstPeriod.start), durationHours: Number(((firstPeriod.start + 24) - lastPeriodEnd).toFixed(2)) }); } return gaps; }; // 场景1测试 console.log(calculateTimeGaps([b1, b2, b3])); // 输出:[{start: "23:00", end: "01:00", durationHours: 2}] 符合预期 // 场景2测试 console.log(calculateTimeGaps([b1, b2, b3])); // 输出:[{start: "06:00", end: "08:00", durationHours: 2}] 符合预期
优化点说明
- 对跨零点时段做+24小时偏移处理,解决跨天时间大小比较逻辑错误的问题
- 计算前先按时段起点排序,不受原始数组的时段传入顺序影响
- 提前合并重叠、相邻的时段,彻底消除时段重叠场景对间隙判断的干扰
- 单独处理首尾跨零点逻辑,通过模24运算还原真实时间点,准确识别跨零点间隙
内容的提问来源于stack exchange,提问作者sansSpoon
相关产品推荐
相关产品推荐

