Календарь на PHP

PHP-класс для вывода календаря на месяц, год или любой другой интервал с возможностью выделить отдельные даты и вывести к ним подсказки.

class Calendar 
{
	/**
	 * Вывод календаря на один месяц.
	 */
	public static function  getMonth($month, $year, $events = array())
	{
		$months = array(
			1  => 'Январь',
			2  => 'Февраль',
			3  => 'Март',
			4  => 'Апрель',
			5  => 'Май',
			6  => 'Июнь',
			7  => 'Июль',
			8  => 'Август',
			9  => 'Сентябрь',
			10 => 'Октябрь',
			11 => 'Ноябрь',
			12 => 'Декабрь'
		);
 
		$month = intval($month);
		$out = '
		<div class="calendar-item">
			<div class="calendar-head">' . $months[$month] . ' ' . $year . '</div>
			<table>
				<tr>
					<th>Пн</th>
					<th>Вт</th>
					<th>Ср</th>
					<th>Чт</th>
					<th>Пт</th>
					<th>Сб</th>
					<th>Вс</th>
				</tr>';
 
		$day_week = date('N', mktime(0, 0, 0, $month, 1, $year));
		$day_week--;
 
		$out.= '<tr>';
 
		for ($x = 0; $x < $day_week; $x++) {
			$out.= '<td></td>';
		}
 
		$days_counter = 0;		
		$days_month = date('t', mktime(0, 0, 0, $month, 1, $year));
	
		for ($day = 1; $day <= $days_month; $day++) {
			if (date('j.n.Y') == $day . '.' . $month . '.' . $year) {
				$class = 'today';
			} elseif (time() > strtotime($day . '.' . $month . '.' . $year)) {
				$class = 'last';
			} else {
				$class = '';
			}
			
			$event_show = false;
			$event_text = array();
			if (!empty($events)) {
				foreach ($events as $date => $text) {
					$date = explode('.', $date);
					if (count($date) == 3) {
						$y = explode(' ', $date[2]);
						if (count($y) == 2) {
							$date[2] = $y[0];
						}

						if ($day == intval($date[0]) && $month == intval($date[1]) && $year == $date[2]) {
							$event_show = true;
							$event_text[] = $text;
						}
					} elseif (count($date) == 2) {
						if ($day == intval($date[0]) && $month == intval($date[1])) {
							$event_show = true;
							$event_text[] = $text;
						}
					} elseif ($day == intval($date[0])) {
						$event_show = true;
						$event_text[] = $text;
					}				
				}
			}
			
			if ($event_show) {
				$out.= '<td class="calendar-day ' . $class . ' event">' . $day;
				if (!empty($event_text)) {
					$out.= '<div class="calendar-popup">' . implode('<br>', $event_text) . '</div>';
				}
				$out.= '</td>';
			} else {
				$out.= '<td class="calendar-day ' . $class . '">' . $day . '</td>';
			}
 
			if ($day_week == 6) {
				$out.= '</tr>';
				if (($days_counter + 1) != $days_month) {
					$out.= '<tr>';
				}
				$day_week = -1;
			}
 
			$day_week++; 
			$days_counter++;
		}
 
		$out .= '</tr></table></div>';
		return $out;
	}
	
	/**
	 * Вывод календаря на несколько месяцев.
	 */
	public static function  getInterval($start, $end, $events = array())
	{
		$curent = explode('.', $start);
		$curent[0] = intval($curent[0]);
		
		$end = explode('.', $end);
		$end[0] = intval($end[0]);
 
		$begin = true;
		$out = '<div class="calendar-wrp">';
		do {
			$out .= self::getMonth($curent[0], $curent[1], $events);
 
			if ($curent[0] == $end[0] && $curent[1] == $end[1]) {
				$begin = false;
			}		
 
			$curent[0]++;
			if ($curent[0] == 13) {
				$curent[0] = 1;
				$curent[1]++;
			}
		} while ($begin == true);	
		
		$out .= '</div>';
		return $out;
	}
}
PHP

CSS-стили:

