问题
I'm trying to find the weekly periods for a given month and year. Dates should start on a Monday and end on a Sunday. If the 1st of the month is a Sunday (Ex May 2011), it should be the first element.
May 2011
- May 1 (Sunday)
- May 2 - May 8 (Monday - Sunday)
- May 9 - May 15 (Monday - Sunday)
- May 17 - Ma6y 22 (Monday - Sunday)
- May 23 - May 29 (Monday - Sunday)
- May 30 - May 31 (Monday - Tuesday)
September 2012
- September 1 - September 2
- September 3 - September 9
- September 10 - September 16
- September 17 - September 23
- September 24 - September 30
I am using this function to calculate the week numbers for two dates - I.e. the 1st day of the month and last day of the month.
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;
}
Strangely, for the month of January, it returns week numbers of [52, 1, 2, 3, 4] when I'm expecting [1, 2, 3, 4, 5].
Once I have the week numbers, I'm using them like so:
//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);
}
Since, the getWeekNumbers function isn't returning the week numbers I'm expecting, it's not surprising that the output of the above function is
- Dec 24 - Dec 30 (2012)
- Jan 02 - Jan 08 (2012)
- Jan 09 - Jan 15 (2012)
- Jan 16 - Jan 22 (2012)
- Jan 23 - Jan 29 (2012)
Note that the 1st line (Dec 24 - Dec 30) is the end of the current year (2012) and not the end of last year (2011).
Ideally, I want it to look like
Any ideas? Thanks!!
回答1:
If you need all weeks for selected month, and all dates for selected week, then this is all you need:
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() function returns multi dimension array. first key is week number. 2 level is array, that has dates saved as DateTime object.
Fetch example:
print_r( getWeekDays(5, 2011) ); # May 2011
print_r( getWeekDays(9, 2012) ); # Sep 2012
I had a little time extra, so I written an example ;-)
$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;
Output looks like:
回答2:
this works perfect!!! phpfiddle here
<?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 Y-m-d',$what);}
回答3:
The following assumes that the user can pick the month and year for which they wan to run the report (the value posted being 1-12 for month and YYYY for year). There may be a more elegant way to do it, but this seems to work for me. Also, at the top of your post, you say that you want the weeks to be Monday - Sunday. However, your example/screenshot at the bottom shows weeks being Sunday to Saturday. The below is for the originally-stated goal of Monday - Sunday.
$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";
}
来源:https://stackoverflow.com/questions/12317909/find-weekly-periods-starting-on-a-monday-for-a-month