Find weekly periods (starting on a Monday) for a month
我正在尝试查找给定月份和年份的每周时段。日期应从星期一开始,到星期日结束。如果每月的1号是星期日(例如2011年5月),则它应该是第一个元素。
2011年5月
- 5月1日(星期日)
- 5月2日-5月8日(星期一-星期日)
- 5月9日-5月15日(星期一-星期日)
- 5月17日-6月22日(星期一-星期日)
- 5月23日-5月29日(星期一-星期日)
- 5月30日-5月31日(星期一-星期二)
2012年9月
- 9月1日-9月2日
- 9月3日-9月9日
- 9月10日至9月16日
- 9月17日至9月23日
- 9月24日至9月30日
我正在使用此功能来计算两个日期的星期数-即该月的第一天和该月的最后一天。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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; } |
奇怪的是,对于一月,当我期望为[1、2、3、4、5]时,它返回的周数为[52、1、2、3、4]。
一旦有了周数,就可以像这样使用它们:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | //The following loop will populate the dataset with the entire month's durations - regardless if hours were worked or not. $firstDayOfMonth = date('Y-m-d', strtotime("first day of {$this->year}-{$monthName}")); $lastDayOfMonth = date('Y-m-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('Y-m-d', $firstMon) ." +{$beginDays} days"); $searchedSun = strtotime(date('Y-m-d', $firstMon) ." +{$endDays} days"); echo date("M d", $searchedMon) ." -" . date("M d", $searchedSun); } |
由于getWeekNumbers函数未返回我期望的星期数,因此上述函数的输出为
- 2012年12月24日至12月30日
- Jan 02-Jan 08(2012)
- Jan 09-Jan 15(2012)
- Jan 16-Jan 22(2012)
- Jan 23-Jan 29(2012)
请注意,第一行(12月24日至12月30日)是当年(2012年)的结束日期,而不是去年(2011年)的结束日期。
理想情况下,我希望它看起来像
有任何想法吗?谢谢!!
如果您需要选定月份的所有星期,以及选定星期的所有日期,那么这就是您所需要的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | function getWeekDays($month, $year) { $p = new DatePeriod( DateTime::createFromFormat('!Y-n-d',"$year-$month-01"), new DateInterval('P1D'), DateTime::createFromFormat('!Y-n-d',"$year-$month-01")->add(new DateInterval('P1M')) ); $datesByWeek = array(); foreach ($p as $d) { $dateByWeek[ $d->format('W') ][] = $d; } return $dateByWeek; } |
getWeekDays()函数返回多维数组。 第一个关键是星期几。 2级是数组,其日期保存为DateTime对象。
获取示例:
我多了一点时间,所以写了一个例子;-)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | $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; |
输出如下:
以下内容假定用户可以选择运行报表所要使用的月份和年份(发布的值分别为1-12和YYYY)。 可能有一种更优雅的方法可以执行此操作,但这似乎对我有用。 另外,在帖子的顶部,您说您希望星期是星期一-星期日。 但是,您在底部的示例/屏幕截图显示了周日至周日。 以下是周一至周日最初规定的目标。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | $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"])) ."\ "; } |
这很完美!!! phpfiddle在这里
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | <?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).''; foreach ($weeks as $week){ echo fDate($week['start']).' '.fDate($week['end']).''; } echo 'To: '.fDate($end).''; /* 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 Y-m-d',$what);} |