Skip to content
Advertisement

Find out by how many days two date ranges overlap in PHP

I have two arbitrary date ranges, for example:

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

How do I find out in PHP, by how many days these date ranges overlap? (In the example above it’s 5 days)

Advertisement

Answer

Here’s a solution using DateTime and DateInterval objects:

$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";

Output

overlap is 5 days

Demo on 3v4l.org

Update

Here is a more robust version of the code that allows for arbitrary overlapping of the ranges (including one being contained entirely in the other):

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 daysn";
}

It can be called like this:

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

User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement