A machine has one clock, and its time can be shown in any zone.
The kernel keeps time as a single number — seconds since 1 January 1970 in UTC, the universal time with no zones and no clock changes. date +%s prints that number. When a program shows the time to a person, it converts the number by a time zone — a rule saying how many hours to add to UTC and when the clocks change. The rules of every zone live in /usr/share/zoneinfo, and the machine's zone is the link /etc/localtime to one of those files.
The TZ environment variable swaps the zone for one program and whatever it starts:
The first two lines are the same moment, in UTC and in Moscow. timedatectl shows the machine's zone and clock together: Local time is the time in the machine's zone, Universal time is UTC, Time zone is the zone itself, and RTC time is the hardware clock the machine takes its time from at boot. The zone here is Etc/UTC, so Local time and Universal time match.
date +%s printed 1792584000. What will TZ=Asia/Tokyo date +%s print right after it?
-
The seconds since 1970 are counted in UTC and do not depend on the zone:
TZ=Asia/Tokyo dateshows other hours, but+%sprints the same number. -
The
%sformat works in any zone and prints the same number — it just does not need the zone.
The zone only changes how a moment looks to a person; the machine has one count of seconds since 1970 in UTC. So date +%s prints the same with any TZ, while plain TZ=Asia/Tokyo date shows other hours.
Key points
- The kernel keeps time as seconds since 1970 in UTC; the zone only turns them into hours and minutes for a person.
-
The machine's zone is the
/etc/localtimelink, visible intimedatectl; theTZvariable changes the zone for one program.