Экстраполя Cotonti: тип данных datetime — Дата и время
Как работают экстраполя типа datetime в Cotonti: хранение в Unix timestamp, параметры min/max/format, импорт, вывод с учётом часовых поясов и использование в шаблонах. Подробный разбор с примерами кода.
Экстраполя Cotonti: тип данных datetime — Дата и время
Общие сведения
Тип datetime в системе дополнительных полей (extrafields) Cotonti предназначен для хранения даты и времени в виде целого числа — Unix timestamp. Это значение представляет собой количество секунд, прошедших с полуночи 1 января 1970 года по UTC. Такой подход обеспечивает компактное хранение, простоту сравнения и корректное преобразование между часовыми поясами.
Вся логика обработки полей типа datetime сосредоточена в трёх основных файлах:
system/extrafields.php — функции для построения формы, импорта и вывода данных.
system/functions.php — вспомогательные функции для работы с датами и временем (cot_import_date, cot_date, cot_mktime, cot_date2stamp, cot_stamp2date).
Ниже мы детально рассмотрим каждый аспект работы с этим типом.
Хранение значения в базе данных
При создании экстраполя типа datetime через функцию cot_extrafield_add() в таблицу базы данных добавляется колонка со следующим SQL-типом:
int DEFAULT '0'
Это означает:
Значение хранится как целое число (Unix timestamp).
Пустое значение (дата не выбрана) соответствует числу 0.
Максимальное значение определяется типом int (обычно 2^31-1), что позволяет хранить даты до 2038 года на 32-битных системах, но в большинстве современных окружений используется 64-битный PHP, где диапазон шире.
Фактически, в базе данных всегда находится либо 0, либо положительное число — количество секунд с начала эпохи.
Параметры поля (field_params)
Поле field_params в таблице cot_extra_fields для типа datetime хранит строку, состоящую из трёх компонентов, разделённых запятыми:
min,max,format
min — минимальный год (целое число). Используется для ограничения диапазона лет в форме редактирования и при импорте.
max — максимальный год (целое число).
format — строка формата даты/времени для вывода значения. Может быть как стандартным PHP-форматом (например, 'Y-m-d H:i'), так и ключом локализованного формата Cotonti (например, 'datetime_medium').
Поведение по умолчанию
Если параметры не заданы или заданы частично, действуют следующие правила:
Если min пуст или ≤ 0, используется 2000.
Если max пуст или ≤ 0, используется 2030.
Если format пуст, при выводе возвращается исходный Unix timestamp без форматирования.
Разбор параметров в коде
В функции cot_build_extrafields() (для построения формы) параметры разбираются так:
Подробно рассмотрим её поведение на основе кода system/forms.php.
Параметры
$utime — Unix timestamp выбранной даты.
$mode — режим отображения. Для экстраполей всегда передаётся 'long' (полный набор: год, месяц, день, час, минута).
$name — базовое имя поля (например, rxtra_x200_last_promotion).
$max_year, $min_year — границы лет.
$usertimezone — флаг учёта часового пояса пользователя. Для экстраполей передаётся true.
$custom_rc — пользовательский ресурсный шаблон.
Шаги выполнения
Проверка наличия кастомной функции: если определена cot_selectbox_date_custom(), она будет вызвана и результат возвращён без дальнейших действий.
Хук form.date: разработчики могут переопределить вывод через плагины, подключённые к этому хуку.
Определение имени ресурса: если имя поля содержит квадратные скобки (например, rxtra_date[user_id]), извлекается базовое имя до скобок для поиска ресурсных строк.
Если $utime больше нуля и учёт часового пояса включён, к нему добавляется смещение текущего пользователя (в часах, умноженное на 3600). Это обеспечивает отображение времени в локальной зоне пользователя.
Определение компонентов даты:
Если $utime == 0 (пустая дата), то компоненты ($s_year, $s_month, $s_day, $s_hour, $s_minute) устанавливаются в null. Затем проверяется буферизованное значение через cot_import_buffered(). Это позволяет восстановить выбранные значения после неудачной отправки формы (например, при ошибке валидации). Если буфер содержит массив, его значения используются для заполнения полей.
Если $utime > 0, то компоненты извлекаются через date('Y-m-d-H-i', $utime) и разбиваются по -.
Формирование массива месяцев: используется языковой массив $L для локализованных названий месяцев (от $L['January'] до $L['December']).
Создание выпадающих списков:
Год: cot_selectbox($s_year, $name.'[year]', range($max_year, $min_year, -1)). Диапазон лет от максимума к минимуму.
Таким образом, если выбранный год выходит за допустимые границы, он принудительно заменяется на min или max с сохранением остальных компонентов.
Проверка обязательности: если поле обязательное (field_required = 1) и $import равно null, '' или 0, генерируется ошибка через cot_error().
Функция cot_import_date()
Эта функция находится в system/functions.php и играет ключевую роль.
Логика работы
Проверка кастомной функции: если существует cot_import_date_custom(), она вызывается.
Хук import.date: позволяет плагинам переопределить импорт.
Получение данных:
Сначала пытается получить массив из источника через cot_import($name, $source, 'ARR'). Ожидается массив с ключами year, month, day, hour, minute.
Если массив пуст, предпринимается попытка прочитать значение как обычную строку (cot_import(..., 'TXT')). Это может быть дата в текстовом формате (например, 2025-12-31 23:59).
Обработка строкового значения:
Если строка не пуста, вызывается cot_date2stamp($date), которая преобразует её в timestamp. Если преобразование не удалось, возвращается null.
Обработка массива:
Компоненты массива проверяются на наличие, при отсутствии устанавливаются в 0.
Если все компоненты равны null (поле формы отправлено, но ни один элемент не выбран), возвращается null.
В противном случае проверяется строка string и формат format, которые могут быть переданы в массиве. Если строка непуста, используется cot_date2stamp($string, $format). Иначе возвращается null.
Корректировка часового пояса:
if ($usertimezone) {
$timestamp -= Cot::$usr['timezone'] * 3600;
}
Из полученного timestamp вычитается часовой пояс текущего пользователя, чтобы привести время к UTC перед сохранением в базу.
Возврат результата:
Если $returnarray = true, возвращается массив с ключами stamp, year, month, day, hour, minute.
Иначе возвращается целочисленный timestamp.
Таким образом, итоговое значение, сохраняемое в базе данных, всегда является UTC timestamp.
Вывод значения в шаблонах
Для получения готового значения экстраполя используется функция cot_build_extrafields_data() (в system/extrafields.php).
Из параметров извлекается только третий компонент — format.
Если formatпуст, возвращается исходное значение $value (timestamp).
Если format задан, вызывается функция cot_date($format, $value).
Функция cot_date()
Расположена в system/functions.php. Используется для локализованного форматирования даты.
function cot_date($format, $timestamp = null, $usertimezone = true)
{
global $lang, $Ldt;
if (is_null($timestamp)) {
$timestamp = Cot::$sys['now'];
}
$timestamp = (int) $timestamp;
if ($usertimezone) {
$timestamp += Cot::$usr['timezone'] * 3600;
}
$datetime = (isset($Ldt[$format])) ? @date($Ldt[$format], $timestamp) : @date($format, $timestamp);
// ... замена английских названий месяцев/дней на локализованные
return ($lang == 'en') ? $datetime : str_replace($search, $replace, $datetime);
}
Если $timestamp не передан, берётся текущее время Cot::$sys['now'].
При $usertimezone = true к timestamp добавляется часовой пояс пользователя (Cot::$usr['timezone'] * 3600), то есть время из UTC переводится в локальное для отображения.
Если формат присутствует в массиве $Ldt (локализованные форматы), используется он, иначе — переданный PHP-формат.
После форматирования выполняется замена английских названий дней недели и месяцев на локализованные версии из $L (если язык не английский).
Взаимодействие с часовыми поясами
Ключевая особенность типа datetime — корректная работа с часовыми поясами пользователей. Схема следующая:
При вводе (импорте):
Пользователь выбирает дату и время в своей локальной зоне.
Функция cot_import_date() вычитает его часовой пояс (Cot::$usr['timezone'] * 3600), приводя время к UTC.
В базу сохраняется UTC timestamp.
При выводе:
Из базы извлекается UTC timestamp.
Функция cot_date() добавляет часовой пояс текущего пользователя, переводя время обратно в локальное.
Затем происходит форматирование и локализация.
Таким образом, каждый пользователь видит дату и время в своей собственной зоне, независимо от того, где была сохранена запись.
Часовой пояс пользователя хранится в Cot::$usr['timezone'] как смещение в часах от UTC (например, 3 для Москвы).
Использование в плагинах и модулях
Регистрация поля
Для создания экстраполя типа datetime в плагине используется функция cot_extrafield_add(). Пример:
cot_extrafield_add(
'users', // таблица, к которой добавляется поле
'my_event_datetime', // имя поля (без префикса таблицы)
'datetime', // тип
'', // html-конструкция (пусто — стандартная)
'', // варианты (не используются для datetime)
'', // значение по умолчанию (timestamp или 0)
false, // обязательность
'HTML', // парсер (не влияет на datetime)
'Дата события', // описание
'2000,2030,datetime_medium' // параметры: min,max,format
);
После вызова в таблице cot_users появится колонка user_my_event_datetime с типом int DEFAULT '0'.
Сохранение значения
В плагине при обработке POST-запроса:
$exfld = [/* массив описания поля, полученный через cot_load_extrafields() */];
$oldValue = $existingData['user_my_event_datetime'] ?? 0;
$newValue = cot_import_extrafields('rxtra_my_event_datetime', $exfld, 'P', $oldValue, 'xtra_');
// $newValue — UTC timestamp или 0
Если поле обязательное, функция автоматически сгенерирует ошибку при пустом значении.
После успешного импорта всех полей обычно вызывается cot_extrafield_movefiles() (для файловых полей, но не влияет на datetime).
Получение значения
Для получения значения из базы данных достаточно обычного SQL-запроса или использования API плагина. Значение будет целым числом (timestamp).
Использование в шаблонах
Автоматическая генерация тегов
Для пользователей Cotonti предоставляет функцию cot_generate_usertags(), которая создаёт теги для всех экстраполей, включая datetime.
Например, для поля user_x200_last_promotion будут созданы следующие теги:
{USERS_DETAILS_XTRA_X200_LAST_PROMOTION} — отформатированное значение (если format задан) или timestamp.
{USERS_DETAILS_XTRA_X200_LAST_PROMOTION_TITLE} — название поля.
{USERS_DETAILS_XTRA_X200_LAST_PROMOTION_VALUE} — сырое значение (timestamp).
Обратите внимание, что в стандартной генерации тегов для экстраполей пользователей используется префикс user_, но он не включается в имя тега. В плагинах, подобных xtradbrowusers, могут быть свои соглашения.
Проверка наличия значения
Поскольку пустая дата хранится как 0, для проверки заполненности поля следует использовать тег _VALUE:
Условие <!-- IF {TAG_VALUE} --> истинно, если значение не пустое и не равно строке "0". Такой подход гарантирует, что блок с датой не появится, если дата не выбрана.
Оба способа эквивалентны для datetime, так как пустое значение всегда 0. Явное сравнение может быть полезно, если требуется сравнить с текущей датой или другими значениями.
Вывод даты в заданном формате
Если формат не задан в параметрах поля, можно отформатировать timestamp прямо в шаблоне, используя PHP-функцию date внутри {PHP}:
При выводе с заданным форматом cot_date() вернёт дату 1 января 1970 года, что может выглядеть как «01.01.1970». Поэтому всегда проверяйте наличие значения через _VALUE перед выводом.
При проверке обязательности в импорте 0 считается пустым значением.
Относительные даты
Если в значение поля в БД каким-либо образом попало число с ведущим + или - (например, +86400), то при построении формы оно будет преобразовано в $sys['now'] + 86400. Это удобно для динамических сроков, но требует осторожности: при сохранении такого значения через форму оно будет зафиксировано как конкретная дата.
Корректировка года по min/max
min и max влияют на список годов в форме, а также на импорт: если выбранный год меньше min, он заменяется на min, если больше max — на max.
Эти параметры не накладывают ограничений на значение, уже сохранённое в БД, если оно было изменено вручную.
Часовой пояс
При импорте время корректируется по часовому поясу текущего пользователя (того, кто заполняет форму).
При выводе используется часовой пояс пользователя, просматривающего страницу.
Если пользователь не авторизован, Cot::$usr['timezone'] может быть 0 или значение по умолчанию, обычно UTC.
Парсинг строк
cot_import_date() поддерживает импорт не только из массива компонентов, но и из обычной строки с датой. Это может быть полезно при интеграции с внешними источниками данных. Однако строковый ввод не используется в стандартной форме.
Хуки
Хук form.date позволяет полностью заменить вывод формы даты.
Хук import.date позволяет заменить логику импорта.
Если определена функция cot_selectbox_date_custom(), она имеет приоритет.
Влияние обязательности
Если поле datetime помечено как обязательное, пустое значение (0) вызовет ошибку валидации. Ошибка будет связана с именем поля, что позволяет показать сообщение рядом с соответствующей частью формы.
Заключение
Тип datetime в Cotonti является мощным инструментом для хранения дат и времени с учётом часовых поясов. Он хранит данные в виде UTC timestamp, обеспечивает удобный ввод через набор выпадающих списков и гибкий вывод с локализацией. При использовании в шаблонах важно помнить о проверке значения через _VALUE, чтобы корректно скрывать блоки с пустой датой.
Разработчики плагинов могут полностью контролировать поведение поля через параметры min, max и format, а также использовать хуки для расширения функциональности. Знание деталей работы функций cot_build_extrafields, cot_import_extrafields, cot_selectbox_date и cot_date позволяет эффективно интегрировать этот тип в любые модули и темы оформления.
Статья основана исключительно на анализе исходного кода Cotonti, и не содержит предположений или недостоверной информации.