>我的应用程序创建了一系列可能的事件(称为$internalEvents)
>我从日历中获取外部事件,例如Google Calendar,iCloud等(称为$externalEvents).这些是类型为busy的现有事件.
>现在我必须检查内部和外部事件是否存在任何冲突.我尝试了一些你可以在下面看到的东西,但这是迄今为止不正确或防弹的.
我试图尽可能地减少它.这是数据输入:
$internalEvents = array( array( "start" => "03/29/2016 12:00:00","end" => "03/29/2016 13:00:00" ),array( "start" => "03/29/2016 12:30:00","end" => "03/29/2016 13:30:00" ),array( "start" => "03/29/2016 13:00:00","end" => "03/29/2016 14:00:00" ),array( "start" => "03/29/2016 13:30:00","end" => "03/29/2016 14:50:00" ),array( "start" => "03/29/2016 14:00:00","end" => "03/29/2016 15:00:00" ),array( "start" => "03/29/2016 14:30:00","end" => "03/29/2016 15:30:00" ),array( "start" => "03/29/2016 15:00:00","end" => "03/29/2016 16:00:00" ),array( "start" => "03/29/2016 15:30:00","end" => "03/29/2016 16:30:00" ),array( "start" => "03/29/2016 16:00:00","end" => "03/29/2016 17:00:00" ) ); $externalEvents = array( array( "start" => "03/29/2016 08:00:00","end" => "03/29/2016 12:00:00","type" => "busy" ),"end" => "03/29/2016 16:00:00","end" => "03/29/2016 14:15:00","type" => "busy" ) );
现在我尝试通过将内部事件与所有外部事件进行比较来发现任何类型的冲突:
foreach($internalEvents as $internalEvent) { $internalEventStart = new DateTime($internalEvent['start']); $internalEventEnd = new DateTime($internalEvent['end']); $result = true; echo "\nverifying " . $internalEventStart->format('Y-m-d H:i') . " - " . $internalEventEnd->format('Y-m-d H:i') . "\n"; foreach($externalEvents as $externalEvent) { $externalEventStart = new DateTime($externalEvent['start']); $externalEventEnd = new DateTime($externalEvent['end']); // check if there are conflicts between internal and external events if ($internalEventStart >= $externalEventStart && $internalEventStart <= $externalEventEnd) { $result = false; echo " problem 1: event is between busy time: " . "\n"; } if ($internalEventStart >= $externalEventStart && $internalEventStart <= $externalEventEnd && $externalEventEnd <= $internalEventEnd) { $result = false; echo " problem 2: event starts during busy time: " . "\n"; } if ($internalEventStart <= $externalEventStart && $externalEventStart <= $internalEventEnd && $internalEventEnd <= $externalEventEnd) { $result = false; echo " problem 3: event stops during busy time: " . "\n"; } if (($internalEventStart <= $externalEventStart) && ($externalEventStart <= $externalEventEnd) && ($externalEventEnd <= $internalEventEnd)) { $result = false; echo " problem 4: event during busy time: " . "\n"; } if (($internalEventStart <= $internalEventEnd) && ($internalEventEnd <= $externalEventStart) && ($externalEventStart <= $externalEventEnd)) { $result = false; echo " problem 5: event during busy time: " . "\n"; } } if($result) { echo " result: OK\n"; } else { echo " result: NOT OK \n"; } }
我正在寻找一种可以找到任何可能的事件重叠冲突的算法.任何提示都受到高度赞赏.
解决方法
----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'],5 ) ); return $retval; }
此函数返回格式为“start”和“end”的关联数组.我在调试期间添加了第三个键“print”.请注意,在打印中我只考虑小时:分钟(数组样本中的所有日期都来自同一天),但比较是在完整日期进行的.您可以省略此“打印”键或将其替换为首选输出格式.
您执行两个嵌套的foreach,并为每个循环重新计算日期格式.使用数组样本,可以将DateTime / DateTime :: format调用36次.通过创建一个包含所有转换后的$externalEvents的临时数组,我们可以将这些调用减少到12.因此,在启动foreach()循环之前,我们使用带有上述自定义函数和$externalEvents数组的array_map来创建具有格式化日期的数组:
$externalDates = array_map( 'eventsToDate',$externalEvents );
然后,我们在$internalEvents上启动主要的foreach()循环:
foreach( $internalEvents as $internalEvent ) { $internalDates = eventsToDate( $internalEvent ); echo $internalDates['print'] . PHP_EOL; $result = True; foreach( $externalDates as $externalDate ) {
在这一点上,我们比较日期.如上所述,我们将start与end和end与start进行比较.为了简化下一个比较,我们使用strcmp,一个“返回<如果str1小于str2,则为0;如果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"; }
注意:通过上面的比较,使用第一个$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( $startCmp<=0 && $endCmp>=0 )
上面的代码可以使用,如果你想了解有关碰撞类型的更多细节,你可以在条件下测试其他开始/结束组合.
替代方案:返回碰撞事件
如果 – 而不是打印结果 – 你想要捕获碰撞事件,你可以用这种方式用array_filter替换嵌套的foreach():
$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()
>阅读更多关于array_map()
>阅读更多关于array_filter()
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。