Найти недельные периоды (начиная с понедельника) в течение месяца

Я пытаюсь найти недельные периоды для данного месяца и года. Даты должны начинаться в понедельник и заканчиваться в воскресенье. Если первый месяц – воскресенье (Ex May 2011), это должен быть первый элемент.

Май 2011 г.

  • 1 мая (воскресенье)
  • 2 мая – 8 мая (понедельник – воскресенье)
  • 9 мая – 15 мая (понедельник – воскресенье)
  • 17 мая – Ma6y 22 (понедельник – воскресенье)
  • 23 мая – 29 мая (понедельник – воскресенье)
  • 30 мая – 31 мая (понедельник – вторник)

Сентябрь 2012 г.

  • 1 сентября – 2 сентября
  • 3 сентября – 9 сентября
  • 10 сентября – 16 сентября
  • 17 сентября – 23 сентября
  • 24 сентября – 30 сентября

Я использую эту функцию для вычисления чисел недели для двух дат – т.е. 1-го числа месяца и последнего дня месяца.

public function getWeekNumbers($startDate, $endDate) { $p = new DatePeriod( new DateTime($startDate), new DateInterval('P1W'), new DateTime($endDate) ); $weekNumberList = array(); foreach ($p as $w) { $weekNumber = $w->format('W'); $weekNumberList[] = ltrim($weekNumber, '0'); } return $weekNumberList; } 

Как ни странно, за январь он возвращает номера недели [52, 1, 2, 3, 4], когда я ожидаю [1, 2, 3, 4, 5].

Когда у меня есть номера недели, я использую их так:

 //The following loop will populate the dataset with the entire month's durations - regardless if hours were worked or not. $firstDayOfMonth = date('Ym-d', strtotime("first day of {$this->year}-{$monthName}")); $lastDayOfMonth = date('Ym-d', strtotime("last day of {$this->year}-{$monthName}")); foreach ($this->getWeekNumbers($firstDayOfMonth, $lastDayOfMonth) as $key => $weekId) { // find first mоnday of the year $firstMon = strtotime("mon jan {$this->year}"); // calculate how many weeks to add $weeksOffset = $weekId - date('W', $firstMon); $beginDays = $weeksOffset * 7; $endDays = ($weeksOffset * 7) + 6; $searchedMon = strtotime(date('Ym-d', $firstMon) . " +{$beginDays} days"); $searchedSun = strtotime(date('Ym-d', $firstMon) . " +{$endDays} days"); echo date("M d", $searchedMon) . " - " . date("M d", $searchedSun); } 

Поскольку функция getWeekNumbers не возвращает числа недель, которые я ожидаю, неудивительно, что вывод вышеуказанной функции

  • 24 декабря – 30 декабря (2012)
  • Январь 02 – Январь 08 (2012)
  • Январь 09 – Январь 15 (2012)
  • 16 января – 22 января (2012)
  • 23 января – 29 января (2012)

Обратите внимание, что 1-я строка (24 декабря – 30 декабря) – конец текущего года (2012), а не конец прошлого года (2011 год).

В идеале я хочу, чтобы это выглядело введите описание изображения здесь

Есть идеи? Благодаря!!

Если вам нужны все недели в течение выбранного месяца и всех дат для выбранной недели, то это все, что вам нужно:

 function getWeekDays($month, $year) { $p = new DatePeriod( DateTime::createFromFormat('!Yn-d', "$year-$month-01"), new DateInterval('P1D'), DateTime::createFromFormat('!Yn-d', "$year-$month-01")->add(new DateInterval('P1M')) ); $datesByWeek = array(); foreach ($p as $d) { $dateByWeek[ $d->format('W') ][] = $d; } return $dateByWeek; } 

Функция getWeekDays () возвращает многомерный массив. первый ключ – номер недели. 2 – это массив, который имеет даты, сохраненные как объект DateTime.

Пример выборки:

 print_r( getWeekDays(5, 2011) ); # May 2011 print_r( getWeekDays(9, 2012) ); # Sep 2012 