.calendar-item {
	width: 200px;
	display: inline-block;
	vertical-align: top;
	margin: 0 16px 20px;
	font: 14px/1.2 Arial, sans-serif;
}
.calendar-head {
	text-align: center;
	padding: 5px;
	font-weight: 700;
	font-size: 14px;
}
.calendar-item table {
	border-collapse: collapse;
	width: 100%;
}
.calendar-item th {
	font-size: 12px;
	padding: 6px 7px;
	text-align: center;
	color: #888;
	font-weight: normal;
}
.calendar-item td {
	font-size: 13px;
	padding: 6px 5px;
	text-align: center;
	border: 1px solid #ddd;
}
.calendar-item tr th:nth-child(6), .calendar-item tr th:nth-child(7),
.calendar-item tr td:nth-child(6), .calendar-item tr td:nth-child(7)  {
	color: #e65a5a;
}	
.calendar-day.last {
	color: #999 !important;
}	
.calendar-day.today {
	font-weight: bold;
}
.calendar-day.event {
	background: #ffe2ad;
	position: relative;
	cursor: pointer;
}
.calendar-day.event:hover .calendar-popup {
	display: block;
}
.calendar-popup {
	display: none;
	position: absolute;
	top: 40px;
	left: 0;
	min-width: 200px;
	padding: 15px;
	background: #fff;
	text-align: left;
	font-size: 13px;
	z-index: 100;
	box-shadow: 0 0 10px rgba(0,0,0,0.5);
	color: #000;
}
.calendar-popup:before {
	content: ""; 
	border: solid transparent;
	position: absolute;    
	left: 8px;    
	bottom: 100%;
	border-bottom-color: #fff;
	border-width: 9px;
	margin-left: 0;
}
CSS

Далее приведены варианты использования класса и живые примеры.

1

Вывод календаря на текущий месяц:

echo Calendar::getMonth(date('n'), date('Y'));
PHP

Результат:

2
echo Calendar::getInterval(date('n.Y'), date('n.Y', strtotime('+2 month')));
PHP

Результат:

3

Вывод календаря на текущий год с выделенными днями праздников и других событий.
В массиве $events даты могут быть в следующем формате:

  • d – день месяца, при таком формате, заданный день будет выделятся каждый месяц.
  • d.m – день и месяц, такая дата будет выделятся раз в год.
  • d.m.Y или d.m.Y H:i – точная дата.
$events = array(
	'16'    => 'Заплатить ипотеку',
	'23.02' => 'День защитника Отечества',
	'08.03' => 'Международный женский день',
	'31.12' => 'Новый год'
);

echo Calendar::getInterval(date('01.Y'), date('12.Y'), $events);
PHP

Результат:

$events = array(
	'16'    => 'Заплатить ипотеку',
	'23.02' => 'День защитника Отечества',
	'08.03' => 'Международный женский день',
	'31.12' => 'Новый год'
);

echo Calendar::getInterval(date('n.Y'), date('n.Y', strtotime('+11 month')), $events);
PHP

Результат:

21.01.2021, обновлено 07.04.2022
34009

Комментарии 10

Вячеслав Иванов Вячеслав Иванов
1 сентября 2021 в 22:11
Календарь хороший, но есть "косячек":
		$out .= '<div class="">';
		return $out;
плодит не закрытые div
наверное надо так
		$out .= '</div>';
		return $out;
