asissuthar
asissuthar

Reputation: 2256

How to split time slots into day wise slots using javascript?

Any help will be really appreciated! I'm trying from 4 days but still not found any solution. Please help me. Guide me for library or methods i can use.

Here is the given input. array of session start and end. I want to calculate daily usage period. So i want to split each slot in their own day.

var slots = [
  { start: dayjs('2019-01-01 21:00:00'), end: dayjs('2019-01-01 23:00:00') },
  { start: dayjs('2019-01-01 22:00:00'), end: dayjs('2019-01-02 01:00:00') },
  { start: dayjs('2019-01-01 22:00:00'), end: dayjs('2019-01-02 04:00:00') },
  { start: dayjs('2019-01-01 21:00:00'), end: dayjs('2019-01-02 00:00:00') },
  { start: dayjs('2019-01-02 00:00:00'), end: dayjs('2019-01-02 04:00:00') },
  { start: dayjs('2019-01-02 01:00:00'), end: dayjs('2019-01-02 04:00:00') },
  { start: dayjs('2019-01-31 01:00:00'), end: dayjs('2019-02-01 04:00:00') },
]
var output = []

slots.forEach((slot) => {
  // filter same slots with same day
  if (slot.start.isSame(slot.end, 'day')) {
    output.push(slot)
  } else {
  // what to do here? how to split end time
  }
})
console.log(output)

I need this kind of output

[
  { start: '2019-01-01 21:00:00', end: '2019-01-01 23:00:00' },
  { start: '2019-01-01 22:00:00', end: '2019-01-01 23:59:59' },
  { start: '2019-01-02 00:00:00', end: '2019-01-02 01:00:00' },
  { start: '2019-01-01 22:00:00', end: '2019-01-01 23:59:59' },
  { start: '2019-01-02 00:00:00', end: '2019-01-02 04:00:00' },
  { start: '2019-01-01 21:00:00', end: '2019-01-01 23:59:59' },
  { start: '2019-01-02 00:00:00', end: '2019-01-02 00:00:00' },
  { start: '2019-01-02 00:00:00', end: '2019-01-02 04:00:00' },
  { start: '2019-01-02 01:00:00', end: '2019-01-02 04:00:00' },
  { start: '2019-01-31 01:00:00', end: '2019-01-31 23:59:59' },
  { start: '2019-02-01 00:00:00', end: '2019-02-01 04:00:00' },
]

Upvotes: 0

Views: 1448

Answers (3)

Drew Reese
Drew Reese

Reputation: 202605

The idea would be to iteratively split a time slot into two, the first going from the start of the time slot to the end of the day of the start time, and the second going from the start of the next day of the start time (add a day) to the end time.

{ start: dayjs('2019-01-01T22:00:00-00:00'), end: dayjs('2019-01-02T01:00:00-00:00') }

becomes

[
  { start: dayjs('2019-01-01T22:00:00-00:00'), end: dayjs('2019-01-02T23:59:59-00:00') },
  { start: dayjs('2019-01-02T00:00:00-00:00'), end: dayjs('2019-01-02T01:00:00-00:00') }
]

Note, it appears that dayjs uses full DateTime format by default.

Algorithm [Updated with new info about multi-day slots from @asissuthar]

const slotHopper = { ...slot }; // don't mutate original slot
while (!slotHopper.start.isSame(slotHopper.end, "day")) {
  // peel off first day of slot
  const splitSlot = {
    start: slotHopper.start,
    end: dayjs(slotHopper.start).endOf("day")
  };
  acc.push(splitSlot);
  // update start to beginning of next day
  slotHopper.start = dayjs(slotHopper.start)
    .add(1, "day")
    .startOf("day");
}
acc.push(slotHopper);

I extracted the above into a reducer function in the following sandbox example: https://codesandbox.io/s/lp0z5x7zw9, where acc is the accumulation array for the result.

Upvotes: 2

asissuthar
asissuthar

Reputation: 2256

Finally found solution. it works perfactly. Execute

import dayjs from "dayjs";

const slots = [
  { start: dayjs("2019-01-01 21:00:00"), end: dayjs("2019-01-01 23:00:00") },
  { start: dayjs("2019-01-01 22:00:00"), end: dayjs("2019-01-02 01:00:00") },
  { start: dayjs("2019-01-01 22:00:00"), end: dayjs("2019-01-02 04:00:00") },
  { start: dayjs("2019-01-01 21:00:00"), end: dayjs("2019-01-02 00:00:00") },
  { start: dayjs("2019-01-02 00:00:00"), end: dayjs("2019-01-02 04:00:00") },
  { start: dayjs("2019-01-02 01:00:00"), end: dayjs("2019-01-02 04:00:00") },
  { start: dayjs("2019-01-31 01:00:00"), end: dayjs("2019-02-01 04:00:00") },
  { start: dayjs("2019-02-01 01:00:00"), end: dayjs("2019-02-04 04:00:00") }
];

function splitDayWise(slots) {
  let output = [];

  function pushSlot(slot, start, end) {
    output.push({
      ...slot
    });

    let top = output[output.length - 1];
    top.start = start;
    top.end = end;
    top.time = top.end - top.start;
  }

  slots.forEach(slot => {
    if (slot.start.isSame(slot.end, "day")) {
      pushSlot(slot, slot.start, slot.end);
    } else {
      while (!slot.start.isSame(slot.end, "day")) {
        pushSlot(slot, slot.start, slot.start.endOf("day"));
        slot.start = slot.start.add(1, "day").startOf("day");
      }
      pushSlot(slot, slot.start, slot.end);
    }
  });

  return output;
}

const daywiseSlots = splitDayWise(slots).map(slot => ({
  start: slot.start.format("YYYY-MM-DD HH:mm:ss"),
  end: slot.end.format("YYYY-MM-DD HH:mm:ss"),
  time: slot.time
}));

console.log(JSON.stringify(daywiseSlots, null, 2));

Upvotes: 0

adiga
adiga

Reputation: 35202

You can do the following using reduce. I don't know dayjs. I'm assuming you're using it only to compare the date part and it's not part of the original array. So, instead I have created a function which gives just the date part for start and end.

const slots = [
  { start: '2019-01-01 21:00:00', end: '2019-01-01 23:00:00' },
  { start: '2019-01-01 22:00:00', end: '2019-01-02 01:00:00' },
  { start: '2019-01-01 22:00:00', end: '2019-01-02 04:00:00' },
  { start: '2019-01-01 21:00:00', end: '2019-01-02 00:00:00' },
  { start: '2019-01-02 00:00:00', end: '2019-01-02 04:00:00' },
  { start: '2019-01-02 01:00:00', end: '2019-01-02 04:00:00' },
  { start: '2019-01-31 01:00:00', end: '2019-02-01 04:00:00' }];
  
const getDay = (date) => date.split(" ")[0];

const newArray = slots.reduce((acc, {start,end}) => {
    if (getDay(start) != getDay(end))
        acc.push({ start, end: `${getDay(start)} 23:59:59` }, 
                 { start: `${getDay(end)} 00:00:00`, end });
    else
        acc.push({ start, end })
    return acc
}, []);

console.log(newArray)

Upvotes: 1

Related Questions