【问题标题】:Issue with PHP foreach loop on overlapping datetimes重叠日期时间上的 PHP foreach 循环问题
【发布时间】:2015-08-23 05:15:15
【问题描述】:

数据摘要


我有以下数据,现有事件的 $existing_events 数组和新事件的请求($requested_start$requested_end)。通常从 SQL 中提取,但我在这里用静态数组复制了这个问题:

$existing_events = array(
    0   => array(
        'time_start' => '2015-09-05 11:30:00',
        'time_end'   => '2015-09-05 18:45:00'
    ),
    1   => array(
        'time_start' => '2015-09-05 07:15:00',
        'time_end'   => '2015-09-05 10:30:00'
    )
);

$requested_start    =   strtotime('2015-09-05 3:30:00 AM');
$requested_end  =   strtotime('2015-09-05 9:30:00 AM');

结果数组


一个$results 数组,用于跟踪进行了多少次比较('comparison_counter')以及发现了多少冲突('conflicts'):

$results = array(
    'conflicts' => 0,
    'comparison_counter' => 0
);

FOREACH 循环


最后,在输出 json_encode 的结果之前,foreach 循环使用this logic 将请求的新事件的开始和结束时间与每个预先存在的事件的开始和结束时间进行比较。注意comparison_counterconflict 的增量——前者在每次循环运行时运行,而后者仅在其 if 语句中“到达”,当请求的事件时间和当前事件时间之间存在冲突时经过测试。

if (!empty($existing_events)){
    foreach ($existing_events as $existing_event){
        $existing_start = strtotime($existing_event['time_start']);
        $existing_end = strtotime($existing_event['time_end']);
        $results['comparison_counter']++;
        if ($requested_start > $existing_end) {
            break;
        } elseif ($requested_end < $existing_start) {
            break;
        } else {
            $results["conflicts"]++;
        }
    }
}

echo json_encode($results);
exit;

实际反应


不过,我收到的信息表明 foreach 循环似乎只执行了一次,尽管我的 $existing_events 数组中有两个项目。以下是我收到的上述数据:

comparison_counter: 1
conflicts: 0

对比我的期望:

comparison_counter: 2
conflicts: 1

奇怪的是,只要我对 11:30 start-time 进行以下更改(以尝试与 both 事件重叠):

$requested_end  =   strtotime('2015-09-05 11:30:00 AM');

...comparison_counter 现在可以使用了。我现在收到以下信息:

comparison_counter: 2
conflicts: 2

我的问题


根据我传递的数组中的内容,为什么 foreach 循环不能正常运行?我希望它每次触发时至少会击中它的$results['comparison_counter']++;

【问题讨论】:

  • $requested_start 和 $requested_end 的值具体是什么?我认为您的比较不会达到您的预期。
  • @SetSailMedia - 正在提交的表单数据,然后是 strtotime'd...在这种情况下:requested_start: 1441423800 requested_end: 1441452600
  • 它们是日期/时间戳,还是数字 time() 值? nvm 刚刚看到你的编辑
  • 第一个查询不是处理所有这些吗(嗯,稍微调整一下)?我不明白第二个查询的意义
  • @Strawberry 你是对的,它可能会。由于我最初拥有完整日期时间格式的两种格式,我想我会先比较这种方式,然后直接通过引用修改数组。为了隔离问题,我们可能会忘记第二个 foreach 循环的存在。第一个是否存在问题,当只有第二个现有事件发生冲突时,它不会抛出冲突标志?谢谢!

标签: php mysql loops foreach


【解决方案1】:

我认为这可能是您正在寻找的:

if (!empty($results['same_day'])){
    foreach ($results['same_day'] as $same_day){
        $exist_start = strtotime($same_day->time_start);
        $exist_end = strtotime($same_day->time_end);
        // Check if new meeting plans to start during existing meeting
        if ( ($requested_start > $exist_start) && ($requested_start < $exist_end) ) {
            $results["conflicts"]++;
            break;
        }
        // Check if new meeting plans to end during existing meeting
        if ( ($requested_end > $exist_start) && ($requested_end < $exist_end) ) {
            $results["conflicts"]++;
            break;
        }
        // Check if existing meeting starts during new meeting
        if ( ($exist_start > $requested_start) && ($exist_start < $requested_end) ) {
            $results["conflicts"]++;
            break;
        }
        // Check if existing meeting ends during new meeting
        if ( ($exist_end > $requested_start) && ($exist_end < $requested_end) ) {
            $results["conflicts"]++;
            break;
        }
    }
}

