skip to Main Content

I have an input file with call start datetime and call end datetime separated by ‘|’. I am trying to read in the file row-by-row and calculate the maximum number of overlapping/concurrent calls. I’ve been trying, but I can’t seem to get correct.

Example input file:

2023-01-19 11:18:17|2023-01-19 11:21:59
2023-01-19 11:18:30|2023-01-19 11:19:06
2023-01-19 11:18:58|2023-01-19 11:20:04
2023-01-19 11:20:56|2023-01-19 11:21:56
2023-01-19 11:21:18|2023-01-19 11:24:42
2023-01-19 11:21:26|2023-01-19 11:22:02
2023-01-19 11:21:56|2023-01-19 11:22:38
2023-01-19 11:22:47|2023-01-19 11:26:59
2023-01-19 11:23:40|2023-01-19 11:24:58
2023-01-19 11:25:10|2023-01-19 11:25:46
2023-01-19 11:25:51|2023-01-19 11:27:57
2023-01-19 11:26:01|2023-01-19 11:26:37
2023-01-19 11:26:01|2023-01-19 11:27:37
2023-01-19 11:26:19|2023-01-19 11:26:55
2023-01-19 11:27:23|2023-01-19 11:28:59
2023-01-19 11:27:35|2023-01-19 11:27:47
2023-01-19 11:28:26|2023-01-19 11:28:38

My code currently looks like this (I apologize, I was having a hard time with the text editor here so it looks a little disjointed and missing a "{" after the function name…):

function readcsv($filename) {

  $handle = fopen($filename, "r");
  if ($handle) {

    $data = [];
    $max = 0;
    $calls = 0;
    $datetime = "";
    while (($line = fgetcsv($handle, null, "|")) !== false) {

        if (!isset($data["previousendmax"])) {
            $data["previousendmax"] = $line[1];
        }

        if (!isset($data["previousendmin"])) {
            $data["previousendmin"] = $line[0];
        }

        $startdate = $line[0];
        $enddate = $line[1];

        if (
            $startdate >= $data["previousendmin"] &&
            $startdate <= $data["previousendmax"]
        ) {
            $calls++;
        }
        if (
            $enddate > $data["previousendmax"] ||
            $startdate > $data["previousendmax"]
        ) {
            $calls--;
        }

        if ($startdate > $data["previousendmin"]) {
            $data["previousendmin"] = $enddate;
        }
        if ($enddate > $data["previousendmax"]) {
            $data["previousendmax"] = $enddate;
        }

        if ($calls > $max) {
            $max = $calls;
            $data["previousend"] = $line[1];
            $datetime = $line[0];
        }
        echo "Current Calls: " . $calls . "n";
        echo "Max Calls: " . $max . "n";
        print_r($data["previousendmin"]);
        echo "n";
        print_r($data["previousendmax"]);
        echo "n";
    }
    fclose($handle);
}

print_r($max);

The current output is:

Current Calls: 1
Max Calls: 1
2023-01-19 11:18:17
2023-01-19 11:21:59
Current Calls: 2
Max Calls: 2
2023-01-19 11:19:06
2023-01-19 11:21:59
Current Calls: 2
Max Calls: 2
2023-01-19 11:19:06
2023-01-19 11:21:59
Current Calls: 3
Max Calls: 3
2023-01-19 11:21:56
2023-01-19 11:21:59
Current Calls: 2
Max Calls: 3
2023-01-19 11:21:56
2023-01-19 11:24:42
Current Calls: 2
Max Calls: 3
2023-01-19 11:21:56
2023-01-19 11:24:42
Current Calls: 3
Max Calls: 3
2023-01-19 11:21:56
2023-01-19 11:24:42
Current Calls: 3
Max Calls: 3
2023-01-19 11:26:59
2023-01-19 11:26:59
Current Calls: 3
Max Calls: 3
2023-01-19 11:26:59
2023-01-19 11:26:59
Current Calls: 3
Max Calls: 3
2023-01-19 11:26:59
2023-01-19 11:26:59
Current Calls: 2
Max Calls: 3
2023-01-19 11:26:59
2023-01-19 11:27:57
Current Calls: 2
Max Calls: 3
2023-01-19 11:26:59
2023-01-19 11:27:57
Current Calls: 2
Max Calls: 3
2023-01-19 11:26:59
2023-01-19 11:27:57
Current Calls: 2
Max Calls: 3
2023-01-19 11:26:59
2023-01-19 11:27:57
Current Calls: 2
Max Calls: 3
2023-01-19 11:28:59
2023-01-19 11:28:59
Current Calls: 2
Max Calls: 3
2023-01-19 11:28:59
2023-01-19 11:28:59
Current Calls: 2
Max Calls: 3
2023-01-19 11:28:59
2023-01-19 11:28:59
3

Of course, at the end of the list, it should show zero calls so I know it’s not working as expected. If I were to review the first 6 lines list manually, I would expect the following of concurrent calls:

1
2
3
2
3
4

Where I’m struggling is how to account for calls that ended before the next row started… but happened to be a couple rows above the row I’m currently evaluating. For example, row 4, it’s starting at 11:20:56 which means that by the time that call starts, the calls on both rows 2 and 3 have ended. Can anyone point me in the right direction? Thanks!

I’ve tried to construct a rolling "window" of time and then calculate the number of calls going on at the same time within that window, but this method isn’t working as expected (certainly because I’m a novice and doing it wrong).

2

Answers


  1. Chosen as BEST ANSWER

    I spoke to a colleague and he suggested the following: When a call starts, it's +1 When a call ends, it's -1 So break up the rows. Using the first 6 rows as an example:

    2023-01-19 11:18:17,+1
    2023-01-19 11:18:30,+1
    2023-01-19 11:18:58,+1
    2023-01-19 11:20:56,+1
    2023-01-19 11:21:18,+1
    2023-01-19 11:21:26,+1
    2023-01-19 11:21:59,-1
    2023-01-19 11:19:06,-1
    2023-01-19 11:20:04,-1
    2023-01-19 11:21:56,-1
    2023-01-19 11:24:42,-1
    2023-01-19 11:22:02,-1
    

    Then, sort by the date/time and calculate them:

    2023-01-19 11:18:17,+1 - 1
    2023-01-19 11:18:30,+1 - 2
    2023-01-19 11:18:58,+1 - 3
    2023-01-19 11:19:06,-1 - 2
    2023-01-19 11:20:04,-1 - 1
    2023-01-19 11:20:56,+1 - 2
    2023-01-19 11:21:18,+1 - 3
    2023-01-19 11:21:26,+1 - 4
    2023-01-19 11:21:56,-1 - 3
    2023-01-19 11:21:59,-1 - 2
    2023-01-19 11:22:02,-1 - 1
    2023-01-19 11:24:42,-1 - 0
    

    Pretty easy when you approach it like this!


  2. If I understand the question correctly, the problem is to find the periods between changes, where a change is a phone call starting or a phone call ending.

    For simpler testing lets start with an array instead of reading in a CSV file (which is not related to the question):

    $input = [
        [ '2023-01-19 11:18:17', '2023-01-19 11:21:59' ],
        [ '2023-01-19 11:18:30', '2023-01-19 11:19:06' ],
        [ '2023-01-19 11:18:58', '2023-01-19 11:20:04' ],
        [ '2023-01-19 11:20:56', '2023-01-19 11:21:56' ],
        [ '2023-01-19 11:21:18', '2023-01-19 11:24:42' ],
        [ '2023-01-19 11:21:26', '2023-01-19 11:22:02' ],
        [ '2023-01-19 11:21:56', '2023-01-19 11:22:38' ],
        [ '2023-01-19 11:22:47', '2023-01-19 11:26:59' ],
        [ '2023-01-19 11:23:40', '2023-01-19 11:24:58' ],
        [ '2023-01-19 11:25:10', '2023-01-19 11:25:46' ],
        [ '2023-01-19 11:25:51', '2023-01-19 11:27:57' ],
        [ '2023-01-19 11:26:01', '2023-01-19 11:26:37' ],
        [ '2023-01-19 11:26:01', '2023-01-19 11:27:37' ],
        [ '2023-01-19 11:26:19', '2023-01-19 11:26:55' ],
        [ '2023-01-19 11:27:23', '2023-01-19 11:28:59' ],
        [ '2023-01-19 11:27:35', '2023-01-19 11:27:47' ],
        [ '2023-01-19 11:28:26', '2023-01-19 11:28:38' ],
    ];
    
    $date_times = [];
    
    foreach ($input as $item) {
        $date_times[] = [
            'start' => true,
            'time'  => DateTime::createFromFormat('Y-m-d H:i:s', $item[0]),
            'item'  => $item
        ];
        $date_times[] = [
            'start' => false,
            'time'  => DateTime::createFromFormat('Y-m-d H:i:s', $item[1]),
            'item'  => $item
        ];
    }
    
    usort($date_times, fn($item1, $item2) => $item1['time'] <=> $item2['time']);
    
    $result = [];
    
    $temp_items = [];
    $max = 0;
    
    for ($i = 1; $i < count($date_times); $i++) {
        if ($date_times[$i - 1]['start']) {
            $temp_items[] = $date_times[$i - 1]['item'];
        } else {
            $index = array_search($date_times[$i - 1]['item'], $temp_items, true);
            unset($temp_items[$index]);
        }
        $result[] = [
            'from'  => $date_times[$i - 1]['time'],
            'till'  => $date_times[$i]['time'],
            'count' => $count = count($temp_items),
            'max'   => $max = max($max, $count),
            'item'  => $date_times[$i - 1]['item'],
            'items' => $temp_items,
        ];
    }
    
    echo "Period      Calls  Max  Itemsn";
    echo "----------------------------------------------------------------------------------------n";
    foreach ($result as $item) {
        echo $item['from']->format('i:s') . '-' . $item['till']->format('i:s') . '   ';
        echo $item['count'] . '     ';
        echo $item['max'] . '   ';
        foreach ($item['items'] as $index => $sub_items) {
            echo rtrim(str_replace('2023-01-19 11:', '', $sub_items[0] . '-' . $sub_items[1]) . ', ', ', ');
        }
        echo "n";
    }
    

    Output:

    Period      Calls  Max  Items
    ----------------------------------------------------------------------------------------
    18:17-18:30   1     1  18:17-21:59
    18:30-18:58   2     2  18:17-21:59, 18:30-19:06
    18:58-19:06   3     3  18:17-21:59, 18:30-19:06, 18:58-20:04
    19:06-20:04   2     3  18:17-21:59, 18:58-20:04
    20:04-20:56   1     3  18:17-21:59
    20:56-21:18   2     3  18:17-21:59, 20:56-21:56
    21:18-21:26   3     3  18:17-21:59, 20:56-21:56, 21:18-24:42
    21:26-21:56   4     4  18:17-21:59, 20:56-21:56, 21:18-24:42, 21:26-22:02
    21:56-21:56   3     4  18:17-21:59, 21:18-24:42, 21:26-22:02
    21:56-21:59   4     4  18:17-21:59, 21:18-24:42, 21:26-22:02, 21:56-22:38
    21:59-22:02   3     4  21:18-24:42, 21:26-22:02, 21:56-22:38
    22:02-22:38   2     4  21:18-24:42, 21:56-22:38
    22:38-22:47   1     4  21:18-24:42
    22:47-23:40   2     4  21:18-24:42, 22:47-26:59
    23:40-24:42   3     4  21:18-24:42, 22:47-26:59, 23:40-24:58
    24:42-24:58   2     4  22:47-26:59, 23:40-24:58
    24:58-25:10   1     4  22:47-26:59
    25:10-25:46   2     4  22:47-26:59, 25:10-25:46
    25:46-25:51   1     4  22:47-26:59
    25:51-26:01   2     4  22:47-26:59, 25:51-27:57
    26:01-26:01   3     4  22:47-26:59, 25:51-27:57, 26:01-26:37
    26:01-26:19   4     4  22:47-26:59, 25:51-27:57, 26:01-26:37, 26:01-27:37
    26:19-26:37   5     5  22:47-26:59, 25:51-27:57, 26:01-26:37, 26:01-27:37, 26:19-26:55
    26:37-26:55   4     5  22:47-26:59, 25:51-27:57, 26:01-27:37, 26:19-26:55
    26:55-26:59   3     5  22:47-26:59, 25:51-27:57, 26:01-27:37
    26:59-27:23   2     5  25:51-27:57, 26:01-27:37
    27:23-27:35   3     5  25:51-27:57, 26:01-27:37, 27:23-28:59
    27:35-27:37   4     5  25:51-27:57, 26:01-27:37, 27:23-28:59, 27:35-27:47
    27:37-27:47   3     5  25:51-27:57, 27:23-28:59, 27:35-27:47
    27:47-27:57   2     5  25:51-27:57, 27:23-28:59
    27:57-28:26   1     5  27:23-28:59
    28:26-28:38   2     5  27:23-28:59, 28:26-28:38
    28:38-28:59   1     5  27:23-28:59
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search