Skip to content

Instantly share code, notes, and snippets.

@rfprod
Last active April 22, 2017 15:44
Show Gist options
  • Save rfprod/f4a41a34360d80583ab06a7ebc982617 to your computer and use it in GitHub Desktop.
Save rfprod/f4a41a34360d80583ab06a7ebc982617 to your computer and use it in GitHub Desktop.
Appointment Time Finder
function getStartTime(schedules, duration) {
//console.log('schedules:', schedules, '| duration:', duration);
let spareTime = [];
schedules.forEach((schedule, index) => {
//console.log('index:', index);
spareTime.push([]);
if (schedule.length > 0) { // if a whole day is free schedule.length === 0
//console.log('schedule[0]:', schedule[0]);
if ((parseInt(schedule[0][0].split(':')[0]) > 9 && parseInt(schedule[0][0].split(':')[1]) >= 0) || (parseInt(schedule[0][0].split(':')[0]) >= 9 && parseInt(schedule[0][0].split(':')[1]) > 0)) {
//console.log('extra time in the morning, checking duration:', schedule[0][0]);
const diff = (parseInt(schedule[0][0].split(':')[0]) - 9) * 60 + parseInt(schedule[0][0].split(':')[1]);
//console.log('diff:', diff);
if (diff >= duration) { spareTime[index].push(['09:00', schedule[0][0]]); }
//console.log('spareTime:', spareTime);
}
for (let i = 1, max = schedule.length; i < max; i++) {
const previous = schedule[i - 1];
const current = schedule[i];
const diff = (parseInt(current[0].split(':')[0]) - parseInt(previous[1].split(':')[0])) * 60 + parseInt(current[0].split(':')[1]) - parseInt(previous[1].split(':')[1]);
//console.log('diff:', diff);
if (diff >= duration) { spareTime[index].push([previous[1], current[0]]); }
}
const lastIndex = schedule.length - 1;
if (parseInt(schedule[lastIndex][1].split(':')[0]) < 19) {
//console.log('extra time in the evening, checking duration:', schedule[lastIndex][1]);
const diff = (19 - parseInt(schedule[lastIndex][0].split(':')[0])) * 60 + 60 - parseInt(schedule[lastIndex][0].split(':')[1]);
//console.log('diff:', diff);
if (diff >= duration) { spareTime[index].push([schedule[lastIndex][1], '19:00']); }
}
} else {
spareTime[index].push('09:00', '19:00');
}
});
console.log('spareTime:', spareTime);
const noSpareTime = spareTime.filter((schedule) => schedule.length === 0);
if (noSpareTime.length > 0) {
//console.log('noSpareTime:', noSpareTime);
return null;
}
const mostAvailable = spareTime.reduce((a, b) => { return (a.length < b.length) ? b : a; });
//console.log('mostAvailable:', mostAvailable);
spareTime.splice(spareTime.indexOf(mostAvailable), 1);
//console.log('spareTime:', spareTime);
let matches = 0;
let matchesDetails = [];
let time = null;
root:
for (let k = 0, kMax = mostAvailable.length; k < kMax; k++) {
const sch0 = mostAvailable[k];
//console.log('sch0:', sch0);
let sch0Start = parseInt(sch0[0].split(':')[0]) * 60 + parseInt(sch0[0].split(':')[1]);
if (matchesDetails.length > 0) {
sch0Start = (matchesDetails[matchesDetails.length - 1].time && time > sch0Start) ? matchesDetails[matchesDetails.length - 1].time : sch0Start;
}
const sch0End = parseInt(sch0[1].split(':')[0]) * 60 + parseInt(sch0[1].split(':')[1]);
//console.log('sch0:', sch0Start, sch0End);
matches = 0;
time = null;
child1:
for (let j = 0, jMax = spareTime.length; j < jMax; j++) {
const schedule = spareTime[j];
//console.log('NEXT SCHEDULE:', schedule);
child2:
for (let i = 0, max = schedule.length; i < max; i++) {
const start = parseInt(schedule[i][0].split(':')[0]) * 60 + parseInt(schedule[i][0].split(':')[1]);
const end = parseInt(schedule[i][1].split(':')[0]) * 60 + parseInt(schedule[i][1].split(':')[1]);
//console.log('schedule time in minutes', start, end);
if (sch0Start <= start && sch0End >= end) {
matches++;
time = (time < start) ? start : time;
matchesDetails.push({ time: time, gaps: [start, end] });
//console.log('break child2 1, time', time);
break child2;
} else if (sch0Start > start && sch0End >= end && end > sch0Start && end - sch0Start >= duration) {
matches++;
time = (time < sch0Start) ? sch0Start : time;
matchesDetails.push({ time: time, gaps: [start, end] });
/*
console.log('break child2 2, time', time);
console.log('diff', end - sch0Start);
console.log('schedule 0:', sch0Start, sch0End, '|', duration);
console.log('schedule '+i+':', start, end, '|', duration);
*/
break child2;
} else if (sch0Start > start && sch0End < end && end - sch0Start >= duration && sch0End - start >= duration) {
matches++;
time = (time < sch0Start) ? sch0Start : time;
matchesDetails.push({ time: time, gaps: [start, end] });
/*
console.log('break child2 3, time', time);
console.log('diff', sch0End - start);
console.log('schedule 0:', sch0Start, sch0End, '|', duration);
console.log('schedule '+i+':', start, end, '|', duration);
*/
break child2;
} else if (sch0Start <= start && start < sch0End && sch0End < end && sch0End - start >= duration) {
matches++;
time = (time < start) ? start : time;
matchesDetails.push({ time: time, gaps: [start, end] });
/*
console.log('break child2 3, time', time);
console.log('diff', sch0End - start);
console.log('schedule 0:', sch0Start, sch0End, '|', duration);
console.log('schedule '+i+':', start, end, '|', duration);
*/
break child2;
} else {
console.log('ignore');
/*
console.log('schedule 0:', sch0Start, sch0End, '|', duration);
console.log('schedule '+i+':', start, end, '|', duration);
*/
}
}
//console.log('matches:', matches, '| schedules.length:', schedules.length);
//console.log('===');
if (schedules.length - 1 === matches && sch0End - time >= duration) {
//console.log('break root, time', time);
//console.log('schedule 0:', sch0Start, sch0End, '|', duration);
matches++;
break root;
}
}
}
//console.log('matchesDetails:', matchesDetails, 'time:', time);
// recalculate suitable matches after finding earlies starting time possible
matches = 1;
matchesDetails.forEach((match) => {
if (match.gaps[1] - time >= duration) { matches++; }
});
if (schedules.length !== matches) { time = null; }
// convert result to format hh:mm
let hours = Math.floor(time / 60);
hours = (hours < 10) ? '0' + hours : hours;
let minutes = time % 60;
minutes = (minutes < 10) ? '0' + minutes : minutes;
return (time) ? hours + ':' + minutes : time;
}
let schedules = [
[['09:10', '11:30'], ['12:30', '16:30'], ['17:30', '19:15']],
[['09:15', '12:10'], ['14:10', '16:20']]
],
duration = 120;
getStartTime(schedules, duration); // null

Appointment Time Finder

Searches provided schedules of apointments for spare time gaps. Checks whether found time gaps fullfill a provided duration requirement. Possible time for appointment is 09:00 - 19:00 excluding ending time. Next appointment can be scheduled at 11:30 if previous apointment ends at 11:30 accorging to provided schedule. Returns earliest possible time for an appointment in format hh:mm or null if nothing was found.

Input schedule example

Person Meetings
A 09:10 - 11:30, 12:30 - 16:30, 17:30 - 19:15
B 09:15 - 12:10, 14:10 - 16:20

The scehdule is provided as a three dimensinal array, i.e.:

[
  [['09:10', '11:30'], ['12:30', '16:30'], ['17:30', '19:15']],
  [['09:15', '12:10'], ['14:10', '16:20']]
]

A script by V.

License.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment