Reputation: 1495
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
Upvotes: 1
Views: 2376
Reputation: 2312
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
Upvotes: 0
Reputation: 1963
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
Upvotes: 3
Reputation: 575
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
)
Upvotes: 1