1

I need to check if a DateTime-span is overlapping with any existing blocks of time.

My function is supposed to check if anything is overlapping and will run a few hundred times with new start and end date with a span of 10 minutes in between. Spans from the existingTimeBlocks might be anything from 5-60 minutes long.

The first span received will always be the earliest date and the last span received will always be the latest date. The existingTimeBlocks list is also sorted by StartDate

    private bool TimeBlockIsOverLapping(DateTime newTimeBlockStart, DateTime newTimeBlockEnd, IEnumerable<TimeBlock> existingTimeBlocks)
    {
        // The new TimeBlock starts later than latest existing TimeBlock or ends earlier that first existing timeblock so it won't overlap
        if (existingTimeBlocks.Count() == 0)
        {
            return false;
        }

        // The new TimeBlock is within the scope of old TimeBlocks and might overlap
        else
        {
            // TODO: Insert overlap checks here
        }
    }

EDIT: Simplified definition of TimeBlock:

public class TimeBlock
    {
        [Required]
        public int Id { get; set; }

        [Required]
        public DateTime StartTime { get; set; }

        [Required]
        public DateTime EndTime { get; set; }

        [Required]
        public int ScheduleId { get; set; }

        [Required]
        public virtual Schedule Schedule { get; set; }
    }

EDIT: Further clarification: existingTimeBlocks can be for example every Monday and Thursday between 9:00 - 12:00 and 13:00-16:00 for 6 weeks, so a timeSpan of 60 minutes can be passed on a monday between 12:00 and 13:00 and be vaild

Emil Ekman
  • 63
  • 1
  • 6
  • 3
    *existingTimeBlocks.Count()* You shouldn't... The first rule of methods that accept an `IEnumerable` is to enumerate it only once. – xanatos Feb 28 '17 at 11:44
  • 1
    It looks like a hometask. Have you tried something? Nobody will do your work for you. – Yeldar Kurmangaliyev Feb 28 '17 at 11:45
  • Please can you add the definition of `TimeBlock`? – Dr Rob Lang Feb 28 '17 at 11:47
  • @RobLang according to last paragraph of question its probably consist of StartDate and EndDate ;) – M.kazem Akhgary Feb 28 '17 at 11:50
  • One important thing to specify is whether your time ranges are closed or if they are half-open. It is common to use half-open intervals for these things, where the start time is included in the range but the end time is NOT included in the range. This allows you to (for example) represent whole hours more easily without accidentally including a time at an exact hour in two different ranges. – Matthew Watson Feb 28 '17 at 11:53
  • @YeldarKurmangaliyev I think _some_ people here _will_ do his work for him. – Jeppe Stig Nielsen Feb 28 '17 at 12:28

3 Answers3

3

Something like:

private static bool TimeBlockIsOverLapping(DateTime newTimeBlockStart, DateTime newTimeBlockEnd, IEnumerable<TimeBlock> existingTimeBlocks) {
    foreach (var block in existingTimeBlocks) {
        // This is only if existingTimeBlocks are ordered. It is only
        // a speedup
        if (newTimeBlockStart > block.EndTime) {
            break;
        }

        // This is the real check. The ordering of the existingTimeBlocks
        // is irrelevant
        if (newTimeBlockStart <= block.EndTime && newTimeBlockEnd >= block.StartTime) {
            return true;
        }
    }

    return false;
}

To check for overlapping blocks, I've used Algorithm to detect overlapping periods

Community
  • 1
  • 1
xanatos
  • 109,618
  • 12
  • 197
  • 280
  • 1
    Note that this solution assumes a closed interval. That means that a time range 10:00-11:00 and a time range of 11:00-12:00 will overlap. (I avoid closed time intervals for this reason, but the OP will need to decide this.) – Matthew Watson Feb 28 '17 at 11:57
  • time ranges 10:00-11:00 and 11:00-12:00 should pass the check – Emil Ekman Feb 28 '17 at 12:01
1

Well, let's implement:

// static: we don't want "this" in the context
private static bool TimeBlockIsOverLapping(DateTime newTimeBlockStart, 
                                           DateTime newTimeBlockEnd, 
                                           IEnumerable<TimeBlock> existingTimeBlocks) {
  if (null == existingTimeBlocks)
    return false;
  else if (newTimeBlockStart > newTimeBlockEnd)
    return false;

  // assuming that there' no null blocks within existingTimeBlocks
  // and all blocks within existingTimeBlocks are valid ones
  foreach (var block in existingTimeBlocks) {
    //TODO: check edges: < or <=; > or >=
    if ((newTimeBlockStart < block.EndTime) && (newTimeBlockEnd > block.StartTime))
      return true; // overlap found
  }  

  return false; // no overlap found  
}
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
  • Last half of method could also be written `/* TODO: check edges: < or <=; > or >= */ return existingTimeBlocks.Any(block => (newTimeBlockStart < block.EndTime) && (newTimeBlockEnd > block.StartTime));` if one prefers. – Jeppe Stig Nielsen Feb 28 '17 at 13:01
0

Assuming your timeblock contains a start date and an end date, have an OverlapsWith function...

public class TimeBlock
{
    public DateTime EndTime {get;set;}
    public DateTime StartTime {get;set;}

    public bool OverlapsWith(TimeBlock other)
    {
        return (StartTime <= other.StartTime && EndTime >= other.StartTime)
            || (StartTime <= other.EndTime && EndTime >= other.EndTime);
    }
}

And then in your function...

var myBlock = new TimeBlock{ EndTime = newTimeBlockEnd, StartTime = newTimeBlockStart};
if(existingTimeBlocks.Any(x => x.OverlapsWith(myBlock)))
   // ...your code
galister
  • 430
  • 3
  • 9
  • the advantages of this solution are "OOP-thinking" (logic of TimeBlock comparison in TimeBlock class, not in helper method) and usage of existing Linq methods. not +1 at the moment, because OverlapsWith doesn't cover all cases (see the post linked by xanatos: http://stackoverflow.com/questions/13513932/algorithm-to-detect-overlapping-periods) – ASh Feb 28 '17 at 12:06