Gavin
Gavin

Reputation: 437

Comparing dates for overlap - not avoiding

I'm working on a timetabling piece of code. I am using a system of university modules and events associated to those modules, ie

Module CSC3039 Event1 - Lecture Event2 - Lecture Event3 - Practial etc

I need to check the times of each event in the module against each other and compare for clashes. The clashes do not need to be rectified, just highlighted. The table I will use is Events containing Event_ID (PK), Module_code (FK), Start_Date_Time, End_Date_Time plus other fields that don't matter here. I have figured out that I need to implement a For Each statement, ultimately resulting in an if statement such as:

if (startTime1 <= endTime2 or endTime1 >= startTime2) CLASH

My problem is trying to figure out the actual for loop here. I don't know what to write to declare my start times and end times. I presume it is a case of taking event1 and getting its start and end and then checking if event 2, 3 or 4 fit the above if statement. I'm trying to get this but could really use some guidance.

EDIT... Based on suggestions below I have implemented the following code:

    'return all relevant tables from the Modules database, based on the module code entered by the user.
    Dim eventTime = (From mods In db.Modules
                    Join evnt In db.Events On mods.Module_code Equals evnt.Module_code
                    Join rm In db.Rooms On rm.Room_ID Equals evnt.Room_ID
                    Join build In db.Buildings On build.Building_code Equals rm.Building_code
                    Where ((mods.Module_code = initialModCode) And (evnt.Room_ID = rm.Room_ID))
                    Select evnt.Event_ID, evnt.Module_code, evnt.Event_type, evnt.Start_Date_Time, evnt.End_Date_Time, build.Building_code, rm.Room_Number)


    'use the gridview to display the result returned by the above query
    gdvEventsTable.DataSource = eventTime
    gdvEventsTable.DataBind()

    Dim listClashes As New List(Of Array)

    For i As Integer = 0 To eventTime.Count - 1
        For j As Integer = i + 1 To eventTime.Count - 1
            If (eventTime.ToList(i).Start_Date_Time < eventTime.ToList(j).End_Date_Time) And (eventTime.ToList(i).End_Date_Time > eventTime.ToList(j).Start_Date_Time) Then
                MsgBox("Clash", MsgBoxStyle.MsgBoxSetForeground, "")
                listClashes.Add(eventTime)
            Else
                MsgBox("No Clash", MsgBoxStyle.MsgBoxSetForeground, "")
            End If
        Next
    Next

When trying to add an event to my array list I have noticed, in debug, that no events are sent to the list.

Upvotes: 0

Views: 779

Answers (3)

Saulius Šimčikas
Saulius Šimčikas

Reputation: 413

If you want to compare all the pairs of events that are in an array or some kind of a collection, you can use a loop like:

    Dim ModuleEventArray() As ModuleEvent
    '...
    For i As Integer = 0 To ModuleEventArray.Length - 1
        For j As Integer = i + 1 To ModuleEventArray.Length - 1
            'test if ModuleEventArray(i) overlaps with ModuleEventArray(j)
        Next
    Next

ModuleEvent here would be another class or structure that has fields startTime and endTime. The test

if (startTime1 <= endTime2 or endTime1 >= startTime2)

is not enough to test for overlap, but maybe you can figure out the correct test yourself :)


EDIT: Since I see you use some sort of collection, not array, the code you need should be something like:

For i As Integer = 0 To eventTime.Count - 1
    For j As Integer = i + 1 To eventTime.Count - 1
        If (eventTime.Item(i).Start_Date_Time < eventTime.Item(j).End_Date_Time) And (eventTime.Item(i).End_Date_Time > eventTime.Item(j).Start_Date_Time) Then
            MsgBox("Clash")
        Else
            MsgBox("No Clash")
        End If
    Next
Next

Upvotes: 1

Gavin
Gavin

Reputation: 437

My comparisons are coming from the database. Prior to the code below I have a query which returns all the records from my Events table, based on the user input of a Module_Code. This code will show the clashes, through a msgbox. I will be changing it to populate a list. It's not the prettiest and will probably lead to a lot of duplication but it achieves my main objective.

For Each evnt In eventTime


        Dim startTime1 = evnt.Start_Date_Time

        Dim endTime1 = evnt.End_Date_Time

        For Each evat In eventTime
            Dim startTime2 = evat.Start_Date_Time


            Dim endTime2 = evat.End_Date_Time



            If (startTime1 < endTime2) And (endTime1 > startTime2) Then
                MsgBox("Clash")
            Else
                MsgBox("No Clash")
            End If

        Next

    Next

Upvotes: 0

Celada
Celada

Reputation: 22261

Before you write your code, you need to first decide what your algorithm is going to be. For example, if you use the naive method your presume, the code is indeed straightforward (basically 2 nested loops) but the complexity if O(n²).

Depending on how much data you have, whether it is in a database, how likely you expect clashes to be, whether you always have the full list of events at the start or you need to find clashes incrementally, etc... different solutions might be preferred. One consideration is whether you need to partition the list into non-clashing sets of events or just produce a yes/no answer (one one for each event) stating whether there is a clash.

You might consider doing something different instead, like sorting the list by start time before you start comparing. That will allow you to walk the list only once.

Upvotes: 0

Related Questions