Афанасий Павлов Афанасий Павлов
30 ноября 2021 в 15:04
А как показывать определенный месяц? ну или если быть точнее то хочу вытаскивать по 4 месяц, с определенного месяца(например март)
Snipp.ru Snipp.ru
30 ноября 2021 в 15:22
Можно сделать так, выведутся месяцы с марта по июнь текущего года.
echo Calendar::getInterval(date('3.Y'), date('n.Y', strtotime(date('01.03.Y') . ' +3 month')));
Вадим М Вадим М
12 апреля 2022 в 16:25
Если поставить две одинаковые даты, то всплывать будет только последнее событие, ибо дата это кей. небольшая модернизация помогла
if (!empty($events)) {
            foreach ($events as $event) {
				foreach ($event as $date => $text) {

и теперь события появляются все
$events = array(
    array ('30.04.2022' => 'Новый год1'),
    array ('30.04' => 'Новый год2'),
    array ('30.04.2022' => 'Новый год3')
);
Александра Дыдыкина Александра Дыдыкина
25 мая 2022 в 19:57
Странно, у меня ошибка: Invalid argument supplied for foreach()
А что-то еще меняли?
Александра Дыдыкина Александра Дыдыкина
25 мая 2022 в 19:04
Если брать значения из БД с помощью sql запроса, то у меня отображаются только последние события, так как в цикле одна и та же переменная просто перезаписывается. Никто не поможет переделать код так, чтобы отображались все события? Хотела использовать .=, но он ругается. Пробовала использовать цикл for с i++, а затем прибавлять i к переменной events, но опять не получается. Буду очень благодарна, если кто подскажет решение.
$Deadlines = "SELECT Forms.*, Deadlines.*, DATE_FORMAT(start_date, '%d.%m.%Y') as st_date, DATE_FORMAT(end_date, '%d.%m.%Y') as e_date FROM Forms, Deadlines";
$dead = mysqli_query($connection, $Deadlines);
while($deadd = mysqli_fetch_assoc($dead)){

$events = array(
	$deadd['st_date']   => 'Начало срока сдачи отчета по форме '.$deadd['form_index'],
	$deadd['e_date'] => 'Конец срока сдачи отчета по форме '.$deadd["form_index"],
	

	);
}
echo Calendar::getInterval(date('n.Y'), date('n.Y', strtotime('+2 month')), $events);
Александра Дыдыкина Александра Дыдыкина
25 мая 2022 в 19:52
Ой, кажется, получилось))
$events = array();
$Deadlines = "SELECT Forms.*, Deadlines.*, DATE_FORMAT(start_date, '%d.%m.%Y') as st_date, DATE_FORMAT(end_date, '%d.%m.%Y') as e_date FROM Forms, Deadlines WHERE Forms.form_id=Deadlines.form_id";
$dead = mysqli_query($connection, $Deadlines);
while($deadd = mysqli_fetch_assoc($dead)){

$events[$deadd['st_date']] = 'Начало срока сдачи отчета по форме '.$deadd['form_index'];
$events[$deadd['e_date']] = 'Конец срока сдачи отчета по форме '.$deadd['form_index'];
}
STENLI PRODUCTIONS STENLI PRODUCTIONS
25 октября 2022 в 13:25
Здрасти
1. Как добавить ссылку при нажатии на день с событием что бы по ней куда то переходило ?
2. И на само событие если их в этот день несколько (но ссылка на день оставалась бы)
и желательно данные передавать единым массивом
Руслан Строй Руслан Строй
12 мая 2023 в 10:05
добрый день, такой вопрос
мне нужно что бы кроме текста туда еще картинку выводить и ссылку обычную
как это можно сделать?
к примеру
'16' => 'Заплатить ипотеку' 'https://snipp.ru/uploads/users/32x32/0848c43e8b64078fe97cd3f560add056e9d7a5e9.jpg',
Михаил А Михаил А
14 июля 2023 в 09:27
Добрый день. Как сделать, чтобы выводилась просто дата ссылка на страницу без праздника?

, чтобы добавить комментарий.

Другие публикации

Проверка данных регулярными выражениями
Сборник регулярных выражений с примерами на PHP для проверки данных из полей форм.
20084
+8
Вывод даты с русскими месяцами
PHP-функция для вывода даты в привычном формате из метки unix timestamp.
6858
+5
Блоки со стрелками (часть 1)
Добавить стрелки к блоку можно с помощью псевдо-элемента :before.
28407
+2
Блоки со стрелками (часть 2)
В продолжении первой части, примеры как добавить стрелки к блоку с рамкой. Используются оба псевдо-элемента :before и :after.
7191
0
Заполненные PHP-массивы для дат
Заполненные PHP-массивы с элементами дат для проверки данных, операций с датами, вывода списков в формах и т.д.
7490
+2
Работа с массивами PHP – создание, наполнение, удаление
Основные примеры работы с массивами PHP. Создание, наполнение, извлечение удаление значений.
105219
+14