Reputation: 2256
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
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
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
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