返回两个PHP DatePeriod之间的重叠分钟数

时间:2015-10-21 23:04:05

标签: php datetime

我刚刚问了这个问题并且已经标记为已经回答了,但是那个做了那个的人显然不明白这个问题。

这篇文章被标记为重复的问题,

  

How to get time difference in minutes in PHP

但它们甚至不是一样的。

我在两个 DatePeriods 中寻找重叠时间的数量,而不是两个日期之间的差异。

“DatePeriod”由两个日期组成,我正在寻找两个DatePeriod之间的重叠量。

我发现还有另一篇文章回答了我的问题的一半,

  

Determine Whether Two Date Ranges Overlap

并且效果很好,但它没有给出两个日期范围之间重叠的时间量。它只确定它们是否重叠。我需要知道它们重叠的分钟数。所以这是我原来的问题......

我认为有一种非常简单的方法可以做到这一点,但我已经看了一遍,无法找到解决方案。逻辑很简单:找到给定两个DatePeriods的重叠分钟数。

例如,

- 我有$startDate1$endDate1作为第一个日期范围。

- 我有$startDate2$endDate2作为第二个日期范围。

(为了演示,格式为'Y-m-d H:i'。)

  • 假设$startDate1 = '2015-09-11 09:15'$endDate1 = '2015-09-13 11:30'

  • 假设$startDate2 = '2015-09-13 10:45'$endDate2 = '2015-09-14 12:00'

我希望 45分钟重叠的结果。如何实现这一目标?

我已经看到使用两个DateTimes完成了,但这不是我正在寻找的。

datePeriod由两个DateTime组成,我正在寻找两个DatePeriod之间的区别。

4 个答案:

答案 0 :(得分:7)

正如我在评论中所解释的那样,有四个步骤。

  1. 计算以后的开始日期;在此之前不可能重叠。
  2. 计算较早的结束日期;之后不可能重叠。
  3. 从较早的结束日期减去较晚的开始日期。
  4. 检查结果。如果它为零或更大,那么你的答案是肯定的。如果它是否定的,那么你的答案是零;这意味着第二个时期没有开始,直到第一个时期结束。
  5. 这是一个能够做你想做的事情的功能:

    /**
     * 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;
    }
    

    样本使用:

    $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
    

答案 1 :(得分:2)

使用@Ed Cottrell的代码作为基础,我将基于PHP的OO Date类的这个小方法放在一起:

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);
    }
}

使用Ed的测试用例,可以得到:

$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

答案 2 :(得分:0)

如果您将$start1, $end1, $start2, $end2作为Unix时间戳记(例如,用strtotime()创建),则只需键入:

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

结果以秒为单位。将其转换为小时/天等很简单。

答案 3 :(得分:0)

我为我的网站写了类似的东西。这是代码。它不像其他答案那么紧凑,但是希望它是相当可读的。

// Input should be UNIX timestamps
function get_minutes_of_overlap($date1_start_time, $date1_end_time, $date2_start_time, $date2_end_time) {
    if ( $date1_end_time == $date2_end_time ) {
        if ( $date1_start_time > $date2_start_time ) {
            $date1_ends_later = TRUE;
        } else {
            $date1_ends_later = FALSE;
        }
    } elseif ( $date1_end_time > $date2_end_time ) {
        $date1_ends_later = TRUE;
    } else {
        $date1_ends_later = FALSE;
    }

    if ( $date1_ends_later ) {
        $minutes_of_overlap = ($date2_end_time - $date1_start_time) / 60;
    } else {
        $minutes_of_overlap = ($date1_end_time - $date2_start_time) / 60;
    }

    return $minutes_of_overlap;
}