我用来测试的完整代码:

<?php

$a = new stdClass();
$b = new stdClass();

$a->time_start = "2015-09-05 11:30:00";
$a->time_end = "2015-09-05 18:45:00";

$b->time_start = "2015-09-05 07:15:00";
$b->time_end = "2015-09-05 10:30:00";

$results['same_day'] = array( $a, $b );
$results['conflicts'] = 0;

$requested_start = strtotime( "2015-09-05 03:00" );
$requested_end = strtotime( "2015-09-05 11:00" );


if (!empty($results['same_day'])){
    foreach ($results['same_day'] as $same_day){
        $exist_start = strtotime($same_day->time_start);
        $exist_end = strtotime($same_day->time_end);
        // Check if new meeting plans to start during existing meeting
        if ( ($requested_start > $exist_start) && ($requested_start < $exist_end) ) {
            $results["conflicts"]++;
            break;
        }
        // Check if new meeting plans to end during existing meeting
        if ( ($requested_end > $exist_start) && ($requested_end < $exist_end) ) {
            $results["conflicts"]++;
            break;
        }
        // Check if existing meeting starts during new meeting
        if ( ($exist_start > $requested_start) && ($exist_start < $requested_end) ) {
            $results["conflicts"]++;
            break;
        }
        // Check if existing meeting ends during new meeting
        if ( ($exist_end > $requested_start) && ($exist_end < $requested_end) ) {
            $results["conflicts"]++;
            break;
        }
    }
}

var_dump( $results );

?>

【讨论】:

  • 欣赏这个建议!供参考,这里是the logic behind my "start-after OR end-before" approach。我觉得这应该适用于这种情况,因为我一次只将一个现有事件与一个提议的事件进行比较。对此有什么想法?
  • @cdwyer 是有道理的,但是您的 if() elseif() 块不会将一个和另一个一起比较。它分别比较一个或另一个,这就是它没有失败的原因(报告冲突)。
  • 认为我对这个块的作用的书面总结是正确的,因为这些比较应该是排他性的,因为你只需要一个来验证你'很清楚。像这样: (( 1. )) 首先,如果请求的开始出现在现有的结束之后,那没问题。新事件直到另一端才会开始,因此新事件的结束时间无关紧要。 (( 2. )) 其次,如果请求的结束在现有开始之前,那你没问题。新事件将在现有事件开始之前结束,因此新事件开始时间无关紧要。 (( 3. )) 如果两者都是假的,那么一定有重叠的地方。
  • 另外,我几乎彻底检查了我上面的问题。将问题(我认为)隔离到 foreach 本身,而不是内部发生的事情。 comparison_counter 没有显示两个循环,尽管传递给 foreach does 的数组有两个项目。如果您对此有其他想法,请告诉我!
  • 你试过我的代码了吗?它不会产生预期的结果吗?
【解决方案2】:

这应该是一个比以前更直接的认识。如果你使用break,你基本上是在说“我找到了我想要的,完全退出 foreach”。如果您使用continue,它只会退出当前迭代(据我所知)并继续(看看他们做了什么,在那里?)到下一个迭代。发现 this "diagram" 很好地解释了它,并且似乎适用于 foreach 循环,而不仅仅是 while

while ($foo) {   <--------------------┐
    continue;    --- goes back here --┘
    break;       ----- jumps here ----┐
}                                     |
                 <--------------------┘

希望这对其他人有所帮助!

【讨论】:

    猜你喜欢
    • 2015-09-21
    • 2020-01-07
    • 2021-12-27
    • 2018-03-03
    • 1970-01-01
    • 1970-01-01
    • 2013-12-10
    • 1970-01-01
    • 2014-05-13
    相关资源
    最近更新 更多