6

可能重复:
检查集合内的连续日期并作为范围返回

我有一个从 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 日、6 月 29 日至 7 月 1 日

我怎样才能做到这一点?我不知道从哪里开始。

4

7 回答 7

5

这是完整的工作答案。(享受!)

您必须遍历 $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
于 2013-01-07T18:10:05.347 回答
0

我无法为您提供 acutal 代码,但您可以执行以下操作:

  • 查找范围的起点和终点
  • 计算中间步数(1 步 = 1 天)
  • 使用 mktime(或 DateTime 或 strftime)根据开始日期 + 步骤天数计算结束日期)
  • 随心所欲地打印出来。
于 2013-01-07T17:56:49.740 回答
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
于 2013-01-07T18:00:13.033 回答
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如果我是你,我会这样做。

于 2013-01-07T18:06:16.393 回答
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

注意:我没有测试上面的代码,所以它可能包含拼写错误。

我只是在数组中的每一天进行迭代,并确定它是否是前一天的连续一天。如果是,则将其添加到同一组中,如果不是,则将其添加到不同的数组索引中。在此之后,您可能需要使用php 中的某种排序功能对日期进行排序。然后遍历数组组以确定日期范围。

于 2013-01-07T18:06:21.130 回答
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);
于 2013-01-07T18:32:15.683 回答
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

请注意,这是正确处理年份。这就是为什么输出看起来有点奇怪的原因。可能想在输出中解释这一点。

于 2013-01-07T20:08:19.013 回答