I Have a event with a list of workshops that will happen. Each workshop can have multiple meetings. The interfaces looks like:
interface Workshop {
...
meetings: WorkshopMeeting[];
}
interface WorkshopMeeting {
id: number;
startDate: Date;
endDate: Date;
}
My final object have a array of Workshop like:
const event = {
// ... other data
workshops: [] as Workshop[]
}
What I need is to find if have any intersections beetwen all workshops' meetings.
For exemple, my event have 2 workshops, and the first one is scheduled to start at 29/03/2022 14:00 and end at 29/03/2022 18:00, while my second workshop is scheduled to start at 29/03/2022: 15:00 and end at 29/03/2022: 20:00. In this case, the workshop 2 have a meeting that happens at the same time from a meeting of the workshop1.
I'm trying to create a algortihm to find theses dates conflits, but I am not having a good progress.
I tried some loops but i can't find the comparison logic
CodePudding user response:
Moment JS may help you:
const date1 = [moment("2016-12-06 11:00"), moment("2016-12-06 12:00")];
const date2 = [moment("2016-12-06 10:00"), moment("2016-12-06 13:00")];
const range = moment.range(date1);
const range2 = moment.range(date2);
// has overlapping
if(range.overlaps(range2)) {
if((range2.contains(range, true) || range.contains(range2, true)) && !date1[0].isSame(date2[0]))
alert("time range 1 is completely conflict with time range 2 and vice versa");
else
alert("time range 1 is partially conflict with time range 2 and vice versa");
CodePudding user response:
Here's a solution that uses an internal chart like this:
09 10 11 12 13 14 15 16 17 18 19 20
(------------- 1 ------------)
(----------------- 2 ---------------)
(----- 3 -----)
(----- 4 ------)
(------------ 5 ------------)
and then collects the key times on there (where any event stops or starts), here 9
, 11
, 12
, 13
, 14
, 15
, 18
, and 20
, groups those into pairs, such as 9 - 11
, 11 - 12
, ... 18 - 20
, and for each one finds the events which start before the period's end and end after its start. It then filters the list to return those which have more than one event:
// utility functions
const inPairs = (xs) => xs .slice (1) .map ((x, i) => [xs [i], x])
const uniq = (xs) => [... new Set (xs)]
// main function
const overlaps = (events) =>
inPairs (uniq (events .flatMap ((w) => [w .startDate, w .endDate])) .sort ())
.map (([start, end]) => ({
start,
end,
events: events.filter (e => e .startDate < end && e.endDate > start) .map (e => e .id)
}))
.filter (({events}) => events .length > 1)
// sample data
const meetings = [{id: 1, startDate: '2022-03-29T14:00:00', endDate: '2022-03-29T18:00:00'}, {id: 2, startDate: '2022-03-29T15:00:00', endDate: '2022-03-29T20:00:00'}, {id: 3, startDate: '2022-03-29T09:00:00', endDate: '2022-03-29T11:00:00'}, {id: 4, startDate: '2022-03-29T11:00:00', endDate: '2022-03-29T13:00:00'}, {id: 5, startDate: '2022-03-29T12:00:00', endDate: '2022-03-29T16:00:00'}]
// demo
const conflicts = overlaps (meetings)
// display
conflicts .forEach (({start, end, events}) => console .log (`${start} - ${end}: events: ${events .join (', ')}`))
inPairs
converts something like ['a', 'b', 'c', 'd']
into [['a', 'b']. ['b', 'c'], ['c', 'd']]
.
uniq
simply collects the unique elements of an array of elements.
Our main function, overlaps
first collects all the start and end dates of a list of events, finds the unique elements, sorts them, and then uses inPairs
to turn that list into an array of periods. We map these into objects, finding all the events which overlap the period. Finally, we filter them to those which include more than one event.
This uses ISO-8601 string dates rather than Date objects. If you want to use actual dates, you will need to find another way to create the unique set and to do the event filtering. Those aren't hard, but it might be easier just to convert into this format before you call this function.
This doesn't solve your outer problem, but does give you a list of conflicts, and the events in each one.