Получить номер недели для данного месяца года для представления в календаре

Я создаю календарь, в котором воскресенье является началом каждой недели, и я хочу представить номер недели года перед каждой строкой дат.

Это мой календарь

Мой календарь

Как я могу добавить номера недель следующим образом:

Это то, что мне нужно

Мой код:

<?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";

?>

Попытка добавить номер недели, который считается с первой недели января (если последняя неделя предыдущего месяца не полна 7 дней, тогда первая неделя текущего месяца начинается с последней недели предыдущего месяца), но мой код учитывает только первую неделю текущего месяца .

Почему бы не использовать date('W')? Кажется, здесь много дополнительной работы. Также вам не нужен echo для каждой строки.

user3783243 13.02.2023 04:00

Date('w') для начала понедельника. я хочу, чтобы календарь начинался с воскресенья, вот почему.

wowtom16 13.02.2023 04:02

Нижний регистр w для дня недели... верхний регистр W для номера недели в году

Indra Kumar S 13.02.2023 04:04

Stackoverflow.com/questions/16057039/… решает проблему?

user3783243 13.02.2023 04:07

@IndraKumarS . да

wowtom16 13.02.2023 12:09
Laravel с Turbo JS
Laravel с Turbo JS
Turbo - это библиотека JavaScript для упрощения создания быстрых и высокоинтерактивных веб-приложений. Она работает с помощью техники под названием...
Аутсорсинг разработки PHP для индивидуальных веб-решений
Аутсорсинг разработки PHP для индивидуальных веб-решений
Услуги PHP-разработки могут быть экономически эффективным решением для компаний, которые ищут высококачественные услуги веб-разработки по доступным...
Еще один бенчмарк PHP
Еще один бенчмарк PHP
Сегодня я наткнулся на забавный пост на r/ProgrammerHumor, который заставил меня задуматься об одной вещи, которая меня всегда интересовала....
Преобразование данных с помощью красноречивых аксессоров и мутаторов в Laravel
Преобразование данных с помощью красноречивых аксессоров и мутаторов в Laravel
Laravel поставляется с мощной функцией под названием "Eloquent Accessors and Mutators".
Настройка PHP-проекта на MacOS: простое руководство для начинающих
Настройка PHP-проекта на MacOS: простое руководство для начинающих
PHP, широко используемый язык сценариев с открытым исходным кодом, необходим для веб-разработки. Его совместимость с MacOS делает его популярным...
Конечные и Readonly классы в PHP
Конечные и Readonly классы в PHP
В прошлом, когда вы не хотели, чтобы другие классы расширяли определенный класс, вы могли пометить его как final.
0
5
54
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Я не верю, что в стандартной библиотеке PHP есть способ установить день начала недели без ручного вычисления, но вы можете легко сделать это с помощью библиотеки intl (убедитесь, что расширение intl PHP включено):

$cal = IntlGregorianCalendar::createInstance();

// Set start of week to Sunday
$cal->setFirstDayOfWeek(IntlGregorianCalendar::DOW_SUNDAY);

// Get week number of the year for the current date
$weekOfYear = intval(IntlDateFormatter::formatObject($cal, 'w'));

// Advance to the next week
$cal->add(IntlGregorianCalendar::FIELD_WEEK_OF_YEAR, 1);

// ect...
Ответ принят как подходящий

Мне удалось получить правильный результат (насколько я тестировал) с IntlCalendar и его константой FIELD_WEEK_OF_YEAR вместо подсчета воскресений.

Я сделал рефакторинг вашей функции, но не хватило времени, чтобы сделать полное сокращение скрипта (могут быть еще строки, которые можно упростить/сжать).

Код: (Демо)

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;
}

Другие вопросы по теме