Задача: вывести ближайшее событие компонентом «Список новостей» и показать под ним таймер «до старта осталось 3 дня 4 часа». Дату события берём из свойства элемента, а сам отсчёт – на чистом JavaScript, без внешней библиотеки. Раньше для этого подключали jQuery.countdown, но в 2026 году отдельная библиотека и сам jQuery ради одного таймера уже избыточны.
Шаг 1. Свойство и настройка компонента
В инфоблоке «Мероприятия» создаём свойство «Дата мероприятия» типа «Дата/время» с кодом TIME_EVENT – из него таймер возьмёт дедлайн. Дальше настраиваем компонент bitrix:news.list:
- количество элементов на странице – 1 (нужно ближайшее событие);
- сортировка – по дате начала активности или по свойству
TIME_EVENT, чтобы «ближайшее» было первым; - в блоке «Источник данных» отмечаем свойство
TIME_EVENT, иначе оно не попадёт вDISPLAY_PROPERTIES.
Шаг 2. Отдаём дату в HTML через data-атрибут
Копируем шаблон компонента в свой шаблон сайта. В нём переводим значение свойства в Unix-timestamp через MakeTimeStamp() и кладём его в data-атрибут блока таймера. Timestamp – самый надёжный способ передать момент времени в JavaScript: он не зависит от формата даты и локали.
<?php foreach ($arItem['DISPLAY_PROPERTIES'] as $pid => $arProperty): ?>
<?php if ($pid === 'TIME_EVENT'): ?>
<?php $eventTs = MakeTimeStamp($arProperty['VALUE']); ?>
<div class="event__date">
<?= FormatDate('d F Y в H:i', $eventTs) ?> <?php // читаемая дата для человека ?>
</div>
<!-- дедлайн для JS: timestamp в миллисекундах -->
<div class="event__counter" data-deadline="<?= $eventTs * 1000 ?>"></div>
<?php endif ?>
<?php endforeach ?>
Здесь MakeTimeStamp переводит строку из свойства в timestamp (секунды), а * 1000 даёт миллисекунды – именно в них работает Date в JavaScript. Заодно выводим человеку понятную дату через FormatDate('d F Y в H:i', ...).
Шаг 3. Таймер на чистом JavaScript
В отдельном JS-файле забираем дедлайн из data-атрибута и раз в секунду пересчитываем остаток. Никакого jQuery – только современный синтаксис (const/let, стрелочные функции):
const box = document.querySelector('.event__counter');
if (box) {
const deadline = Number(box.dataset.deadline);
// склонение: plural(5, ['день','дня','дней']) → 'дней'
const plural = (n, forms) => {
const idx = (n % 100 > 4 && n % 100 < 20)
? 2
: [2, 0, 1, 1, 1, 2][Math.min(n % 10, 5)];
return forms[idx];
};
const render = () => {
const diff = deadline - Date.now();
if (diff <= 0) {
box.textContent = 'Событие началось';
clearInterval(timer);
return;
}
const totalSec = Math.floor(diff / 1000);
const days = Math.floor(totalSec / 86400);
const hours = Math.floor((totalSec % 86400) / 3600);
const mins = Math.floor((totalSec % 3600) / 60);
const secs = totalSec % 60;
box.textContent =
`${days} ${plural(days, ['день', 'дня', 'дней'])} ` +
`${hours} ${plural(hours, ['час', 'часа', 'часов'])} ` +
`${mins} ${plural(mins, ['минута', 'минуты', 'минут'])} ` +
`${secs} ${plural(secs, ['секунда', 'секунды', 'секунд'])}`;
};
render();
const timer = setInterval(render, 1000);
}
Почему именно так
- Считаем от
Date.now(), а не накапливаем. Каждый тик берёт свежую разницу «дедлайн − сейчас», поэтому таймер не «плывёт», даже если вкладка была свёрнута или браузер притормозил интервалы. - Останавливаемся на нуле. При
diff <= 0вызываемclearInterval, иначе счётчик уйдёт в отрицательные значения. - Склонение по русским правилам. Функция
pluralвыбирает форму «день / дня / дней» по последней цифре и исключению для 11–14.
Подводные камни
- Часовой пояс. Unix-timestamp не зависит от пояса, но
MakeTimeStampтрактует строку свойства в поясе сайта. Если сервер и посетитель в разных поясах, договоритесь, что дедлайн задаётся во времени сайта, и не смешивайте это с локальным временем браузера. - Кэш компонента. Дата попадает в кэшируемый шаблон как timestamp – это правильно: кэшируется момент, а не «осталось столько-то». Сам отсчёт всегда живой, потому что считается на клиенте.
- Свойство не выводится. Если
DISPLAY_PROPERTIESпуст, значит свойство не отмечено в «Источнике данных» настроек компонента – проверьте настройки, это самая частая причина «пустого» таймера. - Одна дата – один блок. Скрипт написан под один
.event__counter. Для нескольких таймеров на странице оберните логику вquerySelectorAll(...).forEach(...), чтобы у каждого был свой дедлайн.
Тот же приём для баннера акции без инфоблока – в гайде «Скрипт отсчёта времени до конца акции». Про форматирование дат из свойств – «Сменить формат даты в CMS Битрикс» и «Формат Ydiff». Как вывести конкретное свойство элемента – «Как вывести определённое поле элемента инфоблока».