检查重叠的日期范围(开始和结束日期)

时间:2014-12-22 20:15:19

标签: php validation date loops

function checkDateOverlap($ranges) {
    $res = $ranges[0];
    $countRanges = count($ranges);

    for ($i = 0; $i < $countRanges; $i++) {

        $r1s = $res['start'];
        $r1e = $res['end'];

        $r2s = $ranges[$i]['start'];
        $r2e = $ranges[$i]['end'];

        if ($r1s >= $r2s && $r1s <= $r2e || $r1e >= $r2s && $r1e <= $r2e || $r2s >= $r1s && $r2s <= $r1e || $r2e >= $r1s && $r2e <= $r1e) {
            $res = array(
                'start' => $r1s > $r2s ? $r1s : $r2s,
                'end' => $r1e < $r2e ? $r1e : $r2e
            );
        } else 
            return false;
    }
    return $res;
}
// example of returned dates that overlap
$ranges = array(
    array('start' => '2014-01-01', 'end' => '2014-01-04'),
    array('start' => '2014-01-05', 'end' => '2014-01-10'),
    array('start' => '2014-01-04', 'end' => '2014-01-07')
);
//example of failure
$ranges2 = array(
        array('start' => '2014-01-01', 'end' => '2014-01-04'),
        array('start' => '2014-01-05', 'end' => '2014-01-10'),
        array('start' => '2014-01-11', 'end' => '2014-01-17')
    );

var_dump(checkDateOverlap($ranges));

以下是我试图检查日期范围的交叉点。在数组“ranges1”中,此示例具有重叠日期。它应该返回日期。在数组$ ranges2中,这应该作为没有相交的日期传递。

现在奇怪的是,开始和结束日期可以完全相同,所以你可以在一天内完成一个条目。我尝试了很多东西,我很难过。

我认为需要另一个for循环,但不管我没有取得成功。

这是另一回事:

<?php

//将范围传递给此方法,如果存在共同的交叉点,它将会 //返回或错误

function checkDateOverlap($ranges){
    $res = $ranges[0];
    $countRanges = count($ranges);
    for ($i = 0; $i < count($countRanges); $i++) {
        for($j = $i+1; $j < count($countRanges); $j++) {
            $r1s = $res['start'];
            $r1e = $res['end'];

            $r2s = $ranges[$i]['start'];
            $r2e = $ranges[$i]['end'];

            if (($r1s >= $r2e && $r2s <= $r1e)) {

                $res[] = array(
                    'start' => $r1s > $r2s ? $r1s : $r2s,
                    'end' => $r1e < $r2e ? $r1e : $r2e
                );

            } else 
                return false;
        }
    }
    return $res;
}

// example
$ranges = array(
    array('start' => '2014-01-04', 'end' => '2014-01-05'),
    array('start' => '2014-01-06', 'end' => '2014-01-10'),
    array('start' => '2014-01-11', 'end' => '2014-01-13')
);

echo "<pre>";

var_dump(checkDateOverlap($ranges));
echo "</pre>";  

任何建议都非常感谢。

3 个答案:

答案 0 :(得分:1)

$ranges = array(
        array('start' => new DateTime('2014-01-01'), 'end' => new DateTime('2014-01-05')),
        array('start' => new DateTime('2014-01-06'), 'end' => new DateTime('2014-01-06')),
        array('start' => new DateTime('2014-01-07'), 'end' => new DateTime('2014-01-07')),
    );

    function intersects($lhs, $rhs) {
        // Note that this function allows ranges that "touch", 
        // eg. one pair starts at the exact same time that the other ends.
        // Adding less "or equal to" will allow same start date 
        return !($lhs['start'] > $rhs['end'] || $lhs['end'] < $rhs['start']);
    }

    function checkDates($ranges) {
        // Comparison loop is of size n•log(n), not doing any redundant comparisons
        for($i = 0; $i < sizeof($ranges); $i++) {
            for($j = $i+1; $j < sizeof($ranges); $j++) {
                if(intersects($ranges[$i], $ranges[$j])) {
                    echo "Date {$i} intersects with date {$j}\n";
                }
            }
        }
    }

    checkDates($ranges);

我附上了我的工作代码示例,希望将来帮助其他人寻找相同的解决方案。这将打印相交的数组。

答案 1 :(得分:0)

如果您使用usort首先对日期进行排序,则工作变得更加容易。以下内容可以进行大量优化,但逐步完成后会更容易理解。

//The date comparison function, sort on start and then on end
function cmp($a, $b)
{
    if($a['start']<$b['start']) return -1;
    if($a['start']>$b['start']) return 1;
    if($a['end']<$b['end']) return -1;
    if($a['end']>$b['end']) return 1;
    return 0; // start=start and end=end
}

$ranges = array(
    array('start' => '2014-01-01', 'end' => '2014-01-04'),
    array('start' => '2014-01-05', 'end' => '2014-01-10'),
    array('start' => '2014-01-04', 'end' => '2014-01-07')
);

usort($ranges, 'cmp'); // Sort the dates

$output = array();
for($i=0; $i<sizeof($ranges); $i++)
{
    $endindex = $i; // The index containing the proper 'end' value
    for($j=$i+1; $j<sizeof($ranges); $j++)
    {
        if($ranges[$endindex]['start'] == $ranges[$j]['start']) // Overlap
            $endindex = $j;
        elseif($ranges[$endindex]['end']>=$ranges[$j]['start']) // Overlap
            $endindex = $j;
    }
    $output[] = array('start' => $ranges[$i]['start'], 'end' => $ranges[$endindex]['end']);
    // Break the rules by hard-setting $i from the for loop - it works great in this case
    $i = $endindex;
}

print_r($output);

它适用于您的示例。如果您有其他必须使用的规则,希望您可以调整此代码。

答案 2 :(得分:0)

以下是一些评论:
- 您不会检查由“开始”组成的日期的有效性。并且&#39;结束&#39; - 为什么不将日期转换为时间戳?
- &GT;比较整数值而不是字符串更容易,更快?

为什么不使用PHP DateTime和DateInterval对象?
http://php.net/manual/en/book.datetime.php