找出两个日期范围在PHP中重叠了多少天

时间:2019-02-20 11:13:47

标签: php php-7

我有两个任意的日期范围,例如:

2019-01-01 - 2019-01-10
and
2019-01-06 - 2019-01-20

如何在PHP中找出这些日期范围重叠了多少天? (在上面的示例中是5天)

3 个答案:

答案 0 :(得分:1)

我不确定您要做什么,但是请检查以下解决方案:

<?php

$date1 = strtotime('2019-01-01');
$date2 = strtotime('2019-01-10');

$date3 = strtotime('2019-01-06');
$date4 = strtotime('2019-01-20');

$dateDiff1 = $date2 - $date1;
$dateDiff2 = $date4 - $date3;

$finalDiff = $dateDiff2 - $dateDiff1;

echo round($finalDiff / (60 * 60 * 24));

返回:

5

有关strtotime()

的更多信息

注意::仅当第二个日期始终大于第一个日期时,此选项才有效。您的问题不清楚。

答案 1 :(得分:1)

这是使用DateTimeDateInterval对象的解决方案:

$range1 = '2019-01-01 - 2019-01-10';
$range2 = '2019-01-06 - 2019-01-20';
list($start, $end) = explode(' - ', $range1);
$start1 = new DateTime($start);
$end1 = new DateTime($end);
list($start, $end) = explode(' - ', $range2);
$start2 = new DateTime($start);
$end2 = new DateTime($end);
if ($end1 > $start1) {
    $overlap = $end1->diff(min($start2, $end2));
}
else {
    $overlap = $start1->diff(min($start2, $end2));
}
echo "overlap is " . ($overlap->format('%a') + 1) . " days";

输出

overlap is 5 days

Demo on 3v4l.org

更新

这是代码的更强大的版本,它允许范围的任意重叠(包括一个完全包含在另一个中):

function range_overlap($range1, $range2) {
    list($start, $end) = explode(' - ', $range1);
    $start = new DateTime($start);
    $end =  new DateTime($end);
    $start1 = min($start, $end);
    $end1 = max($start, $end);
    list($start, $end) = explode(' - ', $range2);
    $start = new DateTime($start);
    $end =  new DateTime($end);
    $start2 = min($start, $end);
    $end2 = max($start, $end);
    // check for special cases
    if ($start1 >= $start2 && $end1 <= $end2) {
        // range1 completely contained inside range2
        $overlap = $start1->diff($end1);
    }
    elseif ($start2 >= $start1 && $end2 <= $end1) {
        // range2 completely contained inside range1
        $overlap = $start2->diff($end2);
    }
    elseif ($end2 > $end1) {
        // range1 ends first
        $overlap = $start2->diff($end1);
    }
    else {
        // range2 ends first
        $overlap = $start1->diff($end2);
    }
    // if overlap is < 0 then there is no overlap
    $overlap_days = $overlap->invert ? 0 : ($overlap->format('%a') + 1);
    echo "overlap is $overlap_days days\n";
}

可以这样称呼:

range_overlap('2019-01-01 - 2019-01-10', '2019-01-06 - 2019-01-20'); // 5 days
range_overlap('2019-01-01 - 2019-03-20', '2019-05-06 - 2019-04-20'); // no overlap
range_overlap('2019-01-10 - 2019-05-20', '2019-01-01 - 2019-05-20'); // 131 days
range_overlap('2019-01-06 - 2019-01-20', '2019-01-10 - 2019-01-01'); // 5 days
range_overlap('2019-01-30 - 2019-01-10', '2019-01-12 - 2019-01-15'); // 4 days
range_overlap('2019-02-01 - 2019-03-20', '2019-01-10 - 2019-02-28'); // 28 days

Demo on 3v4l.org

答案 2 :(得分:0)

这是我使用的函数:

function nightsInRange(\Datetime $arriveDate, \Datetime $departDate, \Datetime $rangeStart, \Datetime $rangeEnd) : int
{
    // just use the Y-m-d portion of date
    $arriveDate = clone $arriveDate;
    $arriveDate->setTime(0,0,0);

    $departDate = clone $departDate;
    $departDate->setTime(0,0,0);

    $rangeStart = clone $rangeStart;
    $rangeStart->setTime(0,0,0);

    $rangeEnd = clone $rangeEnd;
    $rangeEnd->setTime(0,0,0);

    if ($arriveDate >= $departDate) {
        throw new \InvalidArgumentException("arriveDate must be BEFORE departDate");
    }

    if ($rangeStart > $rangeEnd) {
        throw new \InvalidArgumentException("rangeEnd must be greater than or equal to rangeStart");
    }

    $arriveDateInRange = ($arriveDate >= $rangeStart && $arriveDate <= $rangeEnd);
    $departDateInRange = ($departDate >= $rangeStart && $departDate <= $rangeEnd);

    if ($arriveDateInRange && $departDateInRange) {
        // both dates inside range
        $nightsInRange = $arriveDate->diff($departDate)->days;
    } elseif ($arriveDateInRange && !$departDateInRange) {
        // arrive inside, depart outside
        $nightsInRange = $arriveDate->diff($rangeEnd)->days + 1;
    } elseif (!$arriveDateInRange && $departDateInRange) {
        // arrive outside, depart inside
        $nightsInRange = $departDate->diff($rangeStart)->days;
    } elseif ($arriveDate <= $rangeStart && $departDate >= $rangeEnd) {
        // arrive before rangeStart, depart after rangeEnd
        //
        // Note that we add 1 to the date diff to get the range length.  For
        // example, the range from 2018-11-01 to 2018-11-30 is 30 days (not 29).
        // A range with same start and end dates (e.g. 2018-11-01 to 2018-11-01)
        // would have a range length of 1 day.
        //
        $nightsInRange = $rangeStart->diff($rangeEnd)->days + 1;
    } else {
        // no overlap
        $nightsInRange = 0;
    }

    return $nightsInRange;
}