Я создаю календарь, в котором воскресенье является началом каждой недели, и я хочу представить номер недели года перед каждой строкой дат.
Это мой календарь
Мой календарь
Как я могу добавить номера недель следующим образом:
Это то, что мне нужно
Мой код:
<?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') для начала понедельника. я хочу, чтобы календарь начинался с воскресенья, вот почему.
Нижний регистр w для дня недели... верхний регистр W для номера недели в году
Stackoverflow.com/questions/16057039/… решает проблему?
@IndraKumarS . да
Я не верю, что в стандартной библиотеке 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;
}
Почему бы не использовать date('W')? Кажется, здесь много дополнительной работы. Также вам не нужен echo для каждой строки.