5

我有一个接受用户提交的系统,在收到提交后,系统将遍历所有时间段以找到合适的时间段。问题是,如果结束时间跨到第二天,它需要能够检查开始和结束时间。

举个例子:时间段从当天晚上 10:30 开始,到第二天下午 4:00 结束。如果当前时间在晚上 10:30 到晚上 11:59:59 之间,则提交将被分配到该时间段。但是,如果当前时间在上午 12:00 到下午 4:00 之间,那么它将跳过时间段。

这是我到目前为止所拥有的:

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";     
        }
}

如果当前时间是 23:00:00,那么结果将是

false
true

但是如果当前时间是 12:00:00 那么结果将是

false
false

即使它在技术上介于两次之间。

我知道这与这样一个事实有关,如果这是新的一天,那么strtotime结果$from将在当天晚些时候。因此,它不是检查昨天晚上 10:30,而是检查今晚晚上 10:30。

我的问题是,如果需要,我似乎无法想出一种将$from时间切换到前一天的方法,类似于我将$to时间强制到第二天的方式。

4

2 回答 2

8

这比您预期的要容易得多。假设您有 3 个时间,t1t2分别tn代表从、到和用户时间。将这些时间视为六位数字(从 000000 到 235959)并检查:

  • 如果t1t2出现在午夜边界的同一侧
    • 检查是否介于和tn之间t1t2
  • 别的
    • 检查是否tn不在t2和之间t1

代码和测试:

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
于 2013-06-17T10:16:18.300 回答
2
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.

于 2013-06-17T09:09:14.800 回答