Cron и часовые пояса: CRON_TZ, TZ и летнее время

Обновлено 6 ноября 2026

У строки crontab нет часового пояса. 0 9 * * 1-5 означает 9 утра в том поясе, в котором работает демон cron, а на облачном сервере это часто UTC, а не пояс людей, которым важна задача. Здесь — как узнать, в каком поясе работает cron, как его поменять и что происходит при переходе на летнее время.

В каком часовом поясе работает cron?

Cron использует системный пояс, который был установлен при запуске демона. Проверьте:

timedatectl | grep "Time zone"
date

Если вы меняете системный пояс командой timedatectl set-timezone Europe/Moscow, перезапустите cron (systemctl restart cron, на RHEL — crond), иначе он может продолжить работать по старому. В Docker-контейнерах пояс часто не задан вовсе, и cron работает по UTC, пока вы не зададите TZ и не установите пакет tzdata.

Вариант 1: сервер в UTC, время пересчитываем

Многие команды держат все серверы в UTC и пишут расписания в UTC намеренно: логи со всех машин совпадают по времени, и ничего не сдвигается дважды в год. Цена — пересчитывать время самому. 9 утра по Москве — это 06:00 UTC круглый год, потому что в России нет перехода на летнее время. А вот 9 утра в Берлине — 08:00 UTC зимой и 07:00 UTC летом, и строка в UTC сдвигается на час относительно местного времени при переводе часов.

Вариант 2: CRON_TZ в crontab

cronie — cron в RHEL, Rocky, AlmaLinux, Fedora и Arch — поддерживает часовой пояс для расписания:

CRON_TZ=Europe/Moscow
0 9 * * 1-5 /srv/report.sh

Строки после CRON_TZ читаются в этом поясе. Cron в Debian и Ubuntu этого не поддерживает: переменная передаётся задаче как любая другая, а расписание остаётся в системном поясе. Прежде чем на это полагаться, загляните в man 5 crontab на своём сервере.

TZ=... в crontab — другое. Эта переменная задаёт пояс, который видит задача, так что date внутри скрипта печатает местное время, но само расписание не сдвигается.

Вариант 3: таймер systemd с часовым поясом

Таймеры systemd принимают пояс в конце OnCalendar:

[Timer]
OnCalendar=Mon..Fri 09:00 Europe/Moscow
Persistent=true

Как systemd это понимает, проверяет systemd-analyze calendar "Mon..Fri 09:00 Europe/Moscow". Остальная настройка — в гайде по таймерам systemd.

Kubernetes и другие планировщики

Летнее время

В России часы не переводят с 2014 года, но если ваши пользователи или серверы в Европе или США, это касается и вас. Дважды в год местное время либо пропускает час, либо повторяет его. В США и большей части Европы весной часы переводят на час вперёд, осенью — на час назад, ночью. Страдают задачи, назначенные на этот час:

Cron в Debian особо обрабатывает переводы меньше трёх часов: задачи на фиксированное время, попавшие в пропущенный промежуток, запускаются сразу после перевода, а задачи в повторяющемся часе — один раз. В других реализациях по-разному. Надёжнее всего:

Мониторьте в том же поясе

Пропущенный запуск проще всего поймать, когда мониторинг точно знает расписание, в том же поясе, что и задача. В Heartcron у каждой проверки своё cron-выражение и свой часовой пояс, летнее время учитывается, так что 0 9 * * 1-5 в Europe/Berlin ожидается в 9 утра по Берлину круглый год:

heartcron checks create weekday-report --cron "0 9 * * 1-5" --tz Europe/Berlin --grace 15m

Потом добавьте пинг в задачу. Расшифровщик cron-выражений показывает ближайшие запуски в любом поясе — быстрый способ проверить, что значит выражение, до перевода часов и после.

Другие руководства