当两个事件发生碰撞时?请参阅此架构:
----E---- CS/EE CE/ES
--N-- < <
--N-- > >
--C-- < >
--C-- < >
--C-- < >
-----C----- < >
··················································
E = Main Event
N = Not Collide Event
C = Collide Event
CS = Compare Event Start
EE = Main Event End
CE = Compare Event End
ES = Main Event Start
正如您所看到的,只有当事件 C 的开始早于事件 E 的结束并且事件 E 的结束晚于事件 C 的开始时,才会发生冲突。了解这一点有助于找到一种高效且简短的方法来比较事件。
关于代码,初步说明:您在代码中多次比较日期之前先转换 ISO 8601 中的日期,那么为什么不为此创建一个函数呢?
function eventsToDate( $row )
{
$retval = array( 'start' => date_create( $row['start'] )->format('Y-m-d H:i:s'), 'end' => date_create( $row['end'] )->format('Y-m-d H:i:s') );
$retval['print'] = sprintf( '%s-%s', substr( $retval['start'],-8,5 ), substr( $retval['end'],-8,5 ) );
return $retval;
}
此函数返回一个以您的格式包含“start”和“end”的关联数组。我添加了第三个键“打印”,以在调试期间使用。请注意,在打印中我只考虑小时:分钟(数组样本中的所有日期都来自同一天),但比较是在完整日期上进行的。您可以省略此“打印”键或将其替换为首选输出格式。
你执行两个嵌套的foreach
,并为每个循环重新计算日期格式。对于数组样本,您调用 DateTime/DateTime::format 36 次。通过创建一个包含所有已转换的临时数组$externalEvents
,我们可以将这些调用减少到 12 个。所以,在开始之前foreach()
循环,我们使用array_map
具有上述自定义功能和$externalEvents
array 创建具有格式化日期的数组:
$externalDates = array_map( 'eventsToDate', $externalEvents );
然后我们开始主要的foreach()
循环播放$internalEvents
:
foreach( $internalEvents as $internalEvent )
{
$internalDates = eventsToDate( $internalEvent );
echo $internalDates['print'] . PHP_EOL;
$result = True;
foreach( $externalDates as $externalDate )
{
此时,我们比较日期。如上所述,我们比较 start 与 end 以及 end 与 start。为了简化接下来的比较,我们使用strcmp
,一个 php 函数,“如果 str1 小于 str2,则返回 0;如果相等,则返回 0”:
$startCmp = strcmp( $internalDates['start'], $externalDate['end'] );
$endCmp = strcmp( $internalDates['end'], $externalDate['start'] );
现在,比较一下:
if( $startCmp<0 && $endCmp>0 )
{
$result = False;
echo " {$externalDate['print']} COLLIDE\n";
}
else
{
echo " {$externalDate['print']} OK\n";
}
}
最后,我们可以打印结果:
echo "Result: " . ( $result ? 'OK' : 'NOT OK') . "\n\n";
}
eval.in demo https://eval.in/541934
注:与上面的比较,与第一个$internalEvent
我们得到以下结果:
12:00-13:00
08:00-12:00 OK
15:30-16:00 OK
13:30-14:15 OK
Result: OK
相反,如果你想要这个结果:
12:00-13:00
08:00-12:00 COLLIDE
15:30-16:00 OK
13:30-14:15 OK
Result: NOT OK
你必须更换上面if
条件与此:
if( $startCmp<=0 && $endCmp>=0 )
上面的代码可以工作,如果您想了解有关碰撞类型的更多详细信息,您可以在内部测试开始/结束的其他组合if
健康)状况。
替代方案:返回碰撞事件
如果您想要捕获碰撞事件而不是打印结果,则可以替换嵌套foreach()
with array_filter
这样:
$result = array_filter
(
$externalDates,
function( $row ) use( $internalDates )
{
$startCmp = strcmp( $internalDates['start'], $row['end'] );
$endCmp = strcmp( $internalDates['end'], $row['start'] );
return( $startCmp<0 && $endCmp>0 );
}
);
此时,碰撞事件已在数组中$result
。显然,如果数组为空,则不存在碰撞。
- 阅读更多关于strcmp() http://php.net/manual/en/function.strcmp.php
- 阅读更多关于数组映射() http://php.net/manual/en/function.array-map.php
- 阅读更多关于数组过滤器() http://php.net/manual/en/function.array-filter.php