0

I have a list of items that each have a start and end date time component.

var myDates= new List<Tuple<DateTime, DateTime>>();

Which I fill it out with some date.

Now I wanted to loop through them and see if any two of those have any overlapping date rang. So I did this:

var myOverlapList = (from start in myDates
                   from endDate in myDates
                   where !Equals(start, end)
                   where start.Item1 <= end.Item2 && start.Item2 >= end.Item1
                   select end);

It works when dates have overlap for example one day back and forth between two dates BUT it does NOT work when two date entries have the EXACT SAME values.
So how I can fix my code or just something else to achieve that.

Bohn
  • 26,091
  • 61
  • 167
  • 254
  • 1
    I don't understand what your sequence is meant to represent at the moment - you seem to be using `dates` as both start and end dates, which is a bit confusing. If you could provide a [mcve] with plenty of sample input and expected output, I think that would make things significantly clearer. – Jon Skeet Mar 16 '20 at 19:32
  • Thanks Jon, each item represents a start date and an end date. For example So for example this person is available for work from this date to that date. – Bohn Mar 16 '20 at 19:33
  • Again, a [mcve] with plenty of sample data would be a *much* better way of making your clearer. (I would say that your naming is *really* confusing - if each tuple is meant to be `(startDate, endDate)` then calling each *tuple value* `startDate` and `endDate` makes it hard to understand what's going on. If you use ValueTuple with named elements, that confusion will be very obvious.) – Jon Skeet Mar 16 '20 at 19:38
  • I will add screen shot of debugger in a minute. – Bohn Mar 16 '20 at 19:40
  • 1
    No, not a screenshot - a simple console app we can run, with sample input and expected input. That way we can easily reproduce the problem and test any potential changes. That's all *much* harder to do with a screenshot. – Jon Skeet Mar 16 '20 at 19:48
  • With two date time ranges you have 5 different conditions where 2,3,4 are overlap conditions and 1,5 do no overlap. 1) Range A starts and ends before Range B 2) Range A starts before Range B and ends inside Range B 3) Range A starts and ends inside Range B 4) Range A starts inside Range B, but ends after Range B ends 5) Range A starts and ends after Range B. – jdweng Mar 16 '20 at 22:00
  • 1
    The easiest way of find overlap is with inverse logic. So overlap is NOT(1 or 5). Using code it would be NOT(( A end time B end time)). – jdweng Mar 16 '20 at 22:07
  • Related: https://stackoverflow.com/questions/13513932/algorithm-to-detect-overlapping-periods and https://stackoverflow.com/questions/7325124/how-check-intersection-of-datetime-periods and https://stackoverflow.com/questions/325933/determine-whether-two-date-ranges-overlap –  Mar 16 '20 at 23:41

1 Answers1

2

The

where !Equals(startDate, endDate)

line, which is supposed to filter out the same date tuple actually is filtering out any duplicate, so any matching timespan falls out of the selection. So your query will return all DateTime tuples, which overlap with some other tuple in the collection, but only unique. And you want also to return tuples if they encounter in your collection more then once.Your problem, actually is that you can not differentiate between two different items with the same value. So you need a discriminator for them and because you use a list, the index of an item fits well. You can cast your Tuple<DateTime, DateTime> collection into, e. g. {int id, Tuple<DateTime, DateTime> range} object by

var datesWithId = dates.Select((d, i) => new {id = i, range = d});

and then modify your query like this:

var anyOverlap = (from startDate in datesWithId
                  from endDate in datesWithId
                  where startDate.id!=endDate.id
                  && startDate.range.Item1 <= endDate.range.Item2
                  && startDate.range.Item2 >= endDate.range.Item1
                  select endDate.range).Distinct();