mirror of
https://github.com/multipleof4/lynchmark.git
synced 2026-01-14 16:47:55 +00:00
Docs: Update benchmark results
This commit is contained in:
@@ -1,85 +1,108 @@
|
||||
const findAvailableSlots = async (cal1, cal2, constraints) => {
|
||||
const { DateTime, Interval } = await import('https://cdn.skypack.dev/luxon');
|
||||
const { default: dayjs } = await import('https://cdn.jsdelivr.net/npm/dayjs@1.11.10/+esm');
|
||||
const [{ default: utc }, { default: customParseFormat }, { default: isBetween }] = await Promise.all([
|
||||
import('https://cdn.jsdelivr.net/npm/dayjs@1.11.10/plugin/utc.js'),
|
||||
import('https://cdn.jsdelivr.net/npm/dayjs@1.11.10/plugin/customParseFormat.js'),
|
||||
import('https://cdn.jsdelivr.net/npm/dayjs@1.11.10/plugin/isBetween.js')
|
||||
]);
|
||||
|
||||
const { durationMinutes: dur, searchRange: range, workHours: wh } = constraints;
|
||||
const [rangeStart, rangeEnd] = [DateTime.fromISO(range.start), DateTime.fromISO(range.end)];
|
||||
const [whStart, whEnd] = wh.start.split(':').map(Number);
|
||||
const [whStartMin, whEndMin] = [whStart * 60 + (wh.start.split(':')[1] || 0),
|
||||
whEnd.split(':').map(Number).reduce((h, m) => h * 60 + m)];
|
||||
|
||||
const mergeIntervals = (intervals) => {
|
||||
if (!intervals.length) return [];
|
||||
const sorted = intervals.sort((a, b) => a.start - b.start);
|
||||
const merged = [sorted[0]];
|
||||
for (let i = 1; i < sorted.length; i++) {
|
||||
const last = merged[merged.length - 1];
|
||||
if (sorted[i].start <= last.end) {
|
||||
last.end = last.end > sorted[i].end ? last.end : sorted[i].end;
|
||||
} else {
|
||||
merged.push(sorted[i]);
|
||||
}
|
||||
}
|
||||
return merged;
|
||||
};
|
||||
|
||||
const toBusy = (cal) => cal.map(({ start, end }) => ({
|
||||
start: DateTime.fromISO(start),
|
||||
end: DateTime.fromISO(end)
|
||||
}));
|
||||
|
||||
const allBusy = mergeIntervals([...toBusy(cal1), ...toBusy(cal2)]);
|
||||
|
||||
const isWorkHour = (dt) => {
|
||||
const min = dt.hour * 60 + dt.minute;
|
||||
return min >= whStartMin && min < whEndMin;
|
||||
};
|
||||
|
||||
const slots = [];
|
||||
let cursor = rangeStart;
|
||||
|
||||
while (cursor < rangeEnd) {
|
||||
if (!isWorkHour(cursor)) {
|
||||
cursor = cursor.plus({ minutes: 1 });
|
||||
continue;
|
||||
}
|
||||
|
||||
const slotEnd = cursor.plus({ minutes: dur });
|
||||
|
||||
if (slotEnd > rangeEnd) break;
|
||||
|
||||
let validSlot = true;
|
||||
let tempCursor = cursor;
|
||||
while (tempCursor < slotEnd) {
|
||||
if (!isWorkHour(tempCursor)) {
|
||||
validSlot = false;
|
||||
break;
|
||||
}
|
||||
tempCursor = tempCursor.plus({ minutes: 1 });
|
||||
}
|
||||
|
||||
if (!validSlot) {
|
||||
cursor = cursor.plus({ minutes: 1 });
|
||||
continue;
|
||||
}
|
||||
|
||||
const overlaps = allBusy.some(busy =>
|
||||
(cursor >= busy.start && cursor < busy.end) ||
|
||||
(slotEnd > busy.start && slotEnd <= busy.end) ||
|
||||
(cursor <= busy.start && slotEnd >= busy.end)
|
||||
);
|
||||
|
||||
if (!overlaps) {
|
||||
slots.push({
|
||||
start: cursor.toISO(),
|
||||
end: slotEnd.toISO()
|
||||
});
|
||||
cursor = slotEnd;
|
||||
dayjs.extend(utc);
|
||||
dayjs.extend(customParseFormat);
|
||||
dayjs.extend(isBetween);
|
||||
|
||||
const { durationMinutes, searchRange, workHours } = constraints;
|
||||
const allBusy = [...cal1, ...cal2].map(s => ({
|
||||
start: dayjs(s.start),
|
||||
end: dayjs(s.end)
|
||||
})).sort((a, b) => a.start - b.start);
|
||||
|
||||
const merged = allBusy.reduce((acc, curr) => {
|
||||
if (!acc.length || acc[acc.length - 1].end < curr.start) {
|
||||
acc.push(curr);
|
||||
} else {
|
||||
const nextBusy = allBusy.find(b => b.end > cursor && b.start <= cursor);
|
||||
cursor = nextBusy ? nextBusy.end : cursor.plus({ minutes: 1 });
|
||||
acc[acc.length - 1].end = dayjs.max(acc[acc.length - 1].end, curr.end);
|
||||
}
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
const slots = [];
|
||||
const searchStart = dayjs(searchRange.start);
|
||||
const searchEnd = dayjs(searchRange.end);
|
||||
const [whStart, whEnd] = [
|
||||
dayjs(workHours.start, 'HH:mm'),
|
||||
dayjs(workHours.end, 'HH:mm')
|
||||
];
|
||||
|
||||
const isInWorkHours = (dt) => {
|
||||
const time = dayjs().hour(dt.hour()).minute(dt.minute());
|
||||
return time.isBetween(whStart, whEnd, null, '[)');
|
||||
};
|
||||
|
||||
const addSlot = (start, end) => {
|
||||
let curr = start;
|
||||
while (curr.add(durationMinutes, 'minute') <= end) {
|
||||
if (isInWorkHours(curr) && isInWorkHours(curr.add(durationMinutes, 'minute').subtract(1, 'second'))) {
|
||||
const slotEnd = curr.add(durationMinutes, 'minute');
|
||||
const dayEnd = curr.hour(whEnd.hour()).minute(whEnd.minute());
|
||||
if (slotEnd <= dayEnd) {
|
||||
slots.push({
|
||||
start: curr.toISOString(),
|
||||
end: slotEnd.toISOString()
|
||||
});
|
||||
}
|
||||
}
|
||||
curr = curr.add(15, 'minute');
|
||||
}
|
||||
};
|
||||
|
||||
let prevEnd = searchStart.hour(whStart.hour()).minute(whStart.minute());
|
||||
if (prevEnd < searchStart) prevEnd = searchStart;
|
||||
|
||||
merged.forEach(busy => {
|
||||
if (busy.start > prevEnd) {
|
||||
let gapStart = prevEnd;
|
||||
let gapEnd = busy.start;
|
||||
|
||||
let day = gapStart.startOf('day');
|
||||
while (day <= gapEnd) {
|
||||
const dayStart = dayjs.max(
|
||||
gapStart,
|
||||
day.hour(whStart.hour()).minute(whStart.minute())
|
||||
);
|
||||
const dayEnd = dayjs.min(
|
||||
gapEnd,
|
||||
day.hour(whEnd.hour()).minute(whEnd.minute())
|
||||
);
|
||||
|
||||
if (dayStart < dayEnd && dayStart >= searchStart && dayEnd <= searchEnd) {
|
||||
addSlot(dayStart, dayEnd);
|
||||
}
|
||||
day = day.add(1, 'day');
|
||||
}
|
||||
}
|
||||
prevEnd = dayjs.max(prevEnd, busy.end);
|
||||
});
|
||||
|
||||
const finalEnd = searchEnd.hour(whEnd.hour()).minute(whEnd.minute());
|
||||
if (prevEnd < finalEnd) {
|
||||
let day = prevEnd.startOf('day');
|
||||
while (day <= finalEnd) {
|
||||
const dayStart = dayjs.max(
|
||||
prevEnd,
|
||||
day.hour(whStart.hour()).minute(whStart.minute())
|
||||
);
|
||||
const dayEnd = dayjs.min(
|
||||
finalEnd,
|
||||
day.hour(whEnd.hour()).minute(whEnd.minute())
|
||||
);
|
||||
|
||||
if (dayStart < dayEnd && dayStart >= searchStart && dayEnd <= searchEnd) {
|
||||
addSlot(dayStart, dayEnd);
|
||||
}
|
||||
day = day.add(1, 'day');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return slots;
|
||||
};
|
||||
export default findAvailableSlots;
|
||||
Reference in New Issue
Block a user