Reputation: 45
I want to split my Start and End Time data on the basis of hourly time slots.
input = [
//Type A, it lies between 7 to 8 time slot
{ "start_time": "2021-08-20T07:00:00.000", "end_time": "2021-08-20T07:25:00.000", "Type": "A" },
//Type B , Time lies between 8, 9 time slot, so need to split into two new objects
{ "start_time": "2021-08-20T07:25:00.000", "end_time": "2021-08-20T08:39:49.000", "Type": "B" },
//Type C, Time lies between three slots 8, 9, 10, and 11. SO need to split in 4 objects.
{ "start_time": "2021-08-20T08:39:50.000", "end_time": "2021-08-20T11:02:34.000", "Type": "C" }
]
Expected output:
var output = [
{ "start_time": "2021-08-20T07:00:00.000", "end_time": "2021-08-20T07:25:00.000", "Type": "A" },
{ "start_time": "2021-08-20T07:25:00.000", "end_time": "2021-08-20T08:00:00.000", "Type": "B" },
{ "start_time": "2021-08-20T08:00:00.000", "end_time": "2021-08-20T08:39:49.000", "Type": "B" },
{ "start_time": "2021-08-20T08:39:49.000", "end_time": "2021-08-20T09:00:00.000", "Type": "C" },
{ "start_time": "2021-08-20T09:00:00.000", "end_time": "2021-08-20T10:00:00.000", "Type": "C" },
{ "start_time": "2021-08-20T10:00:00.000", "end_time": "2021-08-20T11:00:00.000", "Type": "C" },
{ "start_time": "2021-08-20T11:00:00.000", "end_time": "2021-08-20T11:02:34.000", "Type": "C" }
]
I used moment-range to create time Slots.
const day_start=moment().startOf('day').hours(7);
const day_end=moment().startOf('day').hours(15)
const day=moment.range(day_start,day_end)
const time_slots = Array.from(day.by('minutes',{step:60}))
Output I get here :
const hourly_data = [moment("2021-08-20T07:00:00.000"),
moment("2021-08-20T08:00:00.000"),
moment("2021-08-20T09:00:00.000"),
...
moment("2021-08-20T13:00:00.000"),
moment("2021-08-20T14:00:00.000"),
moment("2021-08-20T1500:00.000")]
I got hourly range as required, but unable to split.
Any help to get above output?
Upvotes: 2
Views: 832
Reputation: 3157
Use Array.reduce()
to iterate through each object and calculate time difference
b/w start_time and end_time in minutes using moment
, and then create time slots by calculating remaining minutes inside while loop.
input = [
{ "start_time": "2021-08-20T07:00:00.000", "end_time": "2021-08-20T07:25:00.000", "Type": "A" },
{ "start_time": "2021-08-20T07:25:00.000", "end_time": "2021-08-20T08:39:49.000", "Type": "B" },
{ "start_time": "2021-08-20T08:39:50.000", "end_time": "2021-08-20T11:02:34.000", "Type": "C" }
];
const result = input.reduce((arr, {start_time, end_time, Type}) => {
const dayStart = moment.utc(start_time);
const dayEnd = moment.utc(end_time);
let timeDiff = moment.duration(dayEnd.diff(dayStart)).asMinutes();
if (timeDiff > 60) {
while(dayStart < dayEnd) {
const diff = moment.duration(dayEnd.diff(dayStart)).asMinutes();
const minutes = diff > 60 ? 60 : diff;
const remainder = minutes - dayStart.minute();
const newObj = {
start_time: dayStart.clone(),
Type
};
dayStart.add(remainder, 'minutes');
newObj.end_time = dayStart.clone();
arr.push(newObj);
}
} else {
arr.push({
start_time: dayStart,
end_time: dayEnd,
Type
});
}
return arr;
}, []);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.20.1/moment.min.js"></script>
Upvotes: 2
Reputation: 1242
If you want the output write in your question you can try with this.
But you can do that whitout use range
.
In every case you must check if the end time of the slot is before or after the limit of the range and use the lower
window['moment-range'].extendMoment(moment); // just declaration
const input = [
//Type A, it lies between 7 to 8 time slot
{ "start_time": "2021-08-20T07:00:00.000", "end_time": "2021-08-20T07:25:00.000", "Type": "A" },
//Type B , Time lies between 8, 9 time slot, so need to split into two new objects
{ "start_time": "2021-08-20T07:25:00.000", "end_time": "2021-08-20T08:39:49.000", "Type": "B" },
//Type C, Time lies between three slots 8, 9, 10, and 11. SO need to split in 4 objects.
{ "start_time": "2021-08-20T08:39:50.000", "end_time": "2021-08-20T11:02:34.000", "Type": "C" }
]
const output = [];
for (const rangeDetails of input) {
const { start_time, end_time, Type } = rangeDetails;
const dateTimeStart = moment(start_time);
const dateTimeEnd = moment(end_time);
const range = moment.range(dateTimeStart, dateTimeEnd);
for (const startDateSlot of range.by('minutes', { step: 60 })) {
const help = { Type };
help.start_time = startDateSlot.clone();
help.end_time = moment(startDateSlot).add(60, 'minutes').isBefore(dateTimeEnd) ? moment(startDateSlot).add(60, 'minutes') : dateTimeEnd.clone();
output.push(help);
}
}
console.log(output);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
<script src="https://cdn.tutorialjinni.com/moment-range/4.0.2/moment-range.js"></script>
The alternative without range
is there:
const input = [
//Type A, it lies between 7 to 8 time slot
{ 'start_time': '2021-08-20T07:00:00.000', 'end_time': '2021-08-20T07:25:00.000', 'Type': 'A' },
//Type B , Time lies between 8, 9 time slot, so need to split into two new objects
{ 'start_time': '2021-08-20T07:25:00.000', 'end_time': '2021-08-20T08:39:49.000', 'Type': 'B' },
//Type C, Time lies between three slots 8, 9, 10, and 11. SO need to split in 4 objects.
{ 'start_time': '2021-08-20T08:39:50.000', 'end_time': '2021-08-20T11:02:34.000', 'Type': 'C' }
];
const output = [];
for (const rangeDetails of input) {
const { start_time, end_time, Type } = rangeDetails;
const dateTimeStart = moment(start_time);
const dateTimeEnd = moment(end_time);
while (dateTimeStart.isBefore(dateTimeEnd)) {
const help = { Type, start_time: dateTimeStart.clone() }
dateTimeStart.add(60, 'minutes'); // This edit dateTimeStart, adding 60 minutes
if (dateTimeStart.isAfter(dateTimeEnd)) help.end_time = dateTimeEnd.clone();
else help.end_time = dateTimeStart;
output.push(help);
}
}
console.log(output);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
Upvotes: 4
Reputation: 333
You could check how many hours each time span cuts by calculating its minutes divided by 60 (minutes). Now you know how often you have to split. For every time span you have to split there are three cases:
Maybe there is a more efficient way, but the below code does work:
const input = [
{ "start_time": "2021-08-20T07:00:00.000", "end_time": "2021-08-20T07:25:00.000", "Type": "A" },
{ "start_time": "2021-08-20T07:25:00.000", "end_time": "2021-08-20T08:39:49.000", "Type": "B" },
{ "start_time": "2021-08-20T08:39:50.000", "end_time": "2021-08-20T11:02:34.000", "Type": "C" }
]
const output = []
const format = "YYYY-MM-DDTHH:mm:ss.SSS"
input.forEach(span => {
const end = moment(span.end_time)
const start0 = moment(span.start_time).minutes(0).seconds(0)
const duration = moment.duration(end.diff(start0))
const minutes = duration.asMinutes()
const countSplits = Math.ceil(minutes / 60)
if(countSplits > 1) {
for (let index = 0; index < countSplits; index++) {
if(index === 0) {
output.push({
"start_time": span.start_time,
"end_time": moment(span.start_time).add(1, 'hour').minutes(0).seconds(0).format(format),
"Type": span.Type
})
}
else if(index < countSplits - 1) {
output.push({
"start_time": moment(span.start_time).add(index, 'hour').minutes(0).seconds(0).format(format),
"end_time": moment(span.start_time).add(index + 1, 'hour').minutes(0).seconds(0).format(format),
"Type": span.Type
})
}
else {
output.push({
"start_time": moment(span.start_time).add(index, 'hour').minutes(0).format(format),
"end_time": span.end_time,
"Type": span.Type
})
}
}
}
else {
output.push(span)
}
})
console.log(output)
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js" integrity="sha512-qTXRIMyZIFb8iQcfjXWCO8+M5Tbc38Qi5WzdPOYZHIlZpzBHG3L3by84BBBOiRGiEb7KKtAOAs5qYdUiZiQNNQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
Upvotes: 2
Reputation: 14259
You need to compare each input slot with each of your standard time slots and compute their overlapping - thus you will automatically split the bigger input slots.
var standardTimeSlots = [
{start_time: "07:00:00", end_time: "08:00:00"},
{start_time: "08:00:00", end_time: "09:00:00"},
{start_time: "09:00:00", end_time: "10:00:00"},
{start_time: "10:00:00", end_time: "11:00:00"},
{start_time: "11:00:00", end_time: "12:00:00"},
];
var inputSlots = [
//Type A, it lies between 7 to 8 time slot
{ "start_time": "2021-08-20T07:00:00.000", "end_time": "2021-08-20T07:25:00.000", "Type": "A" },
//Type B , Time lies between 8, 9 time slot, so need to split into two new objects
{ "start_time": "2021-08-20T07:25:00.000", "end_time": "2021-08-20T08:39:49.000", "Type": "B" },
//Type C, Time lies between three slots 8, 9, 10, and 11. SO need to split in 4 objects.
{ "start_time": "2021-08-20T08:39:50.000", "end_time": "2021-08-20T11:02:34.000", "Type": "C" }
];
function computeOverlap(start_1, end_1, start_2, end_2)
{
if (start_1 < end_2 && start_2 < end_1)
{
return [
start_1 > start_2 ? start_1 : start_2,
end_1 < end_2 ? end_1 : end_2
];
}
else
{
return false;
}
}
var indexInput, indexStandard, tmpStart, tmpEnd, overlap;
for(indexInput = 0; indexInput < inputSlots.length; indexInput++)
{
for(indexStandard = 0; indexStandard < standardTimeSlots.length; indexStandard++)
{
overlap = computeOverlap(
inputSlots[indexInput].start_time.substr(11, 8),
inputSlots[indexInput].end_time.substr(11, 8),
standardTimeSlots[indexStandard].start_time,
standardTimeSlots[indexStandard].end_time,
);
if (overlap) console.log(
inputSlots[indexInput].start_time.substr(0, 11) + overlap[0] + inputSlots[indexInput].start_time.substr(19),
inputSlots[indexInput].end_time.substr(0, 11) + overlap[1] + inputSlots[indexInput].end_time.substr(19))
}
}
Upvotes: 1