I recently had to implement a "DateRange" validator to check for any overlaps in the date ranges.
Here is my approach to it :
I started with a custom DateRange class.
public class DateRange
{
public int SortOrder { get; set; }
public DateTime Start { get; set; }
public DateTime End { get; set; }
public DateRange() {}
public DateRange(DateTime sTime, DateTime eTime)
{
Start = sTime;
End = eTime;
}
}
Then I call the "HasOverlap" method on my validator to check for overlaps.
/*
* LOGIC:
*
* 1. Take a List of date ranges. Example:
[Tuple A] -------- [Sort Order 1]
[Tuple B]-------- [Sort Order 2]
[Tuple C] -------- [Sort Order 3]
[Tuple D] -------- [Sort Order 4]
[Tuple E] -------- [Sort Order 5]
[Tuple F] ---------- [Sort Order 6]
* 2. Now sort the range by start + End Dates. This results in:
[Tuple B]-------- [Sort Order 1]
[Tuple C] -------- [Sort Order 2]
[Tuple D] -------- [Sort Order 3]
[Tuple F] ---------- [Sort Order 4]
[Tuple A] -------- [Sort Order 5]
[Tuple E] -------- [Sort Order 6]
* 3. The Logic is that there will be an overlap IF EVEN ONE of
* the 2 base conditions are met:
* (a) After sorting the list, a given tuple (TUPLE X)
* will be deemed overlapping
* if the END-DATE of (TUPLE X) is GREATER THAN the START-DATE
* of ANY tuple WHERE the sort order is GREATER THAN that of (TUPLE X)
*
* --- OR ---
*
* (b) After sorting the list, a given tuple (TUPLE X)
* will be deemed overlapping
* if the START-DATE and END-DATE of (TUPLE X) MATCHES
* the START-DATE and END-DATE of ANY tuple
* WHERE the sort order is GREATER THAN that of (TUPLE X)
*/
private bool HasOverlap(IList<DateRange> ranges)
{
// 1. Sort Dates based on Start & End Dates
var sortedRange = ranges
.OrderBy(p => p.Start)
.ThenBy(p => p.End)
.ToList();
var sortCounter = 0;
sortedRange.ForEach(e =>
{
e.SortOrder = sortCounter;
sortCounter++;
});
// 2. Check if the end dates are > any start dates except the same one
return sortedRange
.Any(tuple => (from innerLoop in sortedRange
where (
tuple.End > innerLoop.Start &&
innerLoop.SortOrder > tuple.SortOrder
) ||
(
tuple.End == innerLoop.End &&
tuple.Start == innerLoop.Start &&
innerLoop.SortOrder > tuple.SortOrder
)
select innerLoop).Any());
}
Additionally I also pass my DateRanges through a sanity check to ensure that the start < end dates.
No comments:
Post a Comment