可能重复:
Check for consecutive dates within a set and return as range
我有一个从mySQL查询中获取的日期数组。我需要将数组分成多个数组,以便每个数组中的日期是连续的。
所以,如果我从
开始$datearray = array("2013-05-05", "2013-05-06", "2013-05-07", "2013-05-08", "2013-06-19", "2013-06-20", "2013-06-21");
我需要将其分成
$firstdatearray = array("2013-05-05", "2013-05-06", "2013-05-07", "2013-05-08");
$seconddatearray = array("2013-06-29", "2013-06-30", "2013-07-01");
最后我将能够打印
3月5日至8月3日,7月29日至7月1日
我该怎么做?我不知道从哪里开始。
答案 0 :(得分:4)
这是完整的工作答案。 (享受!)
你必须遍历$ datearray中的每个值
<?php
$datearray = array("2013-05-05", "2013-05-06", "2013-05-07", "2013-05-08", "2013-06-19", "2013-06-20", "2013-06-21");
asort($datearray);
$resultArray = array();
$index = -1;
$last = 0;
$out = "";
foreach ($datearray as $date) {
$ts = strtotime($date);
if (false !== $ts) {
$diff = $ts - $last;
if ($diff > 86400) {
$index = $index + 1;
$resultArray[$index][] = $date;
} elseif ($diff > 0) {
$resultArray[$index][] = $date;
} else {
// Error! dates are not in order from small to large
}
$last = $ts;
}
}
foreach ($resultArray as $a) {
if (count($a) > 1) {
$firstDate = $a[0];
$firstDateBits = explode('-',$firstDate);
$lastDate = $a[count($a)-1];
$lastDateBits = explode('-',$lastDate);
if ($firstDateBits[1] === $lastDateBits[1]) {
$out .= intval($firstDateBits[2]) . '-' . intval($lastDateBits[2]) . ' ' . date("M",strtotime($firstDate)) . ', ';
} else {
$out .= date("M d",strtotime($firstDate)) . '-' . date("M d",strtotime($lastDate)) . ', ';
}
}
}
这是输出:
5-8 May, 19-21 Jun
答案 1 :(得分:0)
我无法帮助您使用实际代码,但您可以执行以下操作:
答案 2 :(得分:0)
您拥有的所有日期都在同一年。您可以将每个日期转换为该年中的日期数。
然后你会得到一组数字。对于那个阵列,您可以像这里概述的那样:
另一种方法是根据前一个开启计算下一个日期,然后将其与数组中的下一个日期进行比较。如果两者相等,则延长当前时间跨度,如果不相等,则创建新的时间跨度。然后将数组减少到时间跨度:
$consecutiveDates = function ($result, $date) {
if ($count = count($result)) {
$next = clone $result[$count - 1][1];
$next->add(new DateInterval('P1D'));
}
$date = new DateTime($date);
if (!$count || $date != $next) {
$result[$count++] = [$date];
}
$result[$count - 1][1] = $date;
return $result;
};
$reduced = array_reduce($datearray, $consecutiveDates, []);
这给出了以下结果(对于你的数组):
Array
(
[0] => Array
(
[0] => DateTime Object
(
[date] => 2013-05-05 00:00:00
[timezone_type] => 3
[timezone] => Europe/London
)
[1] => DateTime Object
(
[date] => 2013-05-08 00:00:00
[timezone_type] => 3
[timezone] => Europe/London
)
)
[1] => Array
(
[0] => DateTime Object
(
[date] => 2013-06-19 00:00:00
[timezone_type] => 3
[timezone] => Europe/London
)
[1] => DateTime Object
(
[date] => 2013-06-21 00:00:00
[timezone_type] => 3
[timezone] => Europe/London
)
)
)
现在可以使用映射函数轻松地将这两个条目映射到您的输出样式:
$consecutiveDatesString = function ($pair) {
list($start, $end) = $pair;
return $start == $end
? $start->format('j M')
: $start->format($start->format('M') != $end->format('M') ? 'j M' : 'j')
. $end->format(' - j M');
};
$consecutiveDatesStrings = array_map($consecutiveDatesString, $reduced);
然后导致更紧凑的结果:
Array
(
[0] => 5 - 8 May
[1] => 19 - 21 Jun
)
最后打印出以逗号分隔的内容:
echo implode(', ', $consecutiveDatesStrings), "\n";
这给出了猜测:
5 - 8 May, 19 - 21 Jun
答案 3 :(得分:0)
这将有效:
$datearray = array("2013-05-05", "2013-05-06", "2013-05-07", "2013-05-08", "2013-06-19", "2013-06-20", "2013-06-21");
$current_date_array_index = 0;
$dates = array();
for($i=0,$c=count($datearray);$i<$c;$i++){
if(strtotime($dates[$current_date_array_index][count($dates[$current_date_array_index])-1]." +1 day") != strtotime($datearray[$i])){
$current_date_array_index++;
}
$dates[$current_date_array_index][] = $datearray[$i];
}
foreach($dates as $date){
if(count($date) == 1){
$output[] = date('j M',strtotime($date[0]));
}else{
$output[] = date('j',strtotime($date[0]))." - ".date('j M',strtotime($date[count($date)-1]));
}
}
echo implode($output,", "); // output: 5 - 8 May, 19 - 21 Jun
值得注意的是,如果日期超过了一个月,它会说29 - 5 Mar
之类的东西 - 没有定义的第29个,所以如果我是你,我会5 Mar - 8 Mar
。
答案 4 :(得分:0)
尝试这样的事情:
$prev = null;
$groups = array();
$idx = 0;
foreach($datearray as $day)
{
if ($prev == null)
{
$prev = $day;
} else {
$currentDay = strtotime($day);
$prevDay =strtotime($prev);
if ($currentDay + 86400 > $prevDay)
{
// New Array
$idx++;
}
$groups[$idx][] = $day;
}
}
// TODO : Sort the array into date order
注意:我没有测试过上面的代码,因此它可能包含拼写错误。
我只是在数组中每天迭代,并确定它是否是前一天的连续日。如果是,则将其添加到同一组中,如果不是,则将其添加到不同的数组索引中。您可能需要使用某种sorting function from php对此后的日期进行排序。然后迭代数组以确定日期范围。
答案 5 :(得分:0)
假设PHP 5.3或更高版本。
您可以使用DateTime,DateInterval和一些算法工作。
// create the same array but with DateTime objects to represent the dates
$dt_array = array_map(function ($e) { return new DateTime($e); }, $datearray);
$intervals = array();
$len_dt_array_m1 = count($dt_array) - 1;
if ($len_dt_array_m1 >= 0) {
$current_interval = &$intervals[];
}
// now we traverse the array left to right.
// if the difference between the current date and the next is not +1 day, we assume a new interval has begun.
for ($i = 0; $i < $len_dt_array_m1; ++$i) {
$current_dt = $dt_array[$i];
$next_dt = $dt_array[$i+1];
$diff = $current_dt->diff($next_dt);
$current_interval[] = $current_dt->format('Y-m-d');
if ($diff->days != 1 || $diff->invert != 0) {
$current_interval = &$intervals[];
}
}
// add last dt to the interval
if ($len_dt_array_m1 >= 0) {
$current_interval[] = $dt_array[$len_dt_array_m1]->format('Y-m-d');
}
print_r($intervals);
答案 6 :(得分:0)
class Date_Array_Split
{
private $date_arrays = array();
public function __construct( Array $dates, $split_into = 2 )
{
// Sort the array
asort( $dates );
// Calculate the array size to pass to array_chunk
$size = ceil( count( $dates ) / $split_into );
// Break up the array into pieces
$dates = array_chunk( $dates, $size );
$this->date_arrays = $dates;
}
public function __toString()
{
$string = array(); // Oh, the irony!
// Iterate through the chunks
foreach( $this->date_arrays as $date_array )
{
// Here's the oldest date in the chunk
$date_min = min( $date_array );
// Here's the newest date in the chunk
$date_max = max( $date_array );
// Default format for output
$date_min_format = 'j M';
// Accomodate the slight formatting change
if( date( 'my', strtotime( $date_min ) ) === date( 'my', strtotime( $date_max ) ) )
{
// Moth and year are the same, omit the month
$date_min_format = 'j';
}
// String-i-fy the dates for output
$date_min_string = date( $date_min_format, strtotime( $date_min ) );
$date_max_string = date( 'j M', strtotime( $date_max ) );
// Add them to the output array
$string[] = sprintf( '%s - %s', $date_min_string, $date_max_string );
}
// Return the output array separated by commas
return implode( $string, ", " );
}
}
$dates_array = array(
"2013-05-05",
"2013-06-20",
"2013-05-07",
"2013-05-08",
"2014-05-09",
"2013-05-09",
"2013-06-19",
"2013-06-21"
);
$dates = new Date_Array_Split( $dates_array );
echo( $dates );
输出:5 - 9 May, 19 Jun - 9 May
请注意,这是正确处理年份。这就是输出看起来有点奇怪的原因。可能想在输出中考虑到这一点。