2025, Nov 27 19:00

Fixing Python timezone issues on Raspberry Pi when timedatectl changes don't apply: zoneinfo, TZ+tzset, restart

Why changing system timezone with timedatectl doesn't affect a running Python process on Raspberry Pi, and how to fix it using zoneinfo or TZ+tzset or restart.

Changing the system timezone on a running Raspberry Pi process can be deceptive: the command succeeds, yet Python keeps printing datetimes in the old timezone. This guide explains why that happens and shows safe, predictable ways to handle timezones in Python.

Reproducing the issue

The following minimal snippet updates the system timezone with timedatectl and immediately prints the current datetime:

import datetime as dt
import subprocess as sp
sp.run('sudo timedatectl set-timezone America/Toronto', shell=True)
print(dt.datetime.now())

If you set the system timezone to something else beforehand, run this code, and then inspect the output, it will still reflect the original timezone. Running a fresh Python process afterwards and printing the time does show the changed timezone.

Why this happens

Python reads the system timezone only once when the process starts. When you change it mid-execution with timedatectl, the already running process does not pick up that change. New processes see the new timezone; the current one does not.

Reliable ways to fix it

The first option is to change the timezone before starting Python and then run the script. In practice that means invoking timedatectl first and only then starting the interpreter. This ensures the process initializes with the updated timezone.

sudo timedatectl set-timezone America/Toronto
python script.py

The second option is to avoid relying on the process-wide system timezone and pass an explicit timezone to your datetime calls. With Python 3.9+, zoneinfo provides timezones by name and returns the right localized timestamp for that zone.

from datetime import datetime as dts
from zoneinfo import ZoneInfo as ZI
print(dts.now(ZI("America/Toronto")))

The third option on Linux is to set the TZ environment variable and call tzset() so the running process updates its notion of the local timezone. This approach works with TZ and does not rely on timedatectl.

import os as osp
import time as tmod
osp.environ['TZ'] = 'America/Toronto'
tmod.tzset()

This only works with TZ, not timedatectl.

Why this matters

Timezone handling influences logs, schedules, timers, and any time-based logic. Assuming that a running process will “notice” a system timezone change leads to drift between expected and actual behavior. Being explicit about which timezone you use, or controlling when the process initializes its timezone, keeps your application predictable.

Takeaways

Do not expect timedatectl to affect a running Python process. If you must change the system setting, restart the script after the change. If you need per-call control or portability within the same process, use zoneinfo and pass the desired timezone directly. On Linux, if your workflow is tied to the local timezone but must be updated without restarting, set the TZ variable and call tzset(), understanding that this approach is specific to TZ and not to timedatectl.