合并 PHP 中日期范围的算法
Algorithm to combine date ranges in PHP
我有一个数组,其开始日期和结束日期在 key/value 中。
例如。
/* 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。我想要一个元素。所以新数组应该是这样的 >
$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'
})
怎么办?
谢谢
检查下面的代码
<?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
)
我知道已经有了答案,但这是我的版本 - 花了一些时间所以想分享!
如您的示例所示,我假设您的原始数组是按日期顺序排列的,并且键和值始终相同。
您可以使用函数迭代原始数据集和 return 分组日期数组,如下所示...
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
查看此方法,发现于:
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
我有一个数组,其开始日期和结束日期在 key/value 中。 例如。
/* 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。我想要一个元素。所以新数组应该是这样的 >
$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'
})
怎么办?
谢谢
检查下面的代码
<?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
)
我知道已经有了答案,但这是我的版本 - 花了一些时间所以想分享!
如您的示例所示,我假设您的原始数组是按日期顺序排列的,并且键和值始终相同。
您可以使用函数迭代原始数据集和 return 分组日期数组,如下所示...
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
查看此方法,发现于:
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