PHP将两个相互冲突的日期范围组合成唯一的对

PHP将两个相互冲突的日期范围组合成唯一的对,php,date,date-range,Php,Date,Date Range,第一组: 2014-04-05至2014-06-27 2014-06-28至2014-10-19 第二组: 2014-04-05至2014-05-02 2014-05-03至2014-05-31 2014-06-01至2014-10-19 我需要输出的是: 2014-04-05至2014-05-02 2014-05-03至2014-05-31 2014-06-01至2014-06-27 2014-06-28至2014-10-19 我尝试使用一个函数来检查重叠: !($lhs['RecordOns

第一组:

  • 2014-04-05至2014-06-27
  • 2014-06-28至2014-10-19
  • 第二组:

  • 2014-04-05至2014-05-02
  • 2014-05-03至2014-05-31
  • 2014-06-01至2014-10-19
  • 我需要输出的是:

  • 2014-04-05至2014-05-02
  • 2014-05-03至2014-05-31
  • 2014-06-01至2014-06-27
  • 2014-06-28至2014-10-19
  • 我尝试使用一个函数来检查重叠:

    !($lhs['RecordOnset'] > $rhs['RecordOffset'] || $lhs['RecordOffset'] < $rhs['RecordOnset'])
    
    第二对将是一个单独的数组,因为它可能具有相同的密钥

    在此方面的任何指导或帮助都将不胜感激。PHP的日期范围在线资源非常有限。

    以下是我的解决方案:

    <?php
    $array1 = array(
        array('s'=>'2014-04-05','e'=>'2014-06-27'),
        array('s'=>'2014-06-28','e'=>'2014-10-19')
    );
    $array2 = array(
        array('s'=>'2014-04-05','e'=>'2014-05-02'),
        array('s'=>'2014-05-03','e'=>'2014-05-31'),
        array('s'=>'2014-06-01','e'=>'2014-10-19')
    );
    
    //merge arrays together
    $merged_array = array_merge($array1,$array2);
    
    //filter out duplicate start dates
    $filtered_array = array();
    foreach($merged_array as $k=>$v){
        if(!isset($filtered_array[ $v['s'] ] )){
            $filtered_array[ $v['s'] ] = $v;
        }
    
        //if the end date is before the currently saved end date (for this start date) then use it
        if( strtotime($v['e']) < strtotime($filtered_array[ $v['s'] ]['e']) ){
            $filtered_array[ $v['s'] ] = $v;
        }
    }
    
    //reset the array to zero based
    $filtered_array = array_values($filtered_array);
    
    //sort the array by start date
    $tmp = array();
    foreach($filtered_array as $k=>$v){
        $tmp[$k] = $v['s'];
    }
    
    array_multisort($tmp,SORT_ASC,$filtered_array);
    
    //end date overlap checking
    foreach($filtered_array as $k=>$v){
        //if the end date is after (or equal to) the "next" start date, then make that end date the "yesterday" of the next start date
        if( isset($filtered_array[$k+1]['s']) && strtotime($v['e']) >= strtotime($filtered_array[$k+1]['s'])  ){
            $yesterday = strtotime($filtered_array[$k+1]['s']) - 1;
            $yesterday = date("Y-m-d",$yesterday);
            $filtered_array[$k]['e'] = $yesterday;
        }
    }
    
    echo '<pre>',print_r($filtered_array),'</pre>';
    
    /*
    Array
    (
        [0] => Array
            (
                [s] => 2014-04-05
                [e] => 2014-05-02
            )
    
        [1] => Array
            (
                [s] => 2014-05-03
                [e] => 2014-05-31
            )
    
        [2] => Array
            (
                [s] => 2014-06-01
                [e] => 2014-06-27
            )
    
        [3] => Array
            (
                [s] => 2014-06-28
                [e] => 2014-10-19
            )
    
    )
    */
    
    准备

    嗯。现在我们需要循环数组
    $start
    :对于每个
    start
    查找比
    start
    更接近的
    end
    。做它:

     $ranges[$end] = $start;
    
    你需要什么

    注意 关于循环中的这一行:

     $ranges[$end] = $start;
    
    我们可以有这样的情况:

    $input = [
        // One day.
        (object) [
            'title' => 'One day.',
            'from'  => 1560816000,
            'to'    => 1560902399,
        ],
        // Same day, inner period
        (object) [
            'title' => 'Same day, inner period',
            'from'  => 1560816000 + 1000,
            'to'    => 1560902399 - 1000,
        ],
        // Just before midnight
        (object) [
            'title' => 'Just before midnight',
            'from'  => 1560816000 - 1000,
            'to'    => 1560816000 + 1000,
        ],
        // Just after midnight
        (object) [
            'title' => 'Just after midnight',
            'from'  => 1560902399 - 1000,
            'to'    => 1560902399 + 1000,
        ],
        // Other period before
        (object) [
            'title' => 'Other period before',
            'from'  => 1560902399 - 100000,
            'to'    => 1560902399 - 100000 + 5000,
        ],
        // Other period after
        (object) [
            'title' => 'Other period after',
            'from'  => 1560816000 + 100000,
            'to'    => 1560902399 + 100000 + 5000,
        ],
    ];
    
    
    但这是错误的。只需要最后一个范围
    2014-04-05至2014-05-02
    。和行:

    Array
    (
        [0] => Array
            (
                [from] => 2019-06-17 22:13:19
                [to] => 2019-06-17 23:36:39
            )
    
        [1] => Array
            (
                [from] => 2019-06-18 01:43:20
                [to] => 2019-06-19 02:16:39
            )
    
        [2] => Array
            (
                [from] => 2019-06-19 05:46:40
                [to] => 2019-06-20 07:09:59
            )
    
    )
    
    

    使用相同键=>的覆盖值最终将设置为正确的
    2014-04-05
    2014-05-02

    用法:
    $output=mergeRanges($input)

    该方法最初设计用于合并数值范围内的任何类型,包括时间戳,并支持任何类型的重叠。它接受输入中的对象数组,其中包含可自定义的“from”和“to”键

    
    /**
    *@param$范围
    *@param string$keyFrom
    *@param string$keyTo
    *
    *@return数组
    */
    函数mergeRanges($ranges,$keyFrom='from',$keyTo='to')
    {
    //从/到值拆分。
    $arrayFrom=[];
    $arrayTo=[];
    foreach($范围为$日期)
    {
    $arrayFrom[]=$date->$keyFrom;
    $arrayTo[]=$date->$keyTo;
    }
    //分类ASC。
    natsort($arrayFrom);
    纳索特($arrayTo);
    $ranges=[];
    //迭代开始日期。
    foreach($arrayFrom作为$indexFrom=>$from)
    {
    //获取以前的条目。
    $previousEntry=结束($ranges);
    //查找关联的默认“to”值到“from”值。
    $to=$arrayTo[$indexFrom];
    //如果我们有以前的条目且“to”大于
    //当前“从”值。
    如果(设置($previousEntry->to)&&$from<$previousEntry->to+1)
    {
    //如果此范围完全覆盖,则不执行任何操作
    //由上一个。
    如果($to>$previousEntry->to)
    {
    //我们只需将te“改为”先前范围的值,
    //所以我们不创建新条目。
    $previousEntry->to=$to;
    }
    }
    其他的
    {
    //创建一个新的范围条目。
    $ranges[]=(对象)[
    $keyFrom=>$from,
    $keyTo=>$to,
    ];
    }
    }
    返回$ranges;
    }
    
    例如:

    结果:


    这个范围是一个字符串,两个独立的日期/时间戳,你如何接收这些数据,。。??将数组或w/e中的数据添加到您的问题中。我使用的是数组中的日期格式。。例如,第一组是:数组(数组('start'=>'04/05/2014','end'=>'2014-06-27'),数组('start'=>'2014-06-28','end'=>'2014-10-19')),您希望找到两个数组中可用的所有时间段,对吗?比如说,如果你只知道两个人假期的开始和结束,你就可以试着找出他们何时可以见面?这就是我试图做的一个很好的例子。使用范围,保持时间框架的唯一性。。就像日历一样,查找两个人有约会的时间以及他们在约会之外的空闲时间。非常感谢您的输入。到目前为止,这看起来不错,我正在尝试测试这一点。到目前为止,当我返回结果时(在原始数组中有更多开始和结束的数据),日期不是从最小到最大的顺序。我的解决方案可能并不完美,但希望它能为您指明正确的方向
    array\u multisort()
    应允许您根据开始日期使用阵列。我将致力于实现此解决方案,因为它易于理解和理解。你能解释一下最后一部分的意思吗--$ranges[$end]=$start。我想我没有听你的解释。@Nick McCaly你可以更改
    $ranges[$end]=$start到行
    $ranges[]=array('start'=>$start,'end'=>$end)
    ;。如果您这样做了=>还需要删除
    “combine”
    循环。然后你就可以明白为什么我会选择
    $ranges[$end]=$start$ranges = array();
    
    foreach($starts as $start){
        $start_time = strtotime($start);
    
        foreach($ends as $end){
            $end_time = strtotime($end);
            if ($start_time>$end_time) continue;
            else{
                $ranges[$end] = $start;
                break;
            }
        }
    }
    
    // "combine" 
    $result = array();    
    foreach($ranges as $end=>$start) {
        $result[] = array('start' => $start, 'end' => $end);
    }
    
    // print final result
    foreach($result as $item){
        echo $item['start'].'  To  '.$item['end'].'<br/>';
    }
    
    2014-04-05 To 2014-05-02
    2014-05-03 To 2014-05-31
    2014-06-01 To 2014-06-27
    2014-06-28 To 2014-10-19
    
     $ranges[$end] = $start;
    
    2014-04-03 To 2014-05-02
    2014-04-04 To 2014-05-02
    2014-04-05 To 2014-05-02
    
     $ranges[$end] = $start;
    
    $input = [
        // One day.
        (object) [
            'title' => 'One day.',
            'from'  => 1560816000,
            'to'    => 1560902399,
        ],
        // Same day, inner period
        (object) [
            'title' => 'Same day, inner period',
            'from'  => 1560816000 + 1000,
            'to'    => 1560902399 - 1000,
        ],
        // Just before midnight
        (object) [
            'title' => 'Just before midnight',
            'from'  => 1560816000 - 1000,
            'to'    => 1560816000 + 1000,
        ],
        // Just after midnight
        (object) [
            'title' => 'Just after midnight',
            'from'  => 1560902399 - 1000,
            'to'    => 1560902399 + 1000,
        ],
        // Other period before
        (object) [
            'title' => 'Other period before',
            'from'  => 1560902399 - 100000,
            'to'    => 1560902399 - 100000 + 5000,
        ],
        // Other period after
        (object) [
            'title' => 'Other period after',
            'from'  => 1560816000 + 100000,
            'to'    => 1560902399 + 100000 + 5000,
        ],
    ];
    
    
    Array
    (
        [0] => Array
            (
                [from] => 2019-06-17 22:13:19
                [to] => 2019-06-17 23:36:39
            )
    
        [1] => Array
            (
                [from] => 2019-06-18 01:43:20
                [to] => 2019-06-19 02:16:39
            )
    
        [2] => Array
            (
                [from] => 2019-06-19 05:46:40
                [to] => 2019-06-20 07:09:59
            )
    
    )