Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Return the amount of overlapping minutes between two PHP DatePeriods

Tags:

php

datetime

I just asked this question and it was marked as already answered but whoever did that obviously did not understand the question.

This post was marked as a duplicate question to this,

How to get time difference in minutes in PHP ,

but they are not even remotely the same.

I'm looking for the amount of overlapping time in two DatePeriods not the difference between two dates.

A "DatePeriod" consists of two dates and I'm looking for the amount of overlap between two DatePeriods.

There is another post I found that answers half of my question here,

Determine Whether Two Date Ranges Overlap

and it works great but it does not give me the amount of time overlap between the two date ranges. It only determines if they overlap or not. I need to know the amount of minutes that they overlap. So Here is my original question...

I assumed there would be a very easy way to do this but I have looked all over and can not find a solution. The logic is simple: find the amount of overlapping minutes given two DatePeriods.

For example,

-I have $startDate1 and $endDate1 as the first date range.

-I have $startDate2 and $endDate2 as the second date range.

(For demonstration sake, the format is 'Y-m-d H:i'. )

  • Suppose $startDate1 = '2015-09-11 09:15' and $endDate1 = '2015-09-13 11:30'.

  • Suppose $startDate2 = '2015-09-13 10:45' and $endDate2 = '2015-09-14 12:00'.

I would expect a result of 45 minutes overlap. How can this be achieved?

I have seen this done using two DateTimes but that is not what I'm looking for.

A datePeriod consists of two DateTimes and I'm looking for the difference between two DatePeriods.

like image 684
Luke James Avatar asked Oct 21 '15 23:10

Luke James


3 Answers

As I explained in the comments, there are four steps.

  1. Calculate the later start date; overlaps are impossible before that.
  2. Calculate the earlier end date; overlaps are impossible after that.
  3. Subtract the later start date from the earlier end date.
  4. Check the result. If it's zero or greater, there's your answer. If it's negative, then your answer is zero; that implies that the second period didn't start until the first one finished.

Here's a function to do what you want:

/**
 * What is the overlap, in minutes, of two time periods?
 *
 * @param $startDate1   string
 * @param $endDate1     string
 * @param $startDate2   string
 * @param $endDate2     string
 * @returns int     Overlap in minutes
 */
function overlapInMinutes($startDate1, $endDate1, $startDate2, $endDate2)
{
    // Figure out which is the later start time
    $lastStart = $startDate1 >= $startDate2 ? $startDate1 : $startDate2;
    // Convert that to an integer
    $lastStart = strtotime($lastStart);

    // Figure out which is the earlier end time
    $firstEnd = $endDate1 <= $endDate2 ? $endDate1 : $endDate2;
    // Convert that to an integer
    $firstEnd = strtotime($firstEnd);

    // Subtract the two, divide by 60 to convert seconds to minutes, and round down
    $overlap = floor( ($firstEnd - $lastStart) / 60 );

    // If the answer is greater than 0 use it.
    // If not, there is no overlap.
    return $overlap > 0 ? $overlap : 0;
}

Sample uses:

$startDate1 = '2015-09-11 09:15';
$endDate1 = '2015-09-13 11:30';
$startDate2 = '2015-09-13 10:45';
$endDate2 = '2015-09-14 12:00';

echo overlapInMinutes($startDate1, $endDate1, $startDate2, $endDate2) . "\n";
// echoes 45

$startDate1 = '2015-09-11 09:15';
$endDate1 = '2015-09-13 11:30';
$startDate2 = '2015-09-13 12:45';
$endDate2 = '2015-09-14 12:00';

echo overlapInMinutes($startDate1, $endDate1, $startDate2, $endDate2) . "\n";
// echoes 0
like image 199
elixenide Avatar answered Sep 22 '22 14:09

elixenide


Using @Ed Cottrell's code as a basis, i put together this little method based on PHP's OO Date classes:

class DatePeriodHelper extends DatePeriod {
    /**
     * What is the overlap, in minutes, of two time periods?
     * Based on a stackoverflow answer by Ed Cottrell - Thanks Ed :)
     * http://stackoverflow.com/questions/33270716/return-the-amount-of-overlapping-minutes-between-to-php-dateperiods
     * 
     * @param DatePeriod $period    The DatePeriod to compare $this to.
     * @return DateInterval        A DateInterval object expressing the overlap or (if negative) the distance between the DateRanges
     */
    public function overlapsWithPeriod(DatePeriod $period) {
        // Figure out which is the later start time
        $lastStart = $this->getStartDate() >= $period->getStartDate() ? $this->getStartDate() : $period->getStartDate();

        // Figure out which is the earlier end time
        $firstEnd = $this->getEndDate() <= $period->getEndDate() ? $this->getEndDate() : $period->getEndDate();

        // return a DateInterval object that expresses the difference between our 2 dates
        return $lastStart->diff($firstEnd);
    }
}

Using Ed's test cases this yields:

$interval = new DateInterval('P1M');

$startDate1 = new DateTime('2015-09-11 09:15');
$endDate1 = new DateTime('2015-09-13 11:30');
$startDate2 = new DateTime('2015-09-13 10:45');
$endDate2 = new DateTime('2015-09-14 12:00');

$interval = new DateInterval('P1M');

$period1 = new DatePeriodHelper($startDate1, $interval, $endDate1);
$period2 = new DatePeriodHelper($startDate2, $interval, $endDate2);

$overlap = $period1->overlapsWithPeriod($period2);
echo $overlap->format('%r%h:%i:%s');
// echoes: 0:45:0

$startDate2 = new DateTime('2015-09-13 12:45');
$endDate2 = new DateTime('2015-09-14 12:00');
$period2 = new DatePeriodHelper($startDate2, $interval, $endDate2);

$overlap = $period1->overlapsWithPeriod($period2);
echo $overlap->format('%r%h:%i:%s');
// echoes -1:15:0
like image 35
Gung Foo Avatar answered Sep 25 '22 14:09

Gung Foo


If you have $start1, $end1, $start2, $end2 as Unix-Timestamps (e. g. created with strtotime()) you can simply type:

$overlap = max(min($end1, $end2) - max($start1, $start2), 0);

The result is in seconds. It is trivial to convert it to hours/days etc.

like image 42
Peter Avatar answered Sep 25 '22 14:09

Peter