简体   繁体   中英

Get week number where the weeks start counting from first Monday in April until the first Monday next April in PHP

I am trying to achieve the following:

For reporting purposes our week numbers begin from the first Monday in April each year.

I am creating a calendar using PHP in the following format:

MTWTFSS

At the end of each row of that month I want to display the week number, starting at 1 where the first Monday in April will be week one all the way up to the next first Monday in April (next year) where it starts from one again.

I am struggling with the logic - can any one suggest a solution?

Thanks

EDIT see my code below, basically what I am trying to do is instead of having the week number from jan 01, have it from the first Monday in April:

<?php
$monthNames = Array("January", "February", "March", "April", "May",     "June", "July", 
"August", "September", "October", "November", "December");
?>

<?php
if (!isset($_REQUEST["month"])) $_REQUEST["month"] = date("n");
if (!isset($_REQUEST["year"])) $_REQUEST["year"] = date("Y");
?>

<?php
$cMonth = $_REQUEST["month"];
$cYear = $_REQUEST["year"];

$prev_year = $cYear;
$next_year = $cYear;
$prev_month = $cMonth-1;
$next_month = $cMonth+1;

if ($prev_month == 0 ) {
    $prev_month = 12;
    $prev_year = $cYear - 1;
}
if ($next_month == 13 ) {
    $next_month = 1;
    $next_year = $cYear + 1;
}
?>

<table width="250">
<tr align="center">
<td bgcolor="#999999" style="color:#FFFFFF">
<table width="100%" border="0" cellspacing="0" cellpadding="0">
<tr>
<td width="50%" align="left">  <a href="<?php echo $_SERVER["PHP_SELF"] . "?month=". $prev_month . "&year=" . $prev_year; ?>" style="color:#FFFFFF">Previous</a></td>
<td width="50%" align="right"><a href="<?php echo $_SERVER["PHP_SELF"] . "?month=". $next_month . "&year=" . $next_year; ?>" style="color:#FFFFFF">Next</a>  </td>
</tr>
</table>
</td>
</tr>
<tr>
<td align="center">
<table width="100%" border="0" cellpadding="2" cellspacing="2">
<tr align="center">
<td colspan="8" bgcolor="#999999" style="color:#FFFFFF"><strong><?php echo $monthNames[$cMonth-1].' '.$cYear; ?></strong></td>
</tr>
<tr>
<td align="center" bgcolor="#999999" style="color:#FFFFFF"><strong>M</strong></td>
<td align="center" bgcolor="#999999" style="color:#FFFFFF"><strong>T</strong></td>
<td align="center" bgcolor="#999999" style="color:#FFFFFF"><strong>W</strong></td>
<td align="center" bgcolor="#999999" style="color:#FFFFFF"><strong>T</strong></td>
<td align="center" bgcolor="#999999" style="color:#FFFFFF"><strong>F</strong></td>
<td align="center" bgcolor="#999999" style="color:#FFFFFF"><strong>S</strong></td>
<td align="center" bgcolor="#999999" style="color:#FFFFFF"><strong>S</strong></td>
<td align="center" bgcolor="#999999" style="color:#FFFFFF"><strong>Week No</strong></td>
</tr>


<?php 
$timestamp = mktime(0,0,0,$cMonth,1,$cYear);
$maxday = date("t",$timestamp);
$thismonth = getdate ($timestamp);
//$startday = $thismonth['wday'];
$startday = $thismonth['wday']-1;

$firstDateMonth = 0;

function roundToNearestW($int, $i) {
    return ceil($int / $i) * $i;
}

if ($startday == -1)
{
    $startday = 6;
}
$complete_cells = roundToNearestW($maxday+$startday,7);
for ($i=0; $i<($complete_cells); $i++) {
    if(($i % 7) == 0 )
    {
        echo "<tr>
        ";
    }
    if($i < $startday || $i >= $maxday+$startday)
    {
        echo "<td></td>
        ";
    }
    else
    {
        if(($i - $startday + 1) > $firstDateMonth)
        {
            $firstDateMonth = ($i - $startday + 1);
        }
        echo "<td align='center' valign='middle' height='20px'>". ($i - $startday + 1) . "</td>
        ";
    }
    if(($i % 7) == 6 )
    {
        $weekDate = $cYear."-".$cMonth."-".$firstDateMonth;
        $Caldate = new DateTime($weekDate);
        $week = $Caldate->format("W");
        echo "<td align='center' valign='middle' height='20px'>WK ".$week."</td>
        ";
    }
    if(($i % 7) == 6 )
    {
        echo "</tr>";
        //firstDateMonth = 0;
    }

}
?>



</table>
</td>
</tr>
</table>

Partial credit for above calendar (tweaked code slightly myself) to: https://www.phpjabbers.com/how-to-make-a-php-calendar-php26-4.html

I hope the following logic will suit your needs.

<?php

$begin    = new DateTime(date('Y-m-d', strtotime('first Monday of April this year')));
$end      = new DateTime(date('Y-m-d', strtotime('last Monday of March next year')));
$interval = DateInterval::createFromDateString('1 week');

$weekNumberOfFirstMondayInApril = $begin->format('W');

foreach (new DatePeriod($begin, $interval, $end) as $dt) {
    $phpWeekNum = $dt->format('W');

    $isFirstQuarter = ($phpWeekNum < $weekNumberOfFirstMondayInApril);

    $businessWeekNum = $isFirstQuarter
        ? ($phpWeekNum + (52 - $weekNumberOfFirstMondayInApril)) 
        : ($phpWeekNum - $weekNumberOfFirstMondayInApril) ;

    echo 'Date: ' . $dt->format('l, Y-m-d') . PHP_EOL;
    echo 'PHP week number: ' . $phpWeekNum . PHP_EOL;
    echo 'Business week number: ' . ($businessWeekNum + 1) . PHP_EOL;
    echo PHP_EOL;
}

It's output is as follows:

Date: Monday, 2017-04-03
PHP week number: 14
Business week number: 1

    <snip>

Date: Monday, 2017-12-25
PHP week number: 52
Business week number: 39

Date: Monday, 2018-01-01
PHP week number: 01
Business week number: 40

    <snip>

Date: Monday, 2018-03-26
PHP week number: 13
Business week number: 52

This seems less convoluted to me, with less processing inside the loop. DateInterval('P7D') just means set the interval to 7 days (1 week) -- this may be the only part that is mildly confusing because of the syntax. DatePeriod() does all the hard work for you.

Code ( Demo )

$year=2018;  // $_GET['year'];
$next=$year+1;
$start=new DateTime(date('Y-m-d', strtotime("first Monday of April $year")));
$stop=new DateTime(date('Y-m-d', strtotime("first Monday of April $next")));
// there is a known behavior of DatePeriod to stop before $stop (...not contain it)
// See http://au2.php.net/manual/en/class.dateperiod.php for explanations & workarounds
$range=new DatePeriod($start,new DateInterval('P7D'),$stop);
echo "<table>";
    echo "<tr>";
        echo "<th colspan=\"8\">Financial Calendar $year-$next</th>";
    echo "</tr>";
    echo "<tr>";
        echo "<th>M</th><th>T</th><th>W</th><th>T</th><th>F</th><th>S</th><th>S</th><th>#</th>";
    echo "</tr>";
    foreach ($range as $i=>$date) {
        echo "<tr>";
            echo "<td></td><td></td><td></td><td></td><td></td><td></td><td></td><td>",++$i,"(",$date->format("Y-m-d"),")</td>";
        echo "</tr>";
    }
echo "</table>";

Output (unrendered):

<table>
    <tr>
        <th colspan="8">Financial Calendar 2018-2019</th>
    </tr>
    <tr>
        <th>M</th><th>T</th><th>W</th><th>T</th><th>F</th><th>S</th><th>S</th><th>#</th>
    </tr>
    <tr>
        <td></td><td></td><td></td><td></td><td></td><td></td><td></td><td>1(2018-04-02)</td>
    </tr>
    <tr>
        <td></td><td></td><td></td><td></td><td></td><td></td><td></td><td>2(2018-04-09)</td>
    </tr>
    <tr>
        <td></td><td></td><td></td><td></td><td></td><td></td><td></td><td>3(2018-04-16)</td>
    </tr>
    ...
    <tr>
        <td></td><td></td><td></td><td></td><td></td><td></td><td></td><td>50(2019-03-11)</td>
    </tr>
    <tr>
        <td></td><td></td><td></td><td></td><td></td><td></td><td></td><td>51(2019-03-18)</td>
    </tr>
    <tr>
        <td></td><td></td><td></td><td></td><td></td><td></td><td></td><td>52(2019-03-25)</td>
    </tr>
</table>

Now, I don't want to rob you of the opportunity to develop this code for yourself, so I'll stop here. This should give you a foothold to finish this project to your desired specification.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM