-2

I have an array called $timeslots with timeslots like:

array:32 [▼
  0 => "2018-12-15T12:00:00.0000000"
  1 => "2018-12-15T12:15:00.0000000"
  2 => "2018-12-15T12:30:00.0000000"
  3 => "2018-12-15T12:45:00.0000000"
  4 => "2018-12-15T13:00:00.0000000"
  5 => "2018-12-15T13:15:00.0000000"
  6 => "2018-12-15T13:45:00.0000000"
  7 => "2018-12-15T14:15:00.0000000"
  8 => "2018-12-15T14:30:00.0000000"
  9 => "2018-12-15T14:45:00.0000000"
  10 => "2018-12-15T15:00:00.0000000"
  11 => "2018-12-15T15:15:00.0000000"
  12 => "2018-12-15T15:30:00.0000000"
  13 => "2018-12-15T15:45:00.0000000"
  14 => "2018-12-15T16:15:00.0000000"
  15 => "2018-12-15T16:45:00.0000000"
  16 => "2018-12-15T17:00:00.0000000"
  17 => "2018-12-15T17:30:00.0000000"
  18 => "2018-12-15T17:45:00.0000000"
  19 => "2018-12-15T18:30:00.0000000"
  20 => "2018-12-15T18:45:00.0000000"
  21 => "2018-12-15T19:15:00.0000000"
  22 => "2018-12-15T19:45:00.0000000"
  23 => "2018-12-15T20:15:00.0000000"
  24 => "2018-12-15T20:45:00.0000000"
  25 => "2018-12-15T21:00:00.0000000"
  26 => "2018-12-15T21:15:00.0000000"
  27 => "2018-12-15T21:30:00.0000000"
  28 => "2018-12-15T21:45:00.0000000"
  29 => "2018-12-15T22:00:00.0000000"
  30 => "2018-12-15T22:15:00.0000000"
  31 => "2018-12-15T22:30:00.0000000"
]

Also, I have a variable like:

$expected_time = 2018-12-15T18:00:00.0000000; // this can be different value, so its not unique value

$expected_time is never into array $timeslots but I need to find closest value to $expected_time... How I can do that?

How I can get the closest timeslot value from array $timeslots to $expected_time and calculate the difference in minutes?

Any idea?

Aleks Per
  • 1,549
  • 7
  • 33
  • 68
  • 6
    What have you tried so far? It should be fairly simple to write a `foreach` loop and calculate the differences – Nico Haase Nov 13 '18 at 15:27
  • No, its not just the difference. I know to do that, problem is to find the closest value to give $expeted_time ... so $expected_time can be different each time – Aleks Per Nov 13 '18 at 15:29
  • As a hint, if you convert these values to timestamps you can then find which two in the array that the expected time is between. You can then pick the appropriate slot based on any criteria. – JonJ Nov 13 '18 at 15:31
  • Can you explain **why** it is no problem to compute the difference, but a problem to find the element with minimum distance? – Nico Haase Nov 13 '18 at 15:32
  • @JonJ give me nice idea with timestamp. THANKS A LOT! – Aleks Per Nov 13 '18 at 15:34
  • yes, once you have the timestamps, it's a simple loop to find the smallest absolute value of A-B. – Nosajimiki Nov 13 '18 at 15:36
  • https://stackoverflow.com/questions/15016725/how-to-get-closest-date-compared-to-an-array-of-dates-in-php – nforced Nov 13 '18 at 15:45

3 Answers3

3

As Nico mentioned in the comments, it's pretty straightforward. Just looping and calculating the time difference.

$timeslots = [...];
$expected_time = "2018-12-15T18:00:00.0000000";
$timestamp = strtotime($expected_time);
$diff = null;
$index = null;

foreach ($timeslots as $key => $time) {
    $currDiff = abs($timestamp - strtotime($time));
    if (is_null($diff) || $currDiff < $diff) {
        $index = $key;
        $diff = $currDiff;
    }
}

echo $timeslots[$index];
HTMHell
  • 5,761
  • 5
  • 37
  • 79
  • 1
    I would move the `strtotime($expected_time)` outside the loop and make it a variable. The way you do it you will parse the date 31 times more than needed based on the array in question. – Andreas Nov 13 '18 at 16:33
1

Here is one solution fitting your requirements:

function findClosestDate($expectedDate,$dates)
{

    $differenceInMinutes = null; 
    $expectedDate = new DateTime($expectedDate);
    $expectedDateEpoch = $expectedDate->getTimestamp();
    $returnIndex = -1;

    for($i = 0; $i<count($dates); $i++)
    {
        $dateObject = new DateTime($dates[$i]);
        $dateEpoch = $dateObject->getTimestamp();
        $difference = abs($expectedDateEpoch-$dateEpoch);
        $difference = $difference/60;
        if($differenceInMinutes === null || $difference < $differenceInMinutes)
        {
            $differenceInMinutes = $difference;
            $returnIndex = $i;
        }
    }

    return array(
        "closest" => $dates[$returnIndex],
        "difference" => $differenceInMinutes
    ) ;
}

This makes use of the DateTime class to create a DateTime object and get the respective timestamp. The minutes are then calculated by the absolute difference between the expectedDate and the entry in the dates array. After iterating over the whole array, the closest match and the difference is returned in one array.

maio290
  • 6,440
  • 1
  • 21
  • 38
1

as your list is already sorted - u can put the element into array and use sort again - and it will be much faster then calculating the diff in each iteration.

<?php
$timeslots = [
    ...
];

$expected_time = "2018-12-15T18:00:00.0000000";
$counter = count($timeslots);
$timeslots = array_flip($timeslots);
$timeslots[$expected_time] = $counter;
ksort($timeslots);

while (key($timeslots) !== $expected_time) {
    $prev = key($timeslots);
    next($timeslots);
}

next($timeslots);
$next = key($timeslots);

$expected_time = new \DateTime($expected_time);
$closestDiff = min(($expected_time)->diff(new \DateTime($prev)), (new \DateTime($next))->diff($expected_time));
var_dump($closestDiff->i);
myxaxa
  • 1,391
  • 1
  • 8
  • 7