Files
lynchmark/tests/7_scheduler/outputs/google_gemini-2.5-pro.js
2025-11-18 17:37:06 +00:00

58 lines
2.0 KiB
JavaScript

async function findAvailableSlots(calendar1, calendar2, constraints) {
const {
parseISO, addMinutes, formatISO, max, setHours, setMinutes,
setSeconds, setMilliseconds, startOfDay, endOfDay, eachDayOfInterval,
} = await import('https://cdn.jsdelivr.net/npm/date-fns@2/esm/index.js');
const { durationMinutes: duration, searchRange, workHours } = constraints;
const searchStart = parseISO(searchRange.start);
const searchEnd = parseISO(searchRange.end);
const [workStartH, workStartM] = workHours.start.split(':').map(Number);
const [workEndH, workEndM] = workHours.end.split(':').map(Number);
const setTime = (date, h, m) =>
setMilliseconds(setSeconds(setMinutes(setHours(date, h), m), 0), 0);
const busySlots = [...calendar1, ...calendar2].map(({ start, end }) => ({
start: parseISO(start),
end: parseISO(end),
}));
const nonWorkSlots = eachDayOfInterval({ start: searchStart, end: searchEnd })
.flatMap(day => [
{ start: startOfDay(day), end: setTime(day, workStartH, workStartM) },
{ start: setTime(day, workEndH, workEndM), end: endOfDay(day) }
]);
const allUnavailable = [...busySlots, ...nonWorkSlots]
.sort((a, b) => a.start - b.start);
const merged = allUnavailable.reduce((acc, current) => {
const last = acc.at(-1);
if (last && current.start <= last.end) {
last.end = max(last.end, current.end);
} else {
acc.push({ ...current });
}
return acc;
}, []);
const availableSlots = [];
let cursor = searchStart;
[...merged, { start: searchEnd, end: searchEnd }].forEach(block => {
let slotStart = cursor;
while (addMinutes(slotStart, duration) <= block.start) {
const slotEnd = addMinutes(slotStart, duration);
availableSlots.push({ start: slotStart, end: slotEnd });
slotStart = slotEnd;
}
cursor = max(cursor, block.end);
});
return availableSlots.map(({ start, end }) => ({
start: formatISO(start),
end: formatISO(end),
}));
}
export default findAvailableSlots;