dousi2029 2017-04-06 09:23
浏览 53
已采纳

两个日期范围重叠 - 1501人失踪? [PHP]

https://stackoverflow.com/questions/325933/determine-whether-two-date-ranges-overlap

I wrote this post to be sure am I wrong or no one saw the bug here.

To be sure I collect all the data in functions to show results and describe my point.

All was good but when we analise all combination of dates I think there is a bug in combination 6 & 7. Mb it should never happend but when we analise a lot of datas there is point where we don't know and combination 6 will needed.

Function simulate_ranges is to check all posibilities we can check to check the aswer is good or not.

Function stack_overflow_answers - answers from topic to check results.

Ending "for" is to check all answers with all combinations.

Please uncomment other cases to check results and tell me: Am I wrong or topic from top link have wrong math to case 6?

function simulate_ranges($case) {
switch($case)   {
    case 1:
        # A X Z B
        $a='2017-01-01';
        $b='2017-01-04';
        $x='2017-01-02';
        $z='2017-01-03';
        $combo=array('a' => $a,'x' => $x,'z' => $z,'b' => $b);
        $pair=array('a, b' =>$a.' - '.$b, 'x, z' => $x.' - '.$z);
        # ----- START A ------------------------------------------------------------------------------ START B ---  # 
        # -------------------------------- END X ------------------------ END Z -----------------------------------  #
        break;

    case 2:
        # A X B Z
        $a='2017-01-01';
        $b='2017-01-03';
        $x='2017-01-02';
        $z='2017-01-04';
        $combo=array('a' => $a,'x' => $x,'b' => $b,'z' => $z);
        $pair=array('a, b' =>$a.' - '.$b, 'x, z' => $x.' - '.$z);
        # ----- START A ------------------------------------------ START B ---------------------------------------  # 
        # -------------------------------- END X ----------------------------------------------- END Z ------------  #
        break;

    case 3:
        # X A Z B
        $a='2017-01-02';
        $b='2017-01-04';
        $x='2017-01-01';
        $z='2017-01-03';
        $combo=array('x' => $x,'a' => $a,'z' => $z,'b' => $b);
        $pair=array('a, b' =>$a.' - '.$b, 'x, z' => $x.' - '.$z);
        # -------------------------------------- START A --------------------------------------- START B ---------  # 
        # ---------- END X -------------------------------------- END Z -------------------------------------------  #
        break;

    case 4:
        # X A B Z
        $a='2017-01-02';
        $b='2017-01-03';
        $x='2017-01-01';
        $z='2017-01-04';
        $combo=array('x' => $x,'a' => $a,'b' => $b,'z' => $z);
        $pair=array('a, b' =>$a.' - '.$b, 'x, z' => $x.' - '.$z);
        # -------------------------------------- START A ---------------- START B --------------------------------  # 
        # ---------- END X -----------------------------------------------------------  ----------- END Z ---------  #
        break;

    case 5:
        # A B X Z
        $a='2017-01-01';
        $b='2017-01-02';
        $x='2017-01-03';
        $z='2017-01-04';
        $combo=array('a' => $a,'b' => $b,'x' => $x,'z' => $z);
        $pair=array('a, b' =>$a.' - '.$b, 'x, z' => $x.' - '.$z);
        # --------- START A ---------  --------- START B --------- # # ----------------------- ----------------------------------------  # 
        # ---------------------------------------------------------------- #  # ---------- END X -----------  ----------- END Z ---------  #
        break;

    case 6:
        # X Z A B
        $a='2017-01-03';
        $b='2017-01-04';
        $x='2017-01-01';
        $z='2017-01-02';
        # ---------- END X -----------  ----------- END Z ---------  # # ---------------------------------------------------------------- # 
        # ----------------------- ----------------------------------------  # # --------- START A ---------  --------- START B --------- #
        $combo=array('x' => $x,'z' => $z,'a' => $a,'b' => $b);
        $pair=array('a, b' =>$a.' - '.$b, 'x, z' => $x.' - '.$z);
        break;

    case 7:
        # A B X Z
        $a='2017-01-01';
        $b='2017-01-02';
        $x='2017-01-02';
        $z='2017-01-03';
        # --------- START A ---------  --------|- START B -|----------------------------------------------  # 
        # -----------------------------------------|-- END X ---|-------------------------- END Z ---------  #
        $combo=array('a' => $a,'b' => $b,'x' => $x,'z' => $z);
        $pair=array('a, b' =>$a.' - '.$b, 'x, z' => $x.' - '.$z);
        break;

case 8:
    # X Z A B
    $a='2017-01-01 01:00:00';
    $b='2017-01-02 00:00:00';
    $x='2017-01-01 00:00:01';
    $z='2017-01-01 01:00:00';

    # --------- END X ---------  --------|- START A -|----------------------------------------------  # 
    # -----------------------------------------|-- END Z ---|-------------------------- START B ---------  #
    $combo=array('x' => $x,'a' => $a, 'z' => $z,'b' => $b);
    $pair=array('a, b' =>$a.' - '.$b, 'x, z' => $x.' - '.$z);
    break;

}

$a2=strtotime($a);
$b2=strtotime($b);
$x2=strtotime($x);
$z2=strtotime($z);

echo '<table>';
foreach($combo as $var => $data)    {
    $strtotime=${$var.'2'};
    switch($var)        {
        case 'a': $final_var='StartA'; break;
        case 'b': $final_var='StartB'; break;
        case 'x': $final_var='EndA'; break;
        case 'z': $final_var='EndB'; break;
    }
    echo '<tr><td style="text-align: right;"> ('.$final_var.') </td><td>&rarr; '.$data.'</td><td> ('.$strtotime.')</td></tr>';
}
echo '</table>';

echo '<table><tr>';
$i=0;
foreach($pair as $vars => $dates_ranges)    {
    switch($vars)       {
        case 'a, b': $final_vars='StartA, StartB'; break;
        case 'x, z': $final_vars='EndA, EndB'; break;
    }
    echo '<td style="text-align: right;"> ('.$dates_ranges.') </td>';
    if(empty($i)) { 
        echo '<td>&larr;&rarr;</td>'; 
    }
    $i=1;
}
echo '</tr></table>';

return array('a' => $a2, 'b' => $b2, 'x' => $x2, 'z' => $z2);
}

