4

I am stumped about how to go about checking to see if multiple *date/time value -ranges- (meaning: start and end times) are in conflict with one another.

Summary & samples of data I need to work with.

I have an (app) events table, that is used to create a form for the user to go through and check off (checkboxes) all the sessions/events they attended.

The names of the checkboxes are generated using info about the session. (month/day start/end times along with a session id)

ie: hours_9_5_p02_800_845

9 = month
5 = date
p02 = session id/event code
800 = start time
845 = end time

all delimited by an underscore ("_")

If the user checks (and submits) multiple sessions, there will be many of these values to check for a time conflict..

hours_9_5_p08_755_800
hours_9_5_p02_800_845
hours_9_5_p02_800_855
hours_9_5_p03_800_845
hours_9_5_p04_820_835
hours_9_5_p04_845_900
hours_9_5_REG_900_915
hours_9_5_REG_1300_1305
hours_9_5_REG_1310_1335
hours_9_5_REG_1320_1335

The above is an example of the fieldlist/array that I 'could' get as a user selection/submission that I need to check for any possible conflicts (obviously the user couldnt be two places at once) :) And the above have many/several overlapping of just the same exact time slots selected.

** I am open to either PHP, (checking after the user submits) or javascript/jQuery (if it can do the date/time RANGE conflict checking, it might be easier to then highlight those rows/elements on the page if done on the front end)

I'd image, first you need to parse those checkbox names/strings from the fieldlist array...

which I have done like so: (php)

function conflictParse($delimiter, $targetString){
    //echo 'fired';
    $breakDown = explode($delimiter, $targetString);
    $startTime = substr_replace($breakDown[4] , ':', -2, 0);
    $endTime = substr_replace($breakDown[5] , ':', -2, 0);
    $startString = "$breakDown[1]/$breakDown[2]/2015 $startTime";
    $endString = "$breakDown[1]/$breakDown[2]/2015 $endTime";
    $startFormat = strtotime($startString);
    $endFormat = strtotime($endString);
    $start = date('m/d/Y G:i',$startFormat);
    $end = date('m/d/Y G:i',$endFormat);

    return "Session Times: $start -- $end <br>";
}
echo conflictParse('_','hours_9_5_p02_800_845');

but I am not clear on HOW to go about using this RANGE of a date start & end time to check against MULTIPLE other date start/end time RANGES?

