Проверять последовательные даты в наборе и возвращать как диапазон

У меня есть массивы дат формата Ymd, которые могут быть любой комбинацией из десяти заданных дат, разделенных на один день.

Например, вот полный набор:

2011-01-01, 2011-01-02, 2011-01-03, 2011-01-04, 2011-01-05, 2011-01-06, 2011-01-07, 2011-01-08, 2011- 01-09, 2011-01-10

Массивы, созданные из этого набора, могут быть любой комбинацией дат – все из них, одна из них, несколько последовательных, все подряд и т. Д.

В настоящее время я их печатаю много, так как они возвращаются. например, это возможный результат:

2011-01-02

2011-01-03

2011-01-04

2011-01-08

(то, что на самом деле напечатано, больше похоже на «Пятница, 2 января …», но мы будем придерживаться простой строки даты)

Я хотел бы сконденсировать его так, чтобы, если есть три или более последовательных дня, они становятся диапазоном, например, приведенный выше пример стал бы следующим:

2011-01-02 – 2011-01-04

2011-01-08

который в конечном итоге станет:

Воскресенье, 2 января – вторник, 4 января

Суббота 8 января

Есть ли способ перебирать и проверять разницу во времени, создавать время начала и время окончания диапазона (ов), а затем собирать отставших?

Немного быстрого ответа, так жаль об отсутствии реализации, но при условии, что вы используете 5.3, а даты упорядочены в хронологическом порядке, вы можете конвертировать каждую дату в объект DateTime (если они еще не были), а затем перебирать массив с помощью DateTime::diff() для создания объекта DateInterval который вы могли бы использовать для сравнения текущей даты на итерации с последним. Вы можете группировать свои последовательные даты в подматрицы и использовать shift() и pop() чтобы получить первый и последний дни в этом вспомогательном массиве.

РЕДАКТИРОВАТЬ

Я подумал об этом. Довольно грубая и готовая реализация следует, но она должна работать:

 // assuming a chronologically // ordered array of DateTime objects $dates = array( new DateTime('2010-12-30'), new DateTime('2011-01-01'), new DateTime('2011-01-02'), new DateTime('2011-01-03'), new DateTime('2011-01-06'), new DateTime('2011-01-07'), new DateTime('2011-01-10'), ); // process the array $lastDate = null; $ranges = array(); $currentRange = array(); foreach ($dates as $date) { if (null === $lastDate) { $currentRange[] = $date; } else { // get the DateInterval object $interval = $date->diff($lastDate); // DateInterval has properties for // days, weeks. months etc. You should // implement some more robust conditions here to // make sure all you're not getting false matches // for diffs like a month and a day, a year and // a day and so on... if ($interval->days === 1) { // add this date to the current range $currentRange[] = $date; } else { // store the old range and start anew $ranges[] = $currentRange; $currentRange = array($date); } } // end of iteration... // this date is now the last date $lastDate = $date; } // messy... $ranges[] = $currentRange; // print dates foreach ($ranges as $range) { // there'll always be one array element, so // shift that off and create a string from the date object $startDate = array_shift($range); $str = sprintf('%s', $startDate->format('D j M')); // if there are still elements in $range // then this is a range. pop off the last // element, do the same as above and concatenate if (count($range)) { $endDate = array_pop($range); $str .= sprintf(' to %s', $endDate->format('D j M')); } echo "<p>$str</p>"; } 

Выходы:

 Thu 30 Dec Sat 1 Jan to Mon 3 Jan Thu 6 Jan to Fri 7 Jan Mon 10 Jan