function result($result) {
if($result) {
    echo '<span style="background: green; color: white; padding: 1px 10px;">Dates match</span>';
}
else {
    echo '<span style="background: red; color: white; padding: 1px 10px;">Dates <b>NOT</b> match</span>';
}
echo '<hr />';
}

function stack_overflow_answers($case,$a,$b,$x,$z) {
#StartA -> a 
#StartB -> b
#EndA -> x
#EndB -> z
echo '<br />';
switch($case)
{
    case 'Charles Bretana - first':

        echo '<b>(StartA <= EndB) and (StartB <= EndA) and (StartA <= EndA) and (StartB <= EndB)</b><br />';
        if( ( ($a <= $z) && ($b <= $x) && ($a <= $x) && ($b <= $z) ) )
            result(false);
        else
            result(true);
        break;

    case 'Charles Bretana - second':

        echo '<b>(StartA <= EndB) and (StartA <= EndA) and (StartB <= EndA) and (StartB <= EndB)</b><br />';
        if(  ($a <= $z) && ($a <= $x) && ($b <= $x) && ($b <= $z)  )
            result(false);
        else
            result(true);
        break;

    case 'Charles Bretana - third':

        echo '<b>(StartA <= Min(EndA, EndB) and (StartB <= Min(EndA, EndB))</b> &rarr; Missing bracket?<br />';
        if(  $x <= Min($x, $z) && ( $b <= Min($x, $z) ) )
            result(false);
        else
            result(true);
        break;

    case 'Charles Bretana - fourth':

        echo '<b>(Max(StartA, StartB) <= Min(EndA, EndB)</b> &rarr; Missing bracket too?<br />';
        if(  Max($a, $b) <= Min( $x, $z) )
            result(false);
        else
            result(true);
        break;

    case 'Charles Bretana - maybe all cases in once?':

        echo '<b>(StartA <= EndB) and (StartB <= EndA) and (StartA <= EndA) and (StartB <= EndB)<br />';
        echo '(StartA <= EndB) and (StartA <= EndA) and (StartB <= EndA) and (StartB <= EndB)<br />';
        echo '(StartA <= Min(EndA, EndB) and (StartB <= Min(EndA, EndB))<br />';
        echo '(Max(StartA, StartB) <= Min(EndA, EndB)<br />';
        echo '</b><br />';
        if( 
               ( ($a <= $z) && ($b <= $x) && ($a <= $x) && ($b <= $z) ) 
            || ( ($a <= $z) && ($a <= $x) && ($b <= $x) && ($b <= $z)  )
            || ( $x <= Min($x, $z) && ( $b <= Min($x, $z) ) )
            || ( Max($a, $b) <= Min( $x, $z) )
        )
            result(false);
        else
            result(true);
        break;

    case 'Charles Bretana - using C':

        echo '<b>(StartA > StartB? Start A: StartB) <= (EndA < EndB? EndA: EndB)</b><br />';
            $result=($a > $b? $a: $b) <= ($x < $z? $x: $z);
            if($result === false)
                result( true  );
            else
                result( false );

        break;

    case 'Ian Nelson':

        echo '<b>(StartDate1 <= EndDate2) and (StartDate2 <= EndDate1)</b><br />';
        if( 
                ($a <= $z) && ($b <= $x)

        )
            result(false);
        else
            result(true);
        break;

    case 'First Good Solution? Almost':
        echo '<b>Min(StartA, StartB) >= Max(EndA, EndB) OR Max(StartA, StartB) <= Min(EndA, EndB)</b><br />';
        if( ( Min($a, $b) >= Max($x, $z) ) ||  ( Max($a, $b) <= Min($x, $z) )    
                && $a !== $x
                && $b !== $x
                && $a !== $z
                && $b !== $z
            )
            result(false);
        else
            result(true);

        break;

    case 'JustOnUnderMillions':
        echo '<b>Simplyfy function sort before</b><br />';
        $ranges = array(
                    array(array($a,$b),array($x,$z)),
            );
            foreach($ranges as $set){
                    //to change the order of the ranges for testing
                    shuffle($set);
                    //now order it
                    usort($set,function($a,$b){
                             if ($a[0] == $b[0]) { return 0; }
                             return ($a[0] < $b[0]) ? -1 : 1;
                    });
                    //test DR2S > DR1E no overlap
                    if($set[1][0] > $set[0][1]){
                            result(false);
                    } else {
                            result(true);
                    }
            }

            break;
}
}

for($i=1; $i <= 8; $i++) {
$case='Charles Bretana - first';
// $case='Charles Bretana - second';
//  $case='Charles Bretana - third';
//  $case='Charles Bretana - fourth';
//  $case='Charles Bretana - maybe all cases in once?';
//  $case='Charles Bretana - using C';
//  $case='Ian Nelson';
//  $case='First Good Solution? Almost';
//  $case='JustOnUnderMillions';


if($i === 1) { echo '<hr />Case <span style="color: blue;">'.$case.'</span><hr />'; }
echo 'Combination  <span style="color: red;">'.$i.'</span><br />';
$temp=simulate_ranges($i);
$a = $temp['a'];
$b = $temp['b'];
$x = $temp['x'];
$z = $temp['z'];
 stack_overflow_answers($case,$a,$b,$x,$z);
}

Thanks for @JustOnUnderMillions for fast and great response!

UPDATED - 2017.04.06 13:20 - added case 8 date range and @JustOnUnderMillions calculation. His case is working good in all cases.

When we put those date ranges only @JustOnUnderMillions calculate is good

    # https://stackoverflow.com/questions/43250973/two-dates-range-overlap-1501-people-missing-bug-php
$time_min='2017-01-01 01:00:00';
$time_max='2017-01-02 00:00:00';
$time_checked_min='2017-01-01 00:00:01';
$time_checked_max='2017-01-01 01:00:00';

var_dump( checkRangeBetweenRange( $time_min, $time_max, $time_checked_min, $time_checked_max ) );

function checkRangeBetweenRange( $time_min, $time_max, $time_checked_min, $time_checked_max, $convert_date=true ){
    # convert date time
    if($convert_date)   {
        $time_min=strtotime($time_min);
        $time_max=strtotime($time_max);
        $time_checked_min=strtotime($time_checked_min);
        $time_checked_max=strtotime($time_checked_max);
    }

    # https://stackoverflow.com/questions/43250973/two-dates-range-overlap-1501-people-missing-bug-php
    $ranges = array(
                array(array($time_min,$time_max),array($time_checked_min,$time_checked_max)),
        );
        foreach($ranges as $set){
                //to change the order of the ranges for testing
                shuffle($set);
                //now order it
                usort($set,function($a,$b){
                         if ($a[0] == $b[0]) { return 0; }
                         return ($a[0] < $b[0]) ? -1 : 1;
                });
                //test DR2S > DR1E no overlap
                if($set[1][0] > $set[0][1]){
                        return false;
                } else {
                        return true;
                }
        }


}
  • 写回答

1条回答 默认 最新

  • doutang7415 2017-04-06 10:12
    关注

    I have only a Note to complexity used:

    It is all about check a daterange against daterange, so all the stuff called EndA StartA EndB is wired.

    I would first check witch date is earlier in range. And then sort it before using it, so the Charles Bretana - maybe all cases in once? is not needed.

    Just order the dateranges before check them in detail. If you have done this, one single check will say if they overlap or not.

    DR = DateRange , 1 = earlier start than 2, S = start , E = End

    DR2S > DR1E = No Overlap (here we dont do >=)

    $ranges = array(
        //only non overlap
        array(array('2017-01-01','2017-01-02'),array('2017-01-03','2017-01-04')),
        //rest overlapping
        array(array('2017-01-01','2017-01-02'),array('2017-01-02','2017-01-04')),
        array(array('2017-01-01','2017-01-02'),array('2017-01-01','2017-01-04')),
        array(array('2017-01-01','2017-01-03'),array('2017-01-03','2017-01-04')),
    );
    foreach($ranges as $set){
        //to change the order of the ranges for testing
        shuffle($set);
        //now order it
        usort($set,function($a,$b){
             if ($a[0] == $b[0]) { return 0; }
             return ($a[0] < $b[0]) ? -1 : 1;
        });
        //show 
        print implode(' - ',$set[0]).' vs '.implode(' - ',$set[1]);
        //test DR2S > DR1E no overlap
        if($set[1][0] > $set[0][1]){
            print ' NO OVERLAP<br>';
        } else {
            print ' OVERLAP<br>';
        }
    }
    

    Results:

    2017-01-01 - 2017-01-02 vs 2017-01-03 - 2017-01-04 NO OVERLAP

    2017-01-01 - 2017-01-02 vs 2017-01-02 - 2017-01-04 OVERLAP

    2017-01-01 - 2017-01-04 vs 2017-01-01 - 2017-01-02 OVERLAP

    2017-01-01 - 2017-01-03 vs 2017-01-03 - 2017-01-04 OVERLAP

    Hopefully this simplifies the topic a little bit.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 素材场景中光线烘焙后灯光失效
  • ¥15 请教一下各位,为什么我这个没有实现模拟点击
  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置
  • ¥15 有没有研究水声通信方面的帮我改俩matlab代码
  • ¥15 ubuntu子系统密码忘记
  • ¥15 保护模式-系统加载-段寄存器