Чтобы преобразовать дату и время в формат 2025-02-05T15:03 +3 часа в PHP, вы можете использовать класс DateTime и его методы. Вот пример кода:
<?php
// Исходная дата и время
$dateString = '2025-02-05T15:03';
// Создаем объект DateTime
$date = new DateTime($dateString);
// Добавляем 3 часа
$date->modify('+3 hours');
// Форматируем дату и время в нужный формат
$formattedDate = $date->format('Y-m-d\TH:i') . ' +3 часа';
// Выводим результат
echo $formattedDate;
?>Создание объекта DateTime: Мы создаем объект DateTime из строки 2025-02-05T15:03.
Добавление 3 часов: Используем метод modify('+3 hours'), чтобы добавить 3 часа к текущему времени.
Форматирование: Метод format('Y-m-d\TH:i') форматирует дату и время в нужный формат. Мы добавляем +3 часа вручную, так как это текстовая часть.
Вывод: Выводим результат.
2025-02-05T18:03 +3 часа
Этот код преобразует исходную дату и время, добавляет 3 часа и выводит результат в требуемом формате.
Чтобы добавить 3 часа к дате и времени в формате 2025-02-05T22:48, который вы получаете из event.end.toISOString().slice(0, 16) в JavaScript, можно использовать объект Date и его методы. Вот как это можно сделать:
// Предположим, что event.end.toISOString() возвращает что-то вроде "2025-02-05T22:48:00.000Z" const eventEnd = new Date('2025-02-05T22:48:00.000Z'); // Добавляем 3 часа eventEnd.setHours(eventEnd.getHours() + 3); // Форматируем дату и время в нужный формат (без секунд и миллисекунд) const formattedDate = eventEnd.toISOString().slice(0, 16); // Выводим результат console.log(formattedDate); // "2025-02-06T01:48"
Создание объекта Date: Мы создаем объект Date из строки, которую возвращает event.end.toISOString().
Добавление 3 часов: Используем метод setHours(), чтобы добавить 3 часа к текущему времени.
Форматирование: Метод toISOString() возвращает дату в формате ISO (YYYY-MM-DDTHH:mm:ss.sssZ). Мы используем slice(0, 16), чтобы обрезать строку до формата YYYY-MM-DDTHH:mm.
Результат: Выводим отформатированную дату и время.
Если исходная дата была 2025-02-05T22:48, то после добавления 3 часов результат будет:
2025-02-06T01:48
Если вам нужно добавить текст +3 часа к выводу, вы можете сделать это вручную:
console.log(`${formattedDate} +3 часа`);
Результат:
2025-02-06T01:48 +3 часа
Убедитесь, что исходная дата (event.end) корректно передается и обрабатывается. Если она уже в формате Date, то создание нового объекта Date не требуется.
Чтобы собрать все даты в массив для каждого дня или каждой недели в заданном диапазоне, можно использовать цикл while или for с добавлением интервала к начальной дате. Вот пример кода, который собирает все даты в массив в зависимости от выбранного интервала (daily, weekly, и т.д.):
<?php
$startDate = new DateTime('2025-02-08T04:12');
$endDate = new DateTime('2025-03-08T04:12');
$repeat = 'daily'; // или 'weekly', 'monthly', 'yearly'
$interval = null;
switch ($repeat) {
case 'daily':
$interval = new DateInterval('P1D'); // Каждый день
break;
case 'weekly':
$interval = new DateInterval('P1W'); // Каждую неделю
break;
case 'monthly':
$interval = new DateInterval('P1M'); // Каждый месяц
break;
case 'yearly':
$interval = new DateInterval('P1Y'); // Каждый год
break;
default:
throw new Exception("Invalid repeat value");
}
$maxDate = (new DateTime())->modify('+1 year'); // Максимальная дата (1 год от текущей)
$dates = []; // Массив для хранения дат
// Проверяем, чтобы конечная дата не превышала максимальную
if ($endDate > $maxDate) {
$endDate = $maxDate;
}
// Собираем даты в массив
$currentDate = clone $startDate;
while ($currentDate <= $endDate) {
$dates[] = $currentDate->format('Y-m-d\TH:i'); // Форматируем дату и добавляем в массив
$currentDate->add($interval); // Добавляем интервал
}
// Выводим результат
print_r($dates);
?>Начальная и конечная дата:
$startDate — начальная дата.
$endDate — конечная дата.
Если $endDate превышает $maxDate (1 год от текущей даты), она ограничивается значением $maxDate.
Интервал:
В зависимости от значения $repeat (daily, weekly, и т.д.), выбирается соответствующий интервал (P1D, P1W, и т.д.).
Сбор дат:
Используется цикл while, который продолжается, пока текущая дата ($currentDate) не превысит конечную дату ($endDate).
На каждой итерации дата добавляется в массив $dates в формате Y-m-d\TH:i.
Результат:
Массив $dates содержит все даты в заданном диапазоне с учетом интервала.
daily:Array ( [0] => 2025-02-08T04:12 [1] => 2025-02-09T04:12 [2] => 2025-02-10T04:12 [3] => 2025-02-11T04:12 ... [28] => 2025-03-08T04:12 )
weekly:Array ( [0] => 2025-02-08T04:12 [1] => 2025-02-15T04:12 [2] => 2025-02-22T04:12 [3] => 2025-03-01T04:12 [4] => 2025-03-08T04:12 )
Если нужно добавить поддержку других интервалов (например, каждые 2 дня), можно изменить DateInterval на P2D.
Если нужно учитывать часовой пояс, используйте DateTimeZone при создании объектов DateTime.
Вот пример реализации вашего запроса:
Создадим форму с двумя полями input type="datetime-local" и одним input type="checkbox".
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Форма с datetime-local и checkbox</title> <!-- Подключаем Bootstrap CSS --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <div class="container mt-5"> <form id="myForm"> <div class="mb-3"> <label for="startDate" class="form-label">Начальная дата и время</label> <input type="datetime-local" class="form-control" id="startDate"> </div> <div class="mb-3"> <label for="endDate" class="form-label">Конечная дата и время</label> <input type="datetime-local" class="form-control" id="endDate"> </div> <div class="mb-3 form-check"> <input type="checkbox" class="form-check-input" id="disableDates"> <label class="form-check-label" for="disableDates">Отключить выбор дат</label> </div> <button type="submit" class="btn btn-primary">Отправить</button> </form> </div> <!-- Подключаем jQuery --> <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script> <!-- Подключаем Bootstrap JS (необязательно для этой задачи) --> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script> </body> </html>
Добавим код jQuery, который будет скрывать или отключать поля input type="datetime-local" при выборе checkbox.
<script> $(document).ready(function() { // Обработчик изменения состояния checkbox $('#disableDates').change(function() { if ($(this).is(':checked')) { // Если checkbox выбран, скрываем и отключаем поля $('#startDate, #endDate').prop('disabled', true).hide(); } else { // Если checkbox не выбран, показываем и включаем поля $('#startDate, #endDate').prop('disabled', false).show(); } }); }); </script>
Форма:
Два поля input type="datetime-local" для выбора начальной и конечной даты.
Один input type="checkbox" для управления видимостью и активностью полей.
jQuery:
При изменении состояния checkbox (change событие):
Если checkbox выбран (checked), поля datetime-local отключаются (disabled) и скрываются (hide).
Если checkbox не выбран, поля включаются (disabled: false) и показываются (show).
Когда пользователь отмечает checkbox, поля datetime-local исчезают и становятся недоступными.
Когда checkbox снимается, поля снова появляются и становятся активными.
Если нужно не скрывать поля, а только отключать, замените .hide() и .show() на .css('visibility', 'hidden') и .css('visibility', 'visible') соответственно.
Если нужно сохранить видимость полей, но сделать их недоступными, используйте только .prop('disabled', true/false).
Для реализации добавления категорий, сортировки и фильтров в FullCalendar через popup, можно использовать модальное окно (например, из Bootstrap) и динамически управлять событиями календаря. Вот пошаговое руководство:
Убедитесь, что у вас подключены:
FullCalendar (основная библиотека и плагины).
Bootstrap (для модального окна и стилей).
jQuery (для работы с событиями и DOM).
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>FullCalendar с фильтрами и категориями</title> <!-- FullCalendar CSS --> <link href="https://cdn.jsdelivr.net/npm/fullcalendar@5.11.3/main.min.css" rel="stylesheet"> <!-- Bootstrap CSS --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <div class="container mt-5"> <div id="calendar"></div> </div> <!-- Модальное окно для фильтров и категорий --> <div class="modal fade" id="filterModal" tabindex="-1" aria-labelledby="filterModalLabel" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="filterModalLabel">Фильтры и категории</h5> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body"> <form id="filterForm"> <div class="mb-3"> <label for="categorySelect" class="form-label">Категория</label> <select class="form-select" id="categorySelect"> <option value="all">Все</option> <option value="work">Работа</option> <option value="personal">Личное</option> <option value="meeting">Встречи</option> </select> </div> <div class="mb-3"> <label for="sortSelect" class="form-label">Сортировка</label> <select class="form-select" id="sortSelect"> <option value="start">По дате начала</option> <option value="title">По названию</option> </select> </div> </form> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Закрыть</button> <button type="button" class="btn btn-primary" id="applyFilters">Применить</button> </div> </div> </div> </div> <!-- Подключаем jQuery --> <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script> <!-- Подключаем Bootstrap JS --> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script> <!-- FullCalendar JS --> <script src="https://cdn.jsdelivr.net/npm/fullcalendar@5.11.3/main.min.js"></script> </body> </html>
Инициализируем календарь и добавим кнопку для открытия модального окна с фильтрами.
<script> $(document).ready(function() { // Инициализация FullCalendar const calendarEl = document.getElementById('calendar'); const calendar = new FullCalendar.Calendar(calendarEl, { initialView: 'dayGridMonth', events: [ { id: '1', title: 'Событие 1', start: '2025-02-08', category: 'work' }, { id: '2', title: 'Событие 2', start: '2025-02-10', category: 'personal' }, { id: '3', title: 'Событие 3', start: '2025-02-15', category: 'meeting' }, ], headerToolbar: { left: 'prev,next today', center: 'title', right: 'dayGridMonth,timeGridWeek,timeGridDay customFilterButton' }, customButtons: { customFilterButton: { text: 'Фильтры', click: function() { $('#filterModal').modal('show'); // Открываем модальное окно } } } }); calendar.render(); // Применение фильтров $('#applyFilters').on('click', function() { const selectedCategory = $('#categorySelect').val(); // Выбранная категория const selectedSort = $('#sortSelect').val(); // Выбранная сортировка // Фильтрация событий let filteredEvents = calendar.getEvents().filter(event => { return selectedCategory === 'all' || event.extendedProps.category === selectedCategory; }); // Сортировка событий if (selectedSort === 'start') { filteredEvents.sort((a, b) => a.start - b.start); } else if (selectedSort === 'title') { filteredEvents.sort((a, b) => a.title.localeCompare(b.title)); } // Очистка календаря и добавление отфильтрованных событий calendar.removeAllEvents(); filteredEvents.forEach(event => calendar.addEvent(event)); $('#filterModal').modal('hide'); // Закрываем модальное окно }); }); </script>
Модальное окно:
Содержит два выпадающих списка: для выбора категории и сортировки.
Кнопка "Применить" применяет выбранные фильтры.
FullCalendar:
Инициализируется с набором событий, каждое из которых имеет категорию (category).
В панели инструментов добавлена кнопка "Фильтры", которая открывает модальное окно.
Фильтрация и сортировка:
При нажатии на "Применить" события фильтруются по выбранной категории.
События сортируются по дате начала или названию.
Отфильтрованные события добавляются обратно в календарь.
Откройте календарь и нажмите кнопку "Фильтры".
Выберите категорию (например, "Личное") и сортировку (например, "По названию").
Нажмите "Применить", и календарь обновится, показывая только отфильтрованные события.
Добавьте больше категорий и фильтров (например, по цвету событий).
Сохраняйте выбранные фильтры в localStorage, чтобы они сохранялись после перезагрузки страницы.
Используйте AJAX для загрузки событий с сервера с учетом фильтров.
Чтобы удалить все символы после 9-го символа в строке даты 2025-02-03T00:00, можно использовать функцию substr в PHP. Вот пример кода:
<?php
$dateString = '2025-02-03T00:00';
// Удаляем все символы после 9-го символа
$trimmedDate = substr($dateString, 0, 10);
echo $trimmedDate; // Вывод: 2025-02-03
?>substr:
Функция substr возвращает часть строки.
Первый аргумент — исходная строка.
Второй аргумент — начальная позиция (в данном случае 0, чтобы начать с начала строки).
Третий аргумент — длина подстроки (в данном случае 10, чтобы оставить первые 10 символов).
Результат:
Строка 2025-02-03T00:00 обрезается до 2025-02-03.
Если вы хотите удалить всё после символа T, можно использовать функцию explode:
<?php
$dateString = '2025-02-03T00:00';
// Разделяем строку по символу 'T' и берем первую часть
$trimmedDate = explode('T', $dateString)[0];
echo $trimmedDate; // Вывод: 2025-02-03
?>Используйте substr, если вам нужно обрезать строку до определённого количества символов.
Используйте explode, если вам нужно разделить строку по определённому символу (например, T в дате).
Оба метода работают для удаления части строки после 9-го символа. Выбор зависит от ваших предпочтений и конкретной задачи.
Если кнопка "Фильтры" в FullCalendar не работает для выбора "Все" (т.е. не отображаются все события), вероятно, проблема связана с логикой фильтрации. Давайте разберём, как исправить эту проблему.
Когда вы выбираете "Все" в фильтре, события не отображаются, потому что:
Логика фильтрации не учитывает значение "Все".
События не добавляются обратно в календарь после фильтрации.
Вот исправленный код для фильтрации событий, включая выбор "Все":
<script> $(document).ready(function() { // Инициализация FullCalendar const calendarEl = document.getElementById('calendar'); const calendar = new FullCalendar.Calendar(calendarEl, { initialView: 'dayGridMonth', events: [ { id: '1', title: 'Событие 1', start: '2025-02-08', category: 'work' }, { id: '2', title: 'Событие 2', start: '2025-02-10', category: 'personal' }, { id: '3', title: 'Событие 3', start: '2025-02-15', category: 'meeting' }, ], headerToolbar: { left: 'prev,next today', center: 'title', right: 'dayGridMonth,timeGridWeek,timeGridDay customFilterButton' }, customButtons: { customFilterButton: { text: 'Фильтры', click: function() { $('#filterModal').modal('show'); // Открываем модальное окно } } } }); calendar.render(); // Применение фильтров $('#applyFilters').on('click', function() { const selectedCategory = $('#categorySelect').val(); // Выбранная категория const selectedSort = $('#sortSelect').val(); // Выбранная сортировка // Получаем все события let allEvents = calendar.getEvents(); // Фильтрация событий let filteredEvents = allEvents.filter(event => { if (selectedCategory === 'all') { return true; // Показываем все события } else { return event.extendedProps.category === selectedCategory; } }); // Сортировка событий if (selectedSort === 'start') { filteredEvents.sort((a, b) => a.start - b.start); } else if (selectedSort === 'title') { filteredEvents.sort((a, b) => a.title.localeCompare(b.title)); } // Очистка календаря и добавление отфильтрованных событий calendar.removeAllEvents(); filteredEvents.forEach(event => calendar.addEvent(event)); $('#filterModal').modal('hide'); // Закрываем модальное окно }); }); </script>
Фильтрация для "Все":
В условии фильтрации добавлена проверка:
if (selectedCategory === 'all') { return true; // Показываем все события }
Если выбрана категория "Все", фильтр возвращает true для всех событий.
Сохранение всех событий:
Все события сохраняются в переменной allEvents перед фильтрацией:
let allEvents = calendar.getEvents();
Добавление отфильтрованных событий:
После фильтрации и сортировки события добавляются обратно в календарь:
calendar.removeAllEvents(); filteredEvents.forEach(event => calendar.addEvent(event));
Откройте календарь и нажмите кнопку "Фильтры".
Выберите "Все" в выпадающем списке категорий.
Нажмите "Применить".
Все события должны отображаться в календаре.
Сброс фильтров:
Добавьте кнопку "Сбросить фильтры", чтобы вернуть все события без фильтрации:
$('#resetFilters').on('click', function() { calendar.removeAllEvents(); calendar.addEvent(allEvents); // Добавляем все события $('#filterModal').modal('hide'); });
Подсветка отфильтрованных событий:
Используйте CSS для изменения стиля отфильтрованных событий.
Теперь фильтр "Все" работает корректно, и все события отображаются при выборе этой опции. Если у вас остались вопросы, дайте знать! 😊
Ошибка ReferenceError: allEvents is not defined возникает, потому что переменная allEvents не определена в области видимости, где вы пытаетесь её использовать. Чтобы исправить это, нужно убедиться, что переменная allEvents доступна в функции сброса фильтров.
Объявление переменной allEvents на уровне документа:
Переменная allEvents должна быть объявлена вне функций, чтобы она была доступна как для фильтрации, так и для сброса.
Инициализация allEvents при загрузке страницы:
Сохраняем все события в allEvents при инициализации календаря.
Функция сброса фильтров:
Используем allEvents для восстановления всех событий.
Вот исправленный код:
<script> $(document).ready(function() { // Переменная для хранения всех событий let allEvents; // Инициализация FullCalendar const calendarEl = document.getElementById('calendar'); const calendar = new FullCalendar.Calendar(calendarEl, { initialView: 'dayGridMonth', events: [ { id: '1', title: 'Событие 1', start: '2025-02-08', category: 'work' }, { id: '2', title: 'Событие 2', start: '2025-02-10', category: 'personal' }, { id: '3', title: 'Событие 3', start: '2025-02-15', category: 'meeting' }, ], headerToolbar: { left: 'prev,next today', center: 'title', right: 'dayGridMonth,timeGridWeek,timeGridDay customFilterButton' }, customButtons: { customFilterButton: { text: 'Фильтры', click: function() { $('#filterModal').modal('show'); // Открываем модальное окно } } } }); calendar.render(); // Сохраняем все события при загрузке страницы allEvents = calendar.getEvents(); // Применение фильтров $('#applyFilters').on('click', function() { const selectedCategory = $('#categorySelect').val(); // Выбранная категория const selectedSort = $('#sortSelect').val(); // Выбранная сортировка // Фильтрация событий let filteredEvents = allEvents.filter(event => { if (selectedCategory === 'all') { return true; // Показываем все события } else { return event.extendedProps.category === selectedCategory; } }); // Сортировка событий if (selectedSort === 'start') { filteredEvents.sort((a, b) => a.start - b.start); } else if (selectedSort === 'title') { filteredEvents.sort((a, b) => a.title.localeCompare(b.title)); } // Очистка календаря и добавление отфильтрованных событий calendar.removeAllEvents(); filteredEvents.forEach(event => calendar.addEvent(event)); $('#filterModal').modal('hide'); // Закрываем модальное окно }); // Сброс фильтров $('#resetFilters').on('click', function() { // Восстанавливаем все события calendar.removeAllEvents(); allEvents.forEach(event => calendar.addEvent(event)); $('#filterModal').modal('hide'); // Закрываем модальное окно }); }); </script>
Переменная allEvents:
Объявлена на уровне документа, чтобы быть доступной для всех функций.
Инициализируется при загрузке страницы:
allEvents = calendar.getEvents();
Функция сброса фильтров:
Использует allEvents для восстановления всех событий:
calendar.removeAllEvents(); allEvents.forEach(event => calendar.addEvent(event));
При загрузке страницы все события сохраняются в переменной allEvents.
При нажатии на "Сброс фильтров" все события из allEvents добавляются обратно в календарь.
Ошибка ReferenceError: allEvents is not defined больше не возникает, так как переменная определена в правильной области видимости.
Если события динамически добавляются или удаляются, обновляйте переменную allEvents после каждого изменения:
allEvents = calendar.getEvents();
Если вы используете AJAX для загрузки событий, сохраняйте их в allEvents после успешной загрузки:
calendar.refetchEvents(); allEvents = calendar.getEvents();
Теперь ваш код должен работать корректно! Если остались вопросы, дайте знать. 😊