2016-03-24 8 views
4

外部イベントが内部イベント(カレンダーアプリ)と衝突するかどうかをチェックする機能を開発中です。プロセスは次のようになります。PHPを使用してカレンダーイベントのオーバーラップの競合を検出しました

  • 私のアプリケーションは($externalEventsと呼ばれる)($internalEventsと呼ばれる)可能性のあるイベントなど、Googleカレンダー、iCloudの、などのカレンダーから
  • Iソース外部イベントの配列を作成します。これらは、タイプ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" 
    ), 
    array(
     "start" => "03/29/2016 15:30:00", 
     "end" => "03/29/2016 16:00:00", 
     "type" => "busy" 
    ), 
    array(
     "start" => "03/29/2016 13:30: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"; 
    } 
} 

私はあらゆる可能性を見つけることができるアルゴリズムを探していますイベント重複の競合。どんなヒントも高く評価されます。

実行コードはhere(IDEone.com)です。

+0

あなたの実際のコードが動作しますか?私は出力する時間を追加して、それは私のために一貫していないようです。この[pastebin](http://pastebin.com/LHiFMz9z)の私の結果をチェックしてください:私は曖昧な結果を「≈」とマークし、「≠」は正しい結果を表示していません。代わりに、結果が正しい場合は、衝突基準をよりよく説明できますか?私は重複している場合は衝突があることを意図した...私に教えてください。 – fusion3k

+0

@ fusion3kこれは以前は一連のイベントで作業していましたが、イベントを変更したときには実際には機能しないと認識しました。だからこそ私はコミュニティの助けが必要です。あなたの発見は正しいようです。 – doonot

答えて

3

2つのイベントが衝突すると、

       ----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'を含む連想配列を返します。デバッグ時に使用する3番目のキー 'print'を追加しました。このプリントでは、数時間(配列サンプルのすべての日付は同じ日からのものです)と考えていますが、完全な日付で比較しています。この 'print'キーを省略するか、優先出力形式に置き換えることができます。

ネストした2つのコードforeachを実行し、ループごとに日付形式を再計算します。配列サンプルでは、​​DateTime/DateTime :: formatを36回呼び出します。

$externalDates = array_map('eventsToDate', $externalEvents); 

$externalEventsを変換し、すべてで一時配列を作成することにより、我々はforeach()ループを開始する前に、我々は、フォーマットされた日付を持つ配列を作成するために、上記のカスタム関数と$externalEvents配列でarray_mapを使用するので、12にこれらの呼び出しを減らすことができますその後、我々は$internalEventsにメインforeach()ループを開始します。

foreach($internalEvents as $internalEvent) 
{ 
    $internalDates = eventsToDate($internalEvent); 

    echo $internalDates['print'] . PHP_EOL; 
    $result = True; 
    foreach($externalDates as $externalDate) 
    { 

をこの時点で、我々は日付を比較します。上で述べたようにstartとendをstartとendを比較します。「彼らが等しい場合str1がstr2のより大きく、0の場合str1がstr2の未満の場合戻り< 0、> 0」という次の比較、我々はstrcmpを使用し、PHPの機能を簡素化するために:今

 $startCmp = strcmp($internalDates['start'], $externalDate['end']); 
     $endCmp = strcmp($internalDates['end'], $externalDate['start'] ); 

を、比較:

echo "Result: " . ($result ? 'OK' : 'NOT OK') . "\n\n"; 
} 

 if($startCmp<0 && $endCmp>0) 
     { 
      $result = False; 
      echo "   {$externalDate['print']} COLLIDE\n"; 
     } 
     else 
     { 
      echo "   {$externalDate['print']} OK\n"; 
     } 
    } 

とは、最後に、我々は結果を印刷することができます

注:この結果たい場合

代わり
12:00-13:00 
      08:00-12:00 OK 
      15:30-16:00 OK 
      13:30-14:15 OK 
Result: OK 

、::上記の比較で、最初の$internalEventで、我々は次のような結果を得る

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内の開始/終了の他の組み合わせをテストできます。


オルタナティブ:場合はイベント

を衝突返す代わりに - 印刷結果の - あなたが衝突したイベントをキャッチしたい、あなたはこの方法で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にあります。明らかに、配列は空であり、衝突はない。


+0

fusion3kありがとうございました!慎重に勉強する時間が必要だけど、それはすごいよ!私はあなたに戻ってきます – doonot

関連する問題