maybe just sticking with having PHP parse/check conflict upon submit and then return some array of the (original) names page to the page (for some jQuery to use and highlight the elements..etc (but I can handle that aspect later.. for right now I am need help on how I can get the above parse 'date/time' start/end range values checked for conflicts against other 'date/time' start/end range values

update:

Here is the current nested associative array I have to work with for comparing:

Array ( 
    [0] => Array ( 
        [id] => hours_9_9_p02_800_845 
        [fullStart] => 09/09/2015 8:00 
        [fullEnd] => 09/09/2015 8:45 
        [month] => 9 
        [date] => 9 
        [session_code] => p02 
        [start] => 8:00 
        [end] => 8:45 
        [hasConflict] => false 
    ) 
    [1] => Array ( 
        [id] => hours_9_9_p02_800_855 
        [fullStart] => 09/09/2015 8:00 
        [fullEnd] => 09/09/2015 8:55 
        [month] => 9 
        [date] => 9 
        [session_code] => p02 
        [start] => 8:00 
        [end] => 8:55 
        [hasConflict] => false 
    ) 
    [2] => Array ( 
        [id] => hours_9_9_p03_800_845 
        [fullStart] => 09/09/2015 8:00 
        [fullEnd] => 09/09/2015 8:45 
        [month] => 9 
        [date] => 9 
        [session_code] => p03 
        [start] => 8:00 
        [end] => 8:45 
        [hasConflict] => false 
    ) 
    [3] => Array ( 
        [id] => hours_9_9_p04_820_830 
        [fullStart] => 09/09/2015 8:20 
        [fullEnd] => 09/09/2015 8:30 
        [month] => 9 
        [date] => 9 
        [session_code] => p04 
        [start] => 8:20 
        [end] => 8:30 
        [hasConflict] => false 
    ) 
    [4] => Array ( 
        [id] => hours_9_9_p04_845_900 
        [fullStart] => 09/09/2015 8:45 
        [fullEnd] => 09/09/2015 9:00 
        [month] => 9 
        [date] => 9 
        [session_code] => p04 
        [start] => 8:45 
        [end] => 9:00 
        [hasConflict] => false 
    ) 
    [5] => Array ( 
        [id] => hours_9_9_REG_1300_1315 
        [fullStart] => 09/09/2015 13:00 
        [fullEnd] => 09/09/2015 13:15 
        [month] => 9 
        [date] => 9 
        [session_code] => REG 
        [start] => 13:00 
        [end] => 13:15 
        [hasConflict] => false 
    ) 
    [6] => Array ( 
        [id] => hours_9_9_REG_1300_1330 
        [fullStart] => 09/09/2015 13:00 
        [fullEnd] => 09/09/2015 13:30 
        [month] => 9 
        [date] => 9 
        [session_code] => REG 
        [start] => 13:00 
        [end] => 13:30 
        [hasConflict] => false 
    ) 
) 

I need to convert your js functions over to PHP and of course use the fullStart/fullEnd variables in my time compares I guess..??

(but your function is still confusing me as I see references to event1, event 2.. (to match your example)..

update 2:

The above is my object/array (associative array) that I got from selecting some check boxes, and submitting my form...

Here is my attempt to convert your JS code to PHP based [with some update variablenames]: (and the commented out lines just to try and get some sort of output somewhere)

print_r($conflict_list);

    function checkFirst($cf_presX, $cf_presY) {
        //$cf_presX['fullStart'] < $cf_presY['fallStart'] ? checkConflict($cf_presX, $cf_presY) : checkConflict($cf_presY, $cf_presX);

        echo 'Pres Check: '.$cf_presX[0] . '<br>';
        echo 'Pres Check: '.$cf_presY[0] . '<br>';
        /*
        function checkConflict ($cc_presX, $cc_presY) {      
            if ($cc_presX.['fullEnd'] > $cc_presY.['fullStart']) {
                $cc_presX.['hasConflict'] = true;
                $cc_presY.['hasConflict'] = true;
            }
        }
        */
    }

    function setConflicts($events) {
        for ($i = 0; $i < count($events); $i++) {
            for ($j = 0; $i < count($events); $j++) {
              // if it is not the same event
              // if (i !== j) is the same $age['Peter']
              if ($events[$i]['id'] !== $events[$j]['id']) {
                checkFirst($events[$i], $events[$j]);
              }
            }
        }
    }
    setConflicts($conflict_list);

I just keep getting a loop with undefined offset: (counting up to the 100k+ mark)

Notice: Undefined offset: 0 in C:\wamp\www\projects\misc\conflict_check_new.php on line 49 Pres Check:

Notice: Undefined offset: 0 in C:\wamp\www\projects\misc\conflict_check_new.php on line 50 Pres Check:

Notice: Undefined offset: 0 in C:\wamp\www\projects\misc\conflict_check_new.php on line 49 Pres Check:

whispers
  • 962
  • 1
  • 22
  • 48
  • Will the times be sorted (as per your example) or random? –  Oct 17 '15 at 23:42
  • @jeff - Are you referring to these 'times': hours_9_5_p08_755_800 hours_9_5_p02_800_845 hours_9_5_p02_800_855 hours_9_5_p03_800_845 hours_9_5_p04_820_835 hours_9_5_p04_845_900 hours_9_5_REG_900_915 hours_9_5_REG_1300_1305 hours_9_5_REG_1310_1335 hours_9_5_REG_1320_1335 Those will be random..(these are the checkbox names, & hence the user selections submitted) The month date should be the same for each (as if that changed, there wouldnt be a conflict)... but the session name, start time and end times (which will be in 24 hour format) can be anything. – whispers Oct 18 '15 at 00:00
  • Possible duplicate of [Determine Whether Two Date Ranges Overlap](http://stackoverflow.com/questions/325933/determine-whether-two-date-ranges-overlap) – CBroe Oct 18 '15 at 01:00

1 Answers1

1

The same logic could apply in PHP, but assuming you can get your events out into JavaScript and create an array of objects with start and end dates like so:

var events = [
  {
    id: 'event1',
    start: new Date('1/1/1 5:00'),
    end: new Date('1/1/1 6:00'),
    hasConflict: false
  },
  {
    id: 'event2',
    start: new Date('1/1/1 5:30'),
    end: new Date('1/1/1 6:30'),
    hasConflict: false
  },
  {
    id: 'event3',
    start: new Date('1/1/1 7:30'),
    end: new Date('1/1/1 8:30'),
    hasConflict: false
  }
]

You can compare events to see if the one that starts first, has an end time that's later the second one's start time.

function checkFirst (event1, event2) {
  event1.start < event2.start 
    ? checkConflict(event1, event2) 
    : checkConflict(event2, event1)

  function checkConflict (first, second) {      
    if (first.end > second.start) {
      first.hasConflict = second.hasConflict = true
    }
  }
}

Then you can check events against each other. Here's a not particularly efficient, but at least suitable loop:

function flagAllEventsWithConflicts (events) {
  events.forEach(event1 => {
    events.forEach(event2 => {
      event1.id !== event2.id && checkFirst(event1, event2)
    })
  })
}

Update: The above function can also be written as a nested for loop:

function flagAllEventsWithConflicts (events) {
  for (var i = 0; i < events.length; i++) {
    for (var j = 0; j < events.length; j++ {
      // if it is not the same event
      // if (i !== j) is the same
      if (events[i].id !== events[j].id) {
        checkFirst(events[i], events[j])
      }
    }
  }
}

Then check to see if hasConflict is true or false:

flagAllEventsWithConflicts(events)
console.table(events)

Run this fiddle and checkout the console

azium
  • 20,056
  • 7
  • 57
  • 79
  • Thanks for the reply. So for the usage example.. I'd need a forEach() for 'each' event/session that is in the array? Using my example above, there would be 10 forEach() loops? then? (that I would have to write out?) I see the need to find the first (earliest) start time/event... as well as the need to also check against each sequential time/event in the list. – whispers Oct 18 '15 at 00:39
  • but I'm thinking there has to be a better approach? I wont know how many 'check boxes the user will select' upon submission. The array is really unknown, until submitted and parse like my attempts above to get the date stuff broken down. Possibly a variant of what you have suggested, with an array of objects and an index counter to dynamically loop through a forEach()? – whispers Oct 18 '15 at 00:41
  • @whispers I'm not sure what you mean.. you wouldn't have to write any more code than what I'm proposing. You only need to populate the events array. You don't write a `forEach` loop for every event, you just pass the array to the function (which I made more clear in my edit) – azium Oct 18 '15 at 00:56
  • @whispers `forEach` by definition goes through every element in the array. So for *every* event, check against *every* other event for a conflict. This solution would work for any number of events, that may or may not be known. – azium Oct 18 '15 at 01:01
  • Thanks. I'm trying to convert this to PHP, and am still a bit unclear on this line(s): function flagAllEventsWithConflicts(events) { events.foreach(event1 => { events.foreach(event2 => { event1.id !== event2.id && checkFirst(event1, event2) }) }) } seems like you are referencing each event in the array by its ID for comparison? (thats what I was trying to explain before, unsuccessfully) I have now reproduced this portion of the app (at home) and have built my object/associative array (similar to your example above) – whispers Oct 18 '15 at 03:51
  • original post updated with new nested associative array data. I have some extra info there for later use, and some for easier time checking in PHP, I hope. – whispers Oct 18 '15 at 03:52
  • @Julio Soares - Can you expand on this: `function flagAllEventsWithConflicts (events)` function? I'm not clear why you pass in an array, and then manually address (foreach) event 1, event 2.. it seems I would need to do this for event3, 4, 5, 6,...etc? – whispers Oct 18 '15 at 15:47
  • @whispers Ahh I see your confusion. `event1` and `event2` is not addressing the first and second event. but rather I'm doing a 'nested for loop using forEach'. Let me write this another way for you. Updated my answer – azium Oct 18 '15 at 18:00
  • Thanks for the update. I'm to sure if my conversion to PHP ruined something, somewhere? But it loops forever (doesnt stop until timeout or browser crashes..lol) I'll update first post with some info... and my PHP 'attempt' – whispers Oct 20 '15 at 01:51
  • @ azium this line had a typo: `for (var j = 0; i < events.length; j++ { ` :) – whispers Oct 20 '15 at 02:02
  • My current issue with this answer is that when I convert to PHP I feel like I'm loosing scope to the (nested) associative arrays.. as when I try to: Your line: first.hasConflict = second.hasConflict = true My line: $cc_presX.['hasConflict'] = true; $cc_presY.['hasConflict'] = true; I cant seem to set/update the hasConflict value in my original array. I tried to declare the array as global inside the function scope... but as we are passing (pointers?) to specific indexes in the array.. it seems to not save to the original array. – whispers Oct 20 '15 at 16:18
  • @whispers when I have some time later on, I'll look at how to implement in PHP – azium Oct 20 '15 at 16:39
  • HI- (I'm back again). I have ported the code over to PHP without issue..etc. However I have found a slight 'bug'.. that I cant wrap my head around. `//new (proposed) session conflicts checker function checkStartFirst($cf_presX, $cf_presY) { $cf_presX['fullStart'] < $cf_presY['fullStart'] ? $this->isConflict($cf_presX, $cf_presY) : $this->isConflict($cf_presY, $cf_presX); }` This is the function that checks what presentation comes first.. and then switches (or not) the order of the values passed as arguments to the conflict checking function. – whispers Nov 03 '15 at 23:40
  • I started a new thread/post just for debugging the conflict checking portion. http://stackoverflow.com/questions/33529964/php-certain-time-date-values-not-being-marked-as-conflicts-most-others-are-tho something with the conflict checking (or possibly the isFirst function) is allowing for certain values to slip through not flagged as a conflict – whispers Nov 04 '15 at 19:21