【问题标题】:Return the amount of overlapping minutes between two PHP DatePeriods返回两个 PHP DatePeriods 之间的重叠分钟数
【发布时间】:2016-01-21 02:57:39
【问题描述】:

我刚刚问了这个问题,它被标记为已经回答,但是这样做的人显然不理解这个问题。

此帖子被标记为与此重复的问题,

How to get time difference in minutes in PHP,

但它们甚至完全不一样。

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

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

我发现另一个帖子在这里回答了我的一半问题,

Determine Whether Two Date Ranges Overlap

它工作得很好,但它没有给我两个日期范围之间的时间重叠量。它只确定它们是否重叠。我需要知道它们重叠的分钟数。所以这是我最初的问题......

我认为有一个非常简单的方法可以做到这一点,但我已经查看了所有内容,但找不到解决方案。逻辑很简单:给定两个 DatePeriod,求重叠分钟数。

例如,

-我将$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 由两个 DateTimes 组成,我正在寻找两个 DatePeriods 之间的区别。

【问题讨论】:

  • 重叠需要在两个方向上计算。如果 $startDate1 和 $endDate1 晚于或介于 $startDate2 和 $endDate2 之间会怎样。
  • 不,它没有。就像我说的,有四个步骤。 (1) 计算较晚的开始日期;在此之前,重叠是不可能的。 (2) 计算较早的结束日期;在那之后重叠是不可能的。 (3) 从较早的结束日期减去较晚的开始日期。 (4) 检查结果。如果它是零或更大,这就是你的答案。如果它是否定的,那么你的答案是零;这意味着第二个时期直到第一个时期结束才开始。
  • 我明白你的意思。谢谢你。我会尝试一下,并提供有关我是否成功的更新。

标签: php datetime


【解决方案1】:

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

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

这里有一个函数来做你想做的事:

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

【讨论】:

  • 这很好用。非常感谢埃德。我仍然不完全理解逻辑,但我测试了很多不同的方式,效果很好。你一定是个天才。
  • 可靠的答案 - 但你为什么不使用 2 个 DatePeriod 对象?
  • @GungFoo 谢谢!我可能遗漏了一些东西,但我不确定如何在这里使用DatePeriods。据我了解,这些是用于计算重复间隔。我没有看到我们如何使用它们来确定两个不同时间窗口中重叠的分钟数。
  • 我们会将函数的参数数量减少到 2(如果我们扩展 DatePeriod,可能会减少 1),同时使函数更通用,因为它会返回一个区间选择输出的格式。 DateInterval $myPeriod-&gt;overlapsWithPeriod((DatePeriod) $period);
  • @GungFoo 我想这会起作用,但我认为这里没有必要。不过好主意!
【解决方案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

【讨论】:

  • 干得好。我个人不确定我是否觉得这更容易理解,但它是一些 OOP 的一个很好的用途。
  • 感谢您添加此内容。这是一个非常优雅的解决方案。我很高兴人们发现这个帖子很有帮助。
【解决方案3】:

如果您有 $start1, $end1, $start2, $end2 作为 Unix 时间戳(例如,使用 strtotime() 创建),您只需输入:

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

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

【讨论】:

    【解决方案4】:

    我为我的网站写了这样的东西。这是代码。它不像其他一些答案那样紧凑,但希望它具有相当的可读性。

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

    【讨论】:

      猜你喜欢
      • 2016-01-21
      • 1970-01-01
      • 1970-01-01
      • 2012-12-03
      • 1970-01-01
      • 1970-01-01
      • 2013-07-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多