0

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:

M T W T F S S

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

Michael
  • 1,769
  • 2
  • 12
  • 21
  • 1
    You are meant to include your coding attempt, even if it is very poor. Posting your code proves that you have tried to self solve and shows how much research you have done before posting your question. Currently it appears that you are using SO as a free coding service. This may or may not be true. Either way, your question needs an edit. – mickmackusa Aug 11 '17 at 21:36
  • I never asked for a code solution, I was only asking for the logic! The answer below demonstrates the logic so I can understand which I am grateful. – Michael Aug 11 '17 at 21:39
  • That is irrelevant. You are always meant to include your attempt. I'm not calling you a bad person. Please update your question. It can be mixed semi-code that has comments where logic components are but also uses basic php loops and other actual syntax. Doing this step helps people to self solve while writing their question - which cuts down the total questions that hit SO. When the isolated issues cannot be fixed by the OP, volunteers can make simple adjustments, rather than writing a full block of code from scratch. Again, not calling you a bad person. – mickmackusa Aug 11 '17 at 21:47
  • Your question was flagged as too broad and I came here from the Review queue. Think of code as cars -- volunteers are meant to be car mechanics, not car manufacturers. In the future, please isolate your issue a bit more. – mickmackusa Aug 11 '17 at 21:59

2 Answers2

1

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
Nate
  • 1,442
  • 14
  • 22
  • Thanks for this, I think I get the jist of the logic used. I just need to now build this into my calendar so that at the end of each row (each week) is displays the week number, I will update with any progress – Michael Aug 11 '17 at 21:40
1

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.

mickmackusa
  • 43,625
  • 12
  • 83
  • 136
  • Wow, I am really unimpressed by some of the advice in that phpjabber link. If my answer does not solve your issue, can you clarify which part has you hung up. Is your calendar interactive? Do you have data to insert in the day cells? – mickmackusa Aug 12 '17 at 12:43
  • I think it's more around how I would integrate your solution. Not sure if you have ran the code I added to see the results – Michael Aug 12 '17 at 12:56
  • @Michael I am going to cut myself off after this edit, so that I am not doing all of your coding for you. This answer should give you sufficient traction. If you have questions about my answer, feel free to ask. – mickmackusa Aug 13 '17 at 07:24
  • Thanks, I have eventually done it, basically I counted how many weeks between first Monday in April and the first Monday in the current month. Then for each row of the calendar table I added 1. Simple once I thought about it – Michael Aug 13 '17 at 19:56