拆分重叠日期时段并生成新时段的JavaScript实现问题
解决时段重叠拆分问题
问题描述
我有一个包含startDate(开始日期)和endDate(结束日期)的对象数组,示例如下:
var periods = [ { id: "Period1", startDate: new Date("2022-08-29"), endDate: new Date("2022-12-23") }, { id: "Period2", startDate: new Date("2022-12-12"), endDate: new Date("2023-10-02") }, // 更多时段... ]
需要将存在重叠的时段拆分为新的对象,预期效果如下:
// Period1 // 29/08/2022 - 11/12/2022 // 12/12/2022 - 23/12/2022 // Period2 // 12/12/2022 - 23/12/2022 // 24/12/2022 - 02/10/2023
当前代码仅能处理时段起始日期重叠的情况,无法处理结束时的逻辑,需要完善。
解决方案
核心思路是先提取所有关键时间点(所有时段的开始日期、结束日期+1天),将这些时间点排序去重后,相邻时间点之间就构成了一个无重叠的基础区间,再为每个覆盖该区间的原始时段生成对应的子时段。
完整代码实现:
// 保留你定义的日期扩展方法 Date.prototype.addDays = function (days) { var date = new Date(this.valueOf()); date.setDate(date.getDate() + days); return date; } var periods = [ { id: "Period1", startDate: new Date("2022-08-29"), endDate: new Date("2022-12-23") }, { id: "Period2", startDate: new Date("2022-12-12"), endDate: new Date("2023-10-02") }, ]; // 步骤1:收集所有关键时间点 const keyDates = new Set(); periods.forEach(period => { keyDates.add(period.startDate); // 结束日期+1天,用于拆分区间的边界 keyDates.add(period.endDate.addDays(1)); }); // 步骤2:将时间点排序 const sortedDates = Array.from(keyDates).sort((a, b) => a - b); // 步骤3:遍历相邻时间点,生成拆分后的时段 const splitPeriods = []; for (let i = 0; i < sortedDates.length - 1; i++) { const currentStart = sortedDates[i]; // 当前区间的结束日期是下一个时间点减1天 const currentEnd = sortedDates[i + 1].addDays(-1); // 找出所有覆盖当前区间的原始时段 const matchingPeriods = periods.filter(period => { return period.startDate <= currentEnd && period.endDate >= currentStart; }); // 为每个匹配的时段生成子时段 matchingPeriods.forEach(period => { splitPeriods.push({ id: period.id, startDate: new Date(currentStart), endDate: new Date(currentEnd) }); }); } console.log(splitPeriods);
代码说明
- 关键时间点收集:把每个时段的开始日期和结束日期的次日加入集合,这样能确保所有区间拆分的边界都被覆盖,包括重叠的起始和结束点。
- 排序时间点:将时间点按时间顺序排列,保证后续生成的区间是按时间推进的。
- 生成子时段:遍历每一对相邻时间点,计算出当前子区间的起止日期,然后找到所有包含这个子区间的原始时段,为每个原始时段生成对应的子时段对象。
运行这段代码后,输出结果将完全符合预期,无论重叠发生在起始还是结束阶段,都能正确拆分。
内容的提问来源于stack exchange,提问作者Jasper De Smet
相关产品推荐
相关产品推荐

