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

如何用JavaScript将重叠日期范围拆分为无重叠区块?

解答:重叠日期区间的奖金聚合实现

Hey there! 先给你明确一下:你正在做的这个操作,专业上可以叫做重叠区间聚合(Overlapping Interval Aggregation),或者更具体点,是将连续/重叠的日期区间**离散化(Discretization)**为无重叠的子区间,并计算每个子区间的叠加值(这里就是奖金总和)。

需求回顾

你拥有一组包含日期范围与奖金的数组,目标是生成无重叠的日期范围数组,每个区间对应所有覆盖它的原区间的奖金总和,同时还要处理日期之间可能存在的间隔。

实现思路拆解

你的代码思路非常清晰,核心逻辑可以拆成这几步:

  • 提取所有原区间的起始和结束日期,排序后得到所有关键时间节点
  • 用相邻的时间节点生成无重叠的子区间(包括日期间隔的部分)
  • 遍历每个子区间,检查哪些原区间与它相交,累加对应的奖金值

格式化后的完整代码

const _ = require('lodash');
const Moment = require('moment');
const MomentRange = require('moment-range');
const moment = MomentRange.extendMoment(Moment);

let bonuses = [
  {start: new Date('Jan 15, 2018 23:00:00 GMT+0200'), end: new Date('Jan 18, 2018 23:59:59 GMT+0200'), bonus: 30, preSale: true},
  {start: new Date('Jan 17, 2018 00:00:00 GMT+0200'), end: new Date('Jan 29, 2018 13:00:00 GMT+0200'), bonus: 25, preSale: true},
  {start: new Date('Feb 12, 2018 00:00:00 GMT+0200'), end: new Date('Feb 18, 2018 23:59:59 GMT+0200'), bonus: 20, preSale: false},
  {start: new Date('Feb 19, 2018 00:00:00 GMT+0200'), end: new Date('Feb 27, 2018 23:59:59 GMT+0200'), bonus: 15, preSale: false},
  {start: new Date('Feb 26, 2018 00:00:00 GMT+0200'), end: new Date('Mar 4, 2018 23:59:59 GMT+0200'), bonus: 10, preSale: false},
  {start: new Date('Mar 5, 2018 00:00:00 GMT+0200'), end: new Date('Mar 11, 2018 23:59:59 GMT+0200'), bonus: 5, preSale: false},
];

// 为每个奖金区间生成moment-range对象
_.map(bonuses, o => o.range = moment.range(o.start, o.end));

// 收集所有日期点并排序
let dates = [];
_.each(bonuses, o => {
  dates.push(o.start);
  dates.push(o.end);
});
dates.sort((a, b) => a - b);

// 生成无重叠的子区间(跳过空区间)
let ranges = [];
for(let i = 1; i < dates.length; i++) {
  const start = dates[i-1];
  const end = dates[i];
  // 避免生成起始/结束时间完全相同的空区间
  if (start.getTime() !== end.getTime()) {
    ranges.push({
      start,
      end,
      range: moment.range(start, end)
    });
  }
}

// 计算每个子区间的总奖金
for (let range of ranges) {
  range.bonus = 0;
  for (let bonus of bonuses) {
    if (range.range.intersect(bonus.range)) {
      range.bonus += bonus.bonus;
    }
  }
}

// 输出结果
_.each(ranges, r => console.log(r.start, ' - ', r.end, ' => ', r.bonus));

小优化说明

我在生成子区间时加了一个判断,跳过起始和结束日期完全相同的情况,避免生成没有实际时长的空区间,让结果更严谨。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:14:22