2017-04-06 09:23

# 两个日期范围重叠 - 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 />';
}

#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'];
}
``````

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.

点赞 评论