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

これはうまくいきます:

$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
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 に答える
0

あなたが持っているすべての日付は同じ年です。各日付をその年の日の数に変換できます。

次に、数値の配列があります。その配列については、ここで概説したように行うことができます:

もう 1 つの方法は、前の日付に基づいて次の日付を計算し、それを配列内の次の日付と比較することです。両方が等しい場合は現在の期間を延長し、そうでない場合は新しい期間を作成します。次に、配列をタイムスパンに減らします。

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

        )

)

これら 2 つのエントリは、マッピング関数を使用して出力スタイルに簡単にマッピングできるようになりました。

$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

実際のコードについてはお手伝いできませんが、次のようなことができます。

  • 範囲の始点と終点を見つける
  • その間の歩数を数える (1歩 = 1日)
  • mktime (または DateTime または strftime) を使用して、開始日 + ステップ日数に基づいて終了日を計算します)
  • 好きなように印刷してください。
于 2013-01-07T17:56:49.740 に答える
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 に答える