关于php:检查日期范围(开始和结束日期)是否有重叠

Check date ranges (start and end date) for overlap

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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循环,但是不管我没有获得成功。

这是我的另一项尝试:

1
<?php

//将您的范围传递给此方法,如果存在常见的相交,它将
//返回或为false

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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"[cc lang="php"]";

var_dump(checkDateOverlap($ranges));
echo"

";

任何建议,我们将不胜感激。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$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}\
"
;
                }
            }
        }
    }

    checkDates($ranges);

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


以下是一些注意事项:
-您不检查由"开始"和"结束"形成的日期的有效性。
-为什么不将日期转换为时间戳?
->比较整数值而不是字符串更容易,更快捷?

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


如果您使用usort首先对日期进行排序,则工作会容易得多。以下内容可以进行很多优化,但是它是分步完成的,因此更易于理解。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//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);

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