Вопрос по week-number, php, time, period, duration – Найти еженедельные периоды (начиная с понедельника) за месяц

1

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

Май 2011

1 мая (воскресенье)2 мая - 8 мая (понедельник - воскресенье)9 мая - 15 мая (понедельник - воскресенье)17 мая - 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('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 невозвращаю номера недели, которые яЯ ожидаю, этоНе удивительно, что на выходе вышеупомянутой функции

24 декабря - 30 декабря 2012 года02 января - 8 января (2012)09 января - 15 января (2012)16 января - 22 января (2012)23 января - 29 января (2012)

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

В идеале я хочу, чтобы это выглядело как

Есть идеи? Спасибо!!

ты решил свою проблему? Вы можете проголосовать здесь, если они будут полезны. Вы можете выбрать ответчик, который закрывает проблему. Но в другом случае вы можете опубликовать свой собственный ответ на проблему, чтобы поделиться тем, как она была решена. Luis Siquot

Ваш Ответ

3   ответа
2

это работает отлично !!! 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 Y-m-d',$what);}
1

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

$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";
}
3

ой недели, то это все, что вам нужно:

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.

Извлечь пример:

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

У меня было немного дополнительного времени, поэтому я написал пример ;-)

$datesByWeek = getWeekDays(8, 2012);
$o = '';
$o.= '';
foreach ($datesByWeek as $week => $dates) {
    $firstD = $dates[0];
    $lastD = $dates[count($dates)-1];

    $o.= "";
    $o.= "";
    $N = $firstD->format('N');
    for ($i = 1; $i < $N; $i++) {
        $o.= "";
    }
    foreach ($dates as $d) {
        $o.= "";
            # for selected date do you magic
    }
    $N = $lastD->format('N');
    for ($i = $N; $i < 7; $i++) {
        $o.= "";
    }
    $o.= "";
}
$o.= '<table border="1"><tbody><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><tr><td>" . $firstD->format('M d') . ' - ' . $lastD->format('M d') . "</td><td>-</td><td>" . $d->format('d.') . " / 0.00</td><td>-</td></tr></tbody></table>';
echo $o;

Вывод выглядит так:

Вау - это сработало отлично! Большое спасибо за ваше время и усилия. waterloomatt

Похожие вопросы