Search code examples
javascriptdatetimemomentjsprojectiondate-range

Split date range overlaps into chunks (javascript)


I came up with a concept, but am having trouble converting it into code.

Here's a picture to better help explain my idea: da picture

Can't tell by the picture, but there can be gaps between dates as well.

Not to make it an XY-problem, here's why I need to do this. I have array of date ranges and bonuses and I want to create an array of non overlapping dates with sum of bonuses.

I'm trying to split overlaps into chucks that do not overlap anymore. Came across a package called moment-range. Is there perhaps a name for this what I'm trying to succeed? "Projecting date ranges onto linear ...something"

Final code below

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},
]

_.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(function(a, b) {
  return a-b
})

let ranges = []
for(let i=1; i<dates.length; i++) {
  ranges.push({
    start: dates[i-1],
    end: dates[i],
    range: moment.range(dates[i-1], dates[i])
  })
}

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))

Solution

  • var dates = [];
    bonuses.forEach(item => {
        dates.push(item.start);
        dates.push(item.end);
    });
    dates.sort();
    var ranges = [];
    for(var i=1;i<dates.length;i++){
        ranges.push({
            start: dates[i-1], 
            end: dates[i]
        });
    }
    console.log(ranges);