2025, Dec 11 03:01
Почему timedatectl не меняет часовой пояс в работающем Python и что делать
Меняете часовой пояс на Raspberry Pi через timedatectl, а Python показывает старое время? Почему так и что делать: перезапуск, zoneinfo, TZ и tzset. Подробнее.
Менять системный часовой пояс на работающем процессе Raspberry Pi может быть коварно: команда выполняется успешно, но Python продолжает выводить дату и время в старом часовом поясе. В этом руководстве объясняется, почему так происходит, и показаны безопасные, предсказуемые способы работать с часовыми поясами в Python.
Как воспроизвести проблему
Ниже приведён минимальный пример: он меняет системный часовой пояс через timedatectl и тут же печатает текущие дату и время:
import datetime as dt
import subprocess as sp
sp.run('sudo timedatectl set-timezone America/Toronto', shell=True)
print(dt.datetime.now())
Если перед запуском вы зададите другой системный часовой пояс, выполните этот код и посмотрите на вывод, он всё равно будет соответствовать исходному поясу. Зато новый процесс Python, запущенный после изменения, уже покажет обновлённый часовой пояс.
Почему так происходит
Python считывает системный часовой пояс лишь один раз — при старте процесса. Когда вы меняете его на лету через timedatectl, уже запущенный процесс этого не замечает. Новые процессы видят новый пояс, текущий — нет.
Надёжные способы исправить ситуацию
Первый вариант — поменять часовой пояс до запуска Python, а затем выполнить скрипт. На практике это значит: сначала вызвать timedatectl, и только после этого запускать интерпретатор. Так процесс инициализируется уже с обновлённым часовым поясом.
sudo timedatectl set-timezone America/Toronto
python script.py
Второй вариант — не полагаться на системный часовой пояс процесса и передавать явный часовой пояс в вызовах datetime. Начиная с Python 3.9, модуль zoneinfo позволяет задавать пояса по имени и возвращает корректное локализованное время для выбранной зоны.
from datetime import datetime as dts
from zoneinfo import ZoneInfo as ZI
print(dts.now(ZI("America/Toronto")))
Третий вариант в Linux — установить переменную окружения TZ и вызвать tzset(), чтобы работающий процесс обновил представление о локальном часовом поясе. Этот способ опирается на TZ и не зависит от timedatectl.
import os as osp
import time as tmod
osp.environ['TZ'] = 'America/Toronto'
`tmod.tzset()`
Это работает только с TZ, а не с timedatectl.
Почему это важно
Обработка часовых поясов влияет на логи, расписания, таймеры и любую логику, завязанную на время. Ожидание, что работающий процесс «заметит» изменение системного пояса, приводит к расхождению между ожидаемым и реальным поведением. Чётко указывая используемый пояс или контролируя момент инициализации пояса процессом, вы сохраняете предсказуемость приложения.
Главное
Не рассчитывайте, что timedatectl повлияет на уже запущенный процесс Python. Если нужно изменить системную настройку, перезапустите скрипт после изменения. Когда требуется управлять поясом при каждом вызове или обеспечить переносимость внутри одного процесса, используйте zoneinfo и передавайте нужный пояс напрямую. В Linux, если вы привязаны к локальному поясу и хотите обновить его без перезапуска, установите переменную TZ и вызовите tzset(), понимая, что этот путь специфичен именно для TZ, а не для timedatectl.