1

I have an array that have start and end date in key/value. eg.

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

)

Here you can see some element have continuously dates. eg. first three element have 04/01 to 04/03 dates. I want that in one element. so new array should be like this >

$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'
})

How can do it ?

Thanks

3

3 Answers 3

3

I know there's already an answer but here's my version - spent a bit of time on it so wanted to share!

As in your example, I'm assuming your original array is in date order and the keys and values are always the same.

You can use a function to iterate over your original dataset and return an array of grouped dates as follows...

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

You can then use the function as follows,

$result_array = group_dates($arr);

Feeding the function the array in your example will result in an array as you requested.

As your dates are formatted MM/DD/YYYY the string will be correctly converted to a unix timestamp by strtotime(). If you were using other date formats you will want to look at the PHP DateTime object.

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

Sign up to request clarification or add additional context in comments.

Comments

1

Check the below code

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

?>

Output:

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
)

Comments

0

check out this method, found on:

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

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.