Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I find the intersect of two sets of non-contiguous Times?

I am trying to build a tool that calculates something called quota based upon when employees are scheduled to work and when they request off.

My ShiftSet object is a set of Shift objects which consist of a StartTime and EndTime (both of type time(7). Each ShiftSet corresponds to a day.

ScheduleExceptions are times that an employee has off. There can be any number of overlapping or non-overlapping ScheduleExceptions in a day. They are of the datetime data type.

An example of a ShiftSet:
08:00-10:00
10:00-12:00
13:00-15:00
15:00-17:00

An example of ScheduleExceptions for that same day:
07:30-10:30
14:35-16:00

What I need to do is to find the amount of time that the employee is working on a day. The way I can figure to do this is to calculate the intersection of ShiftSet and the inverse of ScheduleExceptions.

How would I do this with time? I would prefer to use Linq if possible.

like image 307
Christopher Rayl Avatar asked Jan 16 '12 16:01

Christopher Rayl


2 Answers

Check out this great article at CodeProject

It's probably way too broad for your specific problem but it will probably give you a good starting point on how to solve it.

like image 180
InBetween Avatar answered Sep 19 '22 03:09

InBetween


As InBetween mentioned, there are libraries out there that have solved this problem, but they solve many related problems as well. If you are wanting to just tackle this particular problem without taking on another dependency, you can try the following.

// Finds ones with absolutely no overlap
var unmodified = shifts.Where(s => !exceptions.Any(e => s.Start < e.End && s.End > e.Start));

// Finds ones entirely overlapped
var overlapped = shifts.Where(s => exceptions.Any(e => e.End >= s.End && e.Start <= s.Start));

// Adjusted shifts
var adjusted = shifts.Where(s => !unmodified.Contains(s) && !overlapped.Contains(s))
                        .Select(s => new Shift
                        {
                            Start = exceptions.Where(e => e.Start <= s.Start && e.End > s.Start).Any() ? exceptions.Where(e => e.Start <= s.Start && e.End > s.Start).First().End : s.Start,
                            End = exceptions.Where(e => e.Start < s.End && e.End >= s.End).Any() ? exceptions.Where(e => e.Start < s.End && e.End >= s.End).First().Start : s.End
                        });

var newShiftSet = unmodified.Union(overlapped).Union(adjusted);

It's a basic example, though it could be compacted (albeit less-readable) and improved.

like image 39
CassOnMars Avatar answered Sep 21 '22 03:09

CassOnMars