Check if current time is between two times, with the possibility of lapping days
Asked Answered
T

2

5

I have a system that accepts user submissions, and upon receiving a submission the system will go through all timeslots to find the appropriate timeslot. The problem is that it needs to be able to check against the start & end times if the end time laps to the next day.

Take the following example: A timeslot begins at 10:30 PM on the current day and ends at 4:00 PM the next day. If the current time is between 10:30 PM and 11:59:59 PM, the submission will be assigned to that timeslot. However, if the current time is between 12:00 AM and 4:00 PM then it will skip the timeslot.

This is what I have so far:

function check_time($from, $to, $time) {
    $time = strtotime($time);
    $from = strtotime($from);
    $to_ = strtotime($to);
    $to = $to_ <= $from ? strtotime($to . " tomorrow") : $to_;
    return ($time >= $from && $time <= $to);
}

$timeslots = array(
    array("16:00:00", "22:30:00"),
    array("22:30:00", "16:00:00")
);
foreach ($timeslots as $slot) {
    if (check_time($slot[0], $slot[1], date("H:i:s")))
        {
            echo "true\n";
        }
    else 
        {
            echo "false\n";     
        }
}

If the current time is 23:00:00, then the result would be

false
true

But if the current time is 12:00:00 then the result would be

false
false

even though it's technically between the two times.

I know it has to do with the fact that if it's a new day, then the strtotime result for $from will be later in the day. So instead of checking for 10:30 PM yesterday, it checks for 10:30 PM tonight.

My problem is that I cannot seem to come up with a way to make the $from time switch to the previous day if it needs to, similar to how I force the $to time into the next day.

Trenton answered 17/6, 2013 at 8:45 Comment(2)
If dates are important, then why not add it to your times?Cuspidation
The times are dynamic. The timeslots are stored in a database and can be changed at the discretion of an administrator. We use it to split the submissions up so the people who review the submissions have an equal work load.Trenton
F
6

This is much easier than you expect. Assume that you have three times, t1, t2 and tn which represent from, to and user time respectively. Treat these times as six digit numbers (from 000000 to 235959) and check:

  • If t1 and t2 are present on the same side of midnight boundary
    • Check if tn lies between t1 and t2
  • Else
    • Check if tn does not lie between t2 and t1

Code and tests:

function check_time($t1, $t2, $tn) {
    $t1 = +str_replace(":", "", $t1);
    $t2 = +str_replace(":", "", $t2);
    $tn = +str_replace(":", "", $tn);
    if ($t2 >= $t1) {
        return $t1 <= $tn && $tn < $t2;
    } else {
        return ! ($t2 <= $tn && $tn < $t1);
    }
}
$tests = array(
    array("16:00:00", "22:30:00", "15:00:00"),
    array("16:00:00", "22:30:00", "16:00:00"),
    array("16:00:00", "22:30:00", "22:29:59"),
    array("16:00:00", "22:30:00", "22:30:00"),
    array("16:00:00", "22:30:00", "23:59:59"),
    array("22:30:00", "16:00:00", "22:29:59"),
    array("22:30:00", "16:00:00", "22:30:00"),
    array("22:30:00", "16:00:00", "15:59:59"),
    array("22:30:00", "16:00:00", "16:00:00"),
    array("22:30:00", "16:00:00", "17:00:00")
);
foreach($tests as $test) {
    list($t1, $t2, $t0) = $test;
    echo "$t1 - $t2 contains $t0: " . (check_time($t1, $t2, $t0) ? "yes" : "no") . "\n";
}
// OUTPUT
//
// 16:00:00 - 22:30:00 contains 15:00:00: no
// 16:00:00 - 22:30:00 contains 16:00:00: yes
// 16:00:00 - 22:30:00 contains 22:29:59: yes
// 16:00:00 - 22:30:00 contains 22:30:00: no
// 16:00:00 - 22:30:00 contains 23:59:59: no
// 22:30:00 - 16:00:00 contains 22:29:59: no
// 22:30:00 - 16:00:00 contains 22:30:00: yes
// 22:30:00 - 16:00:00 contains 15:59:59: yes
// 22:30:00 - 16:00:00 contains 16:00:00: no
// 22:30:00 - 16:00:00 contains 17:00:00: no
Fling answered 17/6, 2013 at 10:16 Comment(2)
Much appreciated, that's exactly what I was looking for. I hadn't even thought about converting the times to integers and comparing them as normal numbers. I guess I should get to sleep by midnight instead of worrying about checking if it is midnight.Trenton
Really appreciated. I was tired to find this solution several days. Php has really bad approaching for time manage.Live
R
1
function check_time($time, $threshold){
    $times = array(&$time, &$threshold);
    foreach($times as &$ts){
        if(!preg_match('~^([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$~', $ts)){
            return false;
        }
        $ts = intval(preg_replace('~[^0-9]+~', null, $ts));
    }
    return ($time >= $threshold) ? 2 : 1;
}

var_dump(check_time(date("H:i:s"), '12:00:00'));

I cheated! Let's follow the logic:

  • Any time can be converted to an integer if we remove the punctuation.
  • I removed the punctuation from the $time you want to test and made it an integer.
  • I've done the same thing to the $threshold which is the date that breaks spaces the slots.
  • This function just checks if the $time integer is before or after the $threshold.
  • It cares nothing about dates, tomorrow, time relativity and such.

If it fails (bad input) it returns false. If it succeeds it returns an integer: - 1 if before the threshold - 2 if after the threshold

Hope it fits your needs.

Roberson answered 17/6, 2013 at 9:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.