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 uniapp uview http 如何实现统一的请求异常信息提示?
  • ¥15 有了解d3和topogram.js库的吗?有偿请教
  • ¥100 任意维数的K均值聚类
  • ¥15 stamps做sbas-insar,时序沉降图怎么画
  • ¥15 买了个传感器,根据商家发的代码和步骤使用但是代码报错了不会改,有没有人可以看看
  • ¥15 关于#Java#的问题,如何解决?
  • ¥15 加热介质是液体,换热器壳侧导热系数和总的导热系数怎么算
  • ¥100 嵌入式系统基于PIC16F882和热敏电阻的数字温度计
  • ¥20 BAPI_PR_CHANGE how to add account assignment information for service line
  • ¥500 火焰左右视图、视差(基于双目相机)