У меня было немного времени, поэтому я написал пример 😉

 $datesByWeek = getWeekDays(8, 2012); $o = '<table border="1">'; $o.= '<tr><th>Week</th><th>Monday</th><th>Tuesday</th><th>Wednesday</th><th>Thursday</th><th>Friday</th><th>Saturday</th><th>Sunday</th></tr>'; foreach ($datesByWeek as $week => $dates) { $firstD = $dates[0]; $lastD = $dates[count($dates)-1]; $o.= "<tr>"; $o.= "<td>" . $firstD->format('M d') . ' - ' . $lastD->format('M d') . "</td>"; $N = $firstD->format('N'); for ($i = 1; $i < $N; $i++) { $o.= "<td>-</td>"; } foreach ($dates as $d) { $o.= "<td>" . $d->format('d.') . " / 0.00</td>"; # for selected date do you magic } $N = $lastD->format('N'); for ($i = $N; $i < 7; $i++) { $o.= "<td>-</td>"; } $o.= "</tr>"; } $o.= '</table>'; echo $o; 

Результат выглядит так: введите описание изображения здесь

это работает отлично !!! phpfiddle здесь

 <?php // start and end must be timestamps !!!! $start = 1346976000; // Thu 2012-09-06 $end = 1348704000; // Tue 2012-09-26 // generate the weeks $weeks = generateweeks($start, $end); // diaplay the weeks echo 'From: '.fDate($start).'<br>'; foreach ($weeks as $week){ echo fDate($week['start']).' '.fDate($week['end']).'<br>'; } echo 'To: '.fDate($end).'<br>'; /* outputs this: From: Thu 2012-09-06 Thu 2012-09-06 Sun 2012-09-09 Mon 2012-09-10 Sun 2012-09-16 Mon 2012-09-17 Sun 2012-09-23 Mon 2012-09-24 Wed 2012-09-26 To: Wed 2012-09-26 */ // $start and $end must be unix timestamps (any range) // returns an array of arrays with 'start' and 'end' elements set // for each week (or part of week) for the given interval // return values are also in timestamps function generateweeks($start,$end){ $ret = array(); $start = E2D($start); $end = E2D($end); $ns = nextSunday($start); while(true){ if($ns>=$end) {insert($ret,$start,$end);return $ret;} insert($ret,$start,$ns); $start = $ns +1; $ns+=7; } } // helper function to append the array and convert back to unix timestamp function insert(&$arr, $start, $end){$arr[] = array('start'=>D2E($start), 'end'=>D2E($end));} // recives any date on CD format returns next Sunday on CD format function nextSunday($Cdate){return $Cdate + 6 - $Cdate % 7;} // recives any date on CD format returns previous Monday on CD format // finaly not used here function prevMonday($Cdate){return $Cdate - $Cdate % 7;} // recives timestamp returns CD function E2D($what){return floor($what/86400)+2;} // floor may be optional in some circunstances // recives CD returns timestamp function D2E($what){return ($what-2)*86400;} // 24*60*60 // just format the timestamp for output, you can adapt it to your needs function fDate($what){return date('D Ym-d',$what);} в <?php // start and end must be timestamps !!!! $start = 1346976000; // Thu 2012-09-06 $end = 1348704000; // Tue 2012-09-26 // generate the weeks $weeks = generateweeks($start, $end); // diaplay the weeks echo 'From: '.fDate($start).'<br>'; foreach ($weeks as $week){ echo fDate($week['start']).' '.fDate($week['end']).'<br>'; } echo 'To: '.fDate($end).'<br>'; /* outputs this: From: Thu 2012-09-06 Thu 2012-09-06 Sun 2012-09-09 Mon 2012-09-10 Sun 2012-09-16 Mon 2012-09-17 Sun 2012-09-23 Mon 2012-09-24 Wed 2012-09-26 To: Wed 2012-09-26 */ // $start and $end must be unix timestamps (any range) // returns an array of arrays with 'start' and 'end' elements set // for each week (or part of week) for the given interval // return values are also in timestamps function generateweeks($start,$end){ $ret = array(); $start = E2D($start); $end = E2D($end); $ns = nextSunday($start); while(true){ if($ns>=$end) {insert($ret,$start,$end);return $ret;} insert($ret,$start,$ns); $start = $ns +1; $ns+=7; } } // helper function to append the array and convert back to unix timestamp function insert(&$arr, $start, $end){$arr[] = array('start'=>D2E($start), 'end'=>D2E($end));} // recives any date on CD format returns next Sunday on CD format function nextSunday($Cdate){return $Cdate + 6 - $Cdate % 7;} // recives any date on CD format returns previous Monday on CD format // finaly not used here function prevMonday($Cdate){return $Cdate - $Cdate % 7;} // recives timestamp returns CD function E2D($what){return floor($what/86400)+2;} // floor may be optional in some circunstances // recives CD returns timestamp function D2E($what){return ($what-2)*86400;} // 24*60*60 // just format the timestamp for output, you can adapt it to your needs function fDate($what){return date('D Ym-d',$what);} 

Следующее предполагает, что пользователь может выбрать месяц и год, за которые они хотят запустить отчет (стоимость размещена 1-12 в месяц и ГГГГ за год). Там может быть более элегантный способ сделать это, но это, похоже, работает для меня. Кроме того, в верхней части вашего сообщения вы говорите, что хотите, чтобы недели были в понедельник – воскресенье. Тем не менее, ваш пример / снимок экрана внизу показывает недели с воскресенья по субботу. Ниже приведена первоначально заявленная цель с понедельника по воскресенье.

 $month = $_POST["month"]; $year = $_POST["year"]; $endDate = date("t", strtotime($year."-".$month."-01")); $dayOfWeekOfFirstOfMonth = date("w", strtotime($year."-".$month."-01")); $lastDayOfFirstWeek = 8 - $dayOfWeekOfFirstOfMonth; $weeksArray = array(array("firstDay"=>1, "lastDay"=>$lastDayOfFirstWeek)); $loopDate = $lastDayOfFirstWeek + 1; while($loopDate < $endDate) { $weeksArray[] = array("firstDay"=>$loopDate, "lastDay"=>($loopDate+6 > $endDate ? $endDate : $loopDate+6)); $loopDate+=7; } foreach($weeksArray as $week) { echo date("M d", strtotime($year."-".$month."-".$week["firstDay"])) . " - " . date("M d", strtotime($year."-".$month."-".$week["lastDay"])) . "\n"; }