Search code examples
phpcalendarweek-number

Get week number for given month of year for presentation on calendar


I'm creating a calendar with Sunday being the start of each week and I want to present the week number of the year before each row of dates.

This is my calendar

my calendar

How can I add week numbers like this:

This is what I need

My code:

<?php
function generate_calendar($month, $year) {
    $calendar = array();
    $days_in_month = cal_days_in_month(CAL_GREGORIAN, $month, $year);
    $first_day_of_month = date('w', strtotime("$year-$month-01"));
    $week_number = 1;
    $week = array();
    
    // Determine the week number offset
    $days_from_january_1st = strtotime("$year-01-01");
    $days_to_first_day_of_month = strtotime("$year-$month-01");
    $week_number_offset = floor(($days_to_first_day_of_month - $days_from_january_1st) / 604800);
    
    // Check if the last week of the previous month is full (7 days)
    $last_week_of_previous_month = $week_number_offset;

    if ($month > 1) {
        $previous_month = $month - 1;
        $previous_month_year = $year;

    $previous_month_year = date("Y", strtotime("-1 month" , strtotime("$year-$month-01")));
    $previous_month = date("n", strtotime("-1 month" , strtotime("$year-$month-01")));

        if ($previous_month == 0) {
            $previous_month = 12;
            $previous_month_year = $year - 1;
        }

        $days_in_previous_month = cal_days_in_month(CAL_GREGORIAN, $previous_month, $previous_month_year);
        $last_day_of_previous_month = date('w', strtotime("$previous_month_year-$previous_month-$days_in_previous_month"));
        if ($last_day_of_previous_month == 6) {
            $last_week_of_previous_month=$last_week_of_previous_month + 1;
        } else {
            // Check if the last week of the previous month only has a few days
            $last_week_of_previous_month = $last_week_of_previous_month;
        }
    }
    
    // Generate the previous month's days
    for ($i = 1; $i <= $first_day_of_month; $i++) {
        array_unshift($week, "");
    }
    
    // Generate the current month's days
    for ($i = 1; $i <= $days_in_month; $i++) {
        $week[] = $i;
        if (count($week) == 7) {
            $calendar[$week_number + $last_week_of_previous_month] = $week;
            $week_number++;
            $week = array();
        }
    }
    
    // Generate the next month's days
    $remaining_days = 7 - count($week);
    for ($i = 1; $i <= $remaining_days; $i++) {
        $week[] = '';
    }
    
    if (!empty($week)) {
        $calendar[$week_number + $last_week_of_previous_month] = $week;
    }
    
    return $calendar;
}

$year = 2022;
echo "<table>\n";
echo "  <tr>\n";
echo "    <th colspan='3'>$year</th>\n";
echo "  </tr>\n";

echo "  <tr>\n";
for($i=1; $i<=12; $i++){

$month_name = date('F Y', strtotime("$year-$i-01"));
$calendar = generate_calendar($i, $year);


echo "<td>\n";
echo "<table>\n";
echo "  <tr>\n";
echo "    <th colspan='8'>$month_name</th>\n";
echo "  </tr>\n";
echo "  <tr>\n";
echo "    <th>Week</th>\n";
echo "    <th>Sun</th>\n";
echo "    <th>Mon</th>\n";
echo "    <th>Tue</th>\n";
echo "    <th>Wed</th>\n";
echo "    <th>Thu</th>\n";
echo "    <th>Fri</th>\n";
echo "    <th>Sat</th>\n";
echo "  </tr>\n";
foreach ($calendar as $week_number => $week) {
    echo "  <tr>\n";
    echo "    <td>$week_number</td>\n";
    foreach ($week as $day) {
        if (empty($day)) {
            echo "    <td></td>\n";
        } else {
            echo "    <td>$day</td>\n";
        }
    }
    echo "  </tr>\n";
}
echo "</table>\n";
echo "</td>\n";

if($i==3 || $i==6 || $i==9){
echo "  </tr>\n";
echo "  <tr>\n";
}

}

echo "  </tr>\n";
echo "</table>\n";

?>

Trying to add week number which counts from first week of January (if last week of previous month is not full 7 days then first week of current month start from last week of previous month), but my code only count from first week of current month.


Solution

  • I managed to get the right result (as far as I tested) with IntlCalendar and its FIELD_WEEK_OF_YEAR constant instead of counting Sundays.

    I did some refactoring of your function, but ran out of time to do a full reduction of the script (there may still be lines that can be simplified/condensed).

    Code: (Demo)

    function generate_calendar(int $month, int $year) {
        $calendar = [];
        
        $week_number = (IntlCalendar::fromDateTime ("$year-$month-01"))->get(IntlCalendar::FIELD_WEEK_OF_YEAR);
        $month_start = new DateTime("$year-$month-01");
    
        // Generate the previous month's days
        if ($first_day = $month_start->format('w')) {
            $week = array_fill(1, $first_day, '');
        }
    
        // Generate the current month's days
        $days_in_month = $month_start->format('t');
        for ($i = 1; $i <= $days_in_month; $i++) {
            $week[] = $i;
            if (count($week) == 7) {
                $calendar[$week_number] = $week;
                $week_number++;
                $week = [];
            }
        }
    
        if ($week) {
            // Generate empty days for the next month
            $calendar[$week_number] = array_pad($week, 7, '');
        }
        
        return $calendar;
    }