两个日期范围重叠 - 1501 人缺少错误? [PHP]

Two dates range overlap - 1501 people missing bug? [PHP]

我写这个 post 是为了确定我是不是错了,或者没有人看到这里的错误。

为了确保我收集函数中的所有数据以显示结果并描述我的观点。

一切都很好,但是当我们分析所有日期组合时,我认为组合 6 和 7 中存在错误。Mb 它应该永远不会发生,但是当我们分析大量数据时,有一点我们不知道需要组合 6。

功能simulate_ranges是检查所有我们可以检查的可能性来检查答案是否正确。

函数 stack_overflow_answers - 从主题回答以检查结果。

结尾"for"是用所有组合检查所有答案

请取消评论其他案例以检查结果并告诉我: 我错了还是顶部 link 的主题对案例 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);
}

感谢@JustOnUnderMillions 快速而出色的回复!

更新 - 2017.04.06 13:20 - 添加案例 8 日期范围和@JustOnUnderMillions 计算。他的案子在所有情况下都运作良好。

当我们只输入这些日期范围时,@JustOnUnderMillions 计算是好的

    # 
$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);
    }

    # 
    $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;
                }
        }


}

我只有一个Note使用的复杂性:

这一切都是关于检查 daterangedaterange,因此所有名为 EndA StartA EndB 的东西都已连线。

我会先检查 日期是否在范围内。然后在使用之前对其进行排序,因此不需要 Charles Bretana - maybe all cases in once?

只需订购 dateranges,然后再详细查看。 如果您这样做了,一张支票会说明它们是否重叠。

DR = DateRange,1 = 早于 2,S = 开始,E = 结束

DR2S > DR1E = 无重叠(这里我们不重叠 >=

$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>';
    }
}

结果:

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

希望这可以简化主题。