Files
lynchmark/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_0.7.js
2025-11-18 22:04:41 +00:00

61 lines
1.8 KiB
JavaScript

export const findAvailableSlots = async (calA, calB, { durationMinutes: dur, searchRange: range, workHours: wh }) => {
const { default: d } = await import('https://esm.sh/dayjs@1.11.10');
const { default: u } = await import('https://esm.sh/dayjs@1.11.10/plugin/utc');
d.extend(u);
const D = t => d.utc(t);
const rS = D(range.start), rE = D(range.end);
const setT = (dt, t) => {
const [h, m] = t.split(':');
return dt.hour(h).minute(m).second(0).millisecond(0);
};
// 1. Merge and Sort Busy Slots
let busy = [...calA, ...calB]
.map(x => ({ s: D(x.start), e: D(x.end) }))
.filter(x => x.e > rS && x.s < rE)
.sort((a, b) => a.s - b.s);
let merged = [], curr = busy[0];
if (curr) {
for (let i = 1; i < busy.length; i++) {
if (busy[i].s < curr.e) curr.e = busy[i].e > curr.e ? busy[i].e : curr.e;
else { merged.push(curr); curr = busy[i]; }
}
merged.push(curr);
}
// 2. Identify Free Gaps within Search Range
let gaps = [], ptr = rS;
for (const b of merged) {
if (b.s > ptr) gaps.push({ s: ptr, e: b.s });
ptr = b.e > ptr ? b.e : ptr;
}
if (ptr < rE) gaps.push({ s: ptr, e: rE });
// 3. Generate Slots intersecting Work Hours
const slots = [];
for (const g of gaps) {
let day = g.s.clone().startOf('day');
const endDay = g.e.clone().endOf('day');
while (day <= endDay) {
const wS = setT(day, wh.start), wE = setT(day, wh.end);
// Intersection of Gap and Work Hours
const start = g.s > wS ? g.s : wS;
const end = g.e < wE ? g.e : wE;
if (start < end) {
let s = start;
while (s.add(dur, 'm') <= end) {
slots.push({ start: s.toISOString(), end: s.add(dur, 'm').toISOString() });
s = s.add(dur, 'm');
}
}
day = day.add(1, 'd');
}
}
return slots;
};
export default findAvailableSlots;