Algorithm | Availability Ranges
import { format } from "@barelyhuman/date-utils";
const startOfDay = new Date(new Date().setHours(0, 0, 0));
const endOfDay = new Date(new Date().setHours(23, 59, 59));
const oneOClock = new Date().setHours(1, 0, 0);
const twoOClock = new Date().setHours(2, 0, 0);
const fourOClock = new Date().setHours(4, 0, 0);
const sixOClock = new Date().setHours(6, 0, 0);
const initialRange = [
{
from: startOfDay,
to: endOfDay,
space: 3,
},
];
const dateInMills = (date) => {
return new Date(date).getTime();
};
const pointIsBetween = (range, point) => {
return (
dateInMills(range.from) <= dateInMills(point) &&
dateInMills(point) <= dateInMills(range.to)
);
};
const pointIsAfter = (range, point) => {
return (
dateInMills(point) >= dateInMills(range.from) &&
dateInMills(point) >= dateInMills(range.to)
);
};
const pointIsBefore = (range, point) => {
return (
dateInMills(point) <= dateInMills(range.from) &&
dateInMills(point) <= dateInMills(range.to)
);
};
const block = (rangeToCheck, toBlock) => {
// Cases
// [done] equal to the whole range, return empty array
// [done] inbetween one range => split range and leave remaining as is
// [done] one value inbetween range => split range into two
// [done] fully equal to existing range => remove range and leave remaining as is
// [done] add spaces , remove 1 on each overlap and containment but not on split ups
console.log(
`----
Blocking ${format("hh:mm:ss", toBlock.from)} to ${format(
"hh:mm:ss",
toBlock.to
)}`
);
const availableRanges = [];
rangeToCheck.forEach((element) => {
// console.log({
// element: {
// from: format("hh-mm-ss", element.from),
// to: format("hh-mm-ss", element.to),
// space: element.space,
// },
// toBlock: {
// from: format("hh-mm-ss", toBlock.from),
// to: format("hh-mm-ss", toBlock.to),
// },
// });
if (
pointIsBetween(toBlock, element.from) &&
pointIsBetween(toBlock, element.to)
) {
if (element.space - 1 > 0) {
availableRanges.push({
...element,
space: element.space - 1,
});
} else {
availableRanges.push({
from: element.to,
to: toBlock.to,
space: element.space,
});
}
}
if (
pointIsBetween(element, toBlock.from) &&
pointIsBetween(element, toBlock.to)
) {
availableRanges.push({
from: element.from,
to: toBlock.from,
space: element.space,
});
if (element.space - 1 > 0) {
availableRanges.push({
from: toBlock.from,
to: toBlock.to,
space: element.space - 1,
});
}
availableRanges.push({
from: toBlock.to,
to: element.to,
space: element.space,
});
}
if (pointIsAfter(element, toBlock.from)) {
availableRanges.push(element);
}
if (pointIsBefore(element, toBlock.to)) {
availableRanges.push(element);
}
});
return availableRanges
.filter((item) => item.from !== item.to)
.sort((x, y) => dateInMills(x.from) - dateInMills(y.from));
};
let available = block(initialRange, { from: oneOClock, to: fourOClock });
bulkPrintRange(available);
available = block(available, { from: oneOClock, to: twoOClock });
bulkPrintRange(available);
available = block(available, { from: oneOClock, to: endOfDay });
bulkPrintRange(available);
available = block(available, { from: twoOClock, to: sixOClock });
bulkPrintRange(available);
function bulkPrintRange(rangeCollection) {
rangeCollection.forEach(printRange);
}
function printRange(range) {
console.log("---xxx---");
console.log("From:", format("hh:mm:ss", range.from));
console.log("To:", format("hh:mm:ss", range.to));
console.log("Space:", range.space);
}