在PHP中组合日期范围的算法


Algorithm to combine date ranges in PHP

我有一个数组,开始和结束日期在键/值。如。

/* formate 'mm/dd/yyyy'=>  'mm/dd/yyyy'*/
$arr = array(
'01/01/2016'=>'01/01/2016',
'01/02/2016'=>'01/02/2016',
'01/03/2016'=>'01/03/2016',

'04/10/2016'=>'04/10/2016',
'04/11/2016'=>'04/11/2016',
'04/12/2016'=>'04/12/2016',

'04/25/2016'=>'04/25/2016',
'04/30/2016'=>'04/30/2016',
'05/01/2016'=>'05/01/2016',
'05/02/2016'=>'05/02/2016' }
)

在这里你可以看到一些元素有连续的日期。如。前三个元素的日期是04/01到04/03。我想让它在一个元素中。所以new array应该是这样的>

$arr = array(
    '01/01/2016'=>'01/03/2016',
    '04/10/2016'=>'04/12/2016',
    '04/25/2016'=>'04/25/2016',
    '04/30/2016'=>'05/02/2016'
})

怎么能做到呢?

谢谢

我知道已经有答案了,但这是我的版本-花了一点时间,所以想分享!

在你的例子中,我假设你的原始数组是按日期顺序,键和值总是相同的。

你可以使用一个函数来迭代你的原始数据集,并返回一个分组日期数组,如下所示…

function group_dates($dates_array) {
   // prepare results array
   $result = array();
   // take the first date from the submitted array
   $group_start = array_shift($dates_array);
   $timestamp_previous_iteration = strtotime($group_start);
   // iterate over remaining values
   foreach ($dates_array as $date) {
      // calculate current iteration's timestamp
      $timestamp_current = strtotime($date);
      // calculate timestamp for 1 day before the current value
      $timestamp_yesterday = strtotime('-1 day', $timestamp_current);
      if ($timestamp_previous_iteration != $timestamp_yesterday) {
         // create group...
         $result[$group_start] = date('m/d/Y', $timestamp_previous_iteration);
         // ...and store the next group's start date
         $group_start = $date;
      }
      // log timestamp for next iteration
      $timestamp_previous_iteration = $timestamp_current;
   }
   // add final group
   $result[$group_start] = date('m/d/Y', $timestamp_previous_iteration);
   return $result;
}

然后你可以像下面这样使用这个函数,

$result_array = group_dates($arr);

在您的示例中为函数提供数组将产生您所要求的数组。

由于您的日期格式为MM/DD/YYYY,该字符串将被strtotime()正确转换为unix时间戳。如果您使用其他日期格式,您将需要查看PHP DateTime对象。

引用
http://php.net/manual/en/function.strtotime.php
http://php.net/manual/en/book.datetime.php

检查下面的代码

<?php
    $arr = array(
        '01/01/2016'=>'01/01/2016',
        '01/02/2016'=>'01/02/2016',
        '01/03/2016'=>'01/03/2016',
        '04/10/2016'=>'04/10/2016',
        '04/11/2016'=>'04/11/2016',
        '04/12/2016'=>'04/12/2016',
        '04/25/2016'=>'04/25/2016',
        '04/30/2016'=>'04/30/2016',
        '05/01/2016'=>'05/01/2016',
        '05/02/2016'=>'05/02/2016' 
    );
    $lastDate = null;
    $ranges = array();
    $currentRange = array();
    foreach ($arr as $date => $value ) {
        $temp = $value;
        $value = date_create(date('m/d/Y', strtotime($value)));
        if (null === $lastDate) {
            $currentRange[] = $temp;
        } else {
            // get the Date object
            $interval = date_diff($value, $lastDate);
            if ($interval->days === 1) {
                // add this date to the current range
                $currentRange[] = $temp;    
            } else {
                // store the old range and start a new
                $ranges[] = $currentRange;
                $currentRange = array($temp);
            }
        } 
        $lastDate = $value;
    }
    $ranges[] = $currentRange;
    $datemerge = array();
    foreach ($ranges as $key) {
        $count = count($key);
        $datemerge[$key[0]] = $key[$count-1];
    }
    print_r($datemerge);
?>
输出:

Array
(
    [01/01/2016] => 01/03/2016
    [04/10/2016] => 04/12/2016
    [04/25/2016] => 04/25/2016
    [04/30/2016] => 05/02/2016
)

查看此方法,见:

function getRelativeDate($p_sDate, $p_sModify, $p_sFormatIn = 'Y-m-d', $p_sFormatOut = 'Y-m-d') {
    $oDT = DateTime::createFromFormat($p_sFormatIn, $p_sDate);
    $oDT->modify($p_sModify);
    return $oDT->format($p_sFormatOut);
}
function mergeDateRanges($p_arrDateranges) {
    // sort by start date
    usort($p_arrDateranges, function($a1, $a2) {
        return $a1['s'] === $a2['s'] ? 0 : ($a1['s'] < $a2['s'] ? -1 : 1);
    });
    
    $arrMerged = array();
    $arrLastDR = null;
    foreach ($p_arrDateranges as $arrDR) {
        if ($arrLastDR === null) {
            $arrLastDR = $arrDR;
            continue;
        }
        //
        // NOTE: dateS is sorted thus $sDateS >= $arrLastDR['s']
        //
        if ($arrDR['e'] <= $arrLastDR['e']) {
            continue; // already in the range.
        }
        // --- [e] > lastDR[e] ---
        $sLastDateE_1 = getRelativeDate($arrLastDR['e'], '+1 day');
        if ($arrDR['s'] <= $sLastDateE_1) { // lapping date-range until day+1
            $arrLastDR['e'] = $arrDR['e'];
            continue;
        }
        // there is gap, so need to create new date-range
        array_push($arrMerged, $arrLastDR);
        $arrLastDR = $arrDR;
    }
    array_push($arrMerged, $arrLastDR);
    return $arrMerged;
}

摘自:http://mdb-blog.blogspot.com/2020/12/php-merge-dateranges-algorithm.html