108.1 Maintain system time¶
Weight: 3
Candidates should be able to properly maintain the system time and synchronize the clock via NTP.
Objectives
- Set the system date and time.
- Set the hardware clock to the correct time in UTC.
- Configure the correct timezone.
- Basic NTP configuration using ntpd and chrony.
- Knowledge of using the pool.ntp.org service.
- Awareness of the ntpq command.
Terms
/usr/share/zoneinfo/, /etc/timezone, /etc/localtime, /etc/ntp.conf, /etc/chrony.conf, date, hwclock, ntpd, ntpdate, chronyc, pool.ntp.org
Two clocks¶
A Linux computer keeps time with two clocks:
| Clock | Where | Runs |
|---|---|---|
| hardware clock (or real-time clock, RTC) | a chip on the motherboard with its own battery | all the time, even when the computer is off |
| system (software) clock | kept by the kernel in memory | only while Linux is running |
At boot, the system clock is set from the hardware clock. After that, the two run independently and can slowly drift apart. Programs always use the system clock.
power off boot running
hardware clock ------> system clock set from it --> both tick separately
(battery) NTP keeps the system clock right
hwclock --systohc copies it back
On most modern systems, NTP (the Network Time Protocol) keeps the time correct for you, and the only thing a user sets is the time zone.
UTC and local time¶
The system clock counts time in UTC (Coordinated Universal Time, the time in Greenwich, UK). Local time is calculated from UTC by adding the offset of your time zone and any daylight saving time. Keeping the clock in UTC avoids a lot of trouble, because time zones and daylight saving rules change, sometimes by political decision.
The hardware clock should also be kept in UTC. It can be set to local time instead, which older operating systems did, but UTC is recommended.
date¶
date shows the system time as local time. -u shows UTC:
Output formats¶
| Option | Prints |
|---|---|
-I |
ISO 8601 format. -Idate gives the date only. Also hours, minutes, seconds, ns |
-R |
RFC 5322 format |
--rfc-3339=... |
RFC 3339 format |
+FORMAT |
your own format, built from codes like %Y (year), %m (month), %d (day), %H (hour), %M (minute), %T (time), %s (Unix time) |
Unix time (or epoch time) is how most Unix-like systems store time inside: the number of seconds since 1 January 1970, UTC. Stored in 32 bits, it runs out on 19 January 2038, a known problem for old 32-bit systems.
--date (-d) shows a time other than now, for example converting Unix time back into a date. --debug shows step by step how date understood your input, which helps with an application that writes odd dates:
$ date --date='@1564013011'
Wed Jul 24 20:03:31 EDT 2019
$ date --debug --date="Fri, 03 Jan 2020 14:00:17 -0500"
date: parsed day part: Fri (day ordinal=0 number=5)
date: parsed date part: (Y-M-D) 2020-01-03
date: parsed time part: 14:00:17 UTC-05
(...)
date: final: 1578078017.000000000 (epoch-seconds)
date: final: (Y-M-D) 2020-01-03 19:00:17 (UTC)
date: final: (Y-M-D) 2020-01-03 14:00:17 (UTC-05)
Setting the date¶
--set (or -s) sets the system clock. This needs root:
# date --set="11 Nov 2011 11:11:11"
# date +%Y%m%d -s "20111125" # date only: the format says how to read the text
# date +%T -s "13:11:00" # time only
hwclock¶
hwclock reads and sets the hardware clock. It needs root. It shows the time converted to local time, even when the hardware clock is kept in UTC:
Changing the system time does not touch the hardware clock. Here the system clock is moved to 2022, but hwclock still shows the real time:
$ date
Fri Jun 23 01:47:22 PM +0330 2023
$ sudo date -s "Jan 22 22:22:22 2022"
Sat Jan 22 10:22:22 PM +0330 2022
$ sudo hwclock
2023-06-23 13:47:41.160122+03:30
--verbose shows the details, including the device (/dev/rtc0), whether the clock is kept in UTC, and the drift between the two clocks:
$ sudo hwclock --verbose
hwclock from util-linux 2.34
System Time: 1578079387.976029
Trying to open: /dev/rtc0
Using the rtc interface to the clock.
Assuming hardware clock is kept in UTC time.
(...)
Calculated Hardware Clock drift is 0.000000 seconds
2020-01-03 14:23:07.948436-05:00
Copying between the clocks:
| Command | Short form | Copies |
|---|---|---|
hwclock --systohc |
hwclock -w |
system clock to hardware clock |
hwclock --hctosys |
hwclock -s |
hardware clock to system clock |
After you change the system time, run hwclock --systohc so both clocks agree. Or go the other way: set the hardware clock, then copy it into the system clock:
# hwclock --set --date "4/12/2019 11:15:19"
# hwclock
Fri 12 Apr 2019 6:15:19 AM EST -0.562862 seconds
# hwclock --hctosys
hwclock --set expects UTC by default and shows local time, which is why 11:15 became 6:15 EST. To say which one the hardware clock uses, add -u (--utc) or --localtime:
# hwclock --localtime --set --date="01/05/2023 22:04:00" # keep the hardware clock in local time
# hwclock -u -w # back to UTC, set from the system clock
The choice is remembered in /etc/adjtime. When you say neither, /etc/adjtime decides, and if that file does not exist, UTC is used.
timedatectl¶
On systemd systems, timedatectl is the preferred tool. It shows local time, UTC, the hardware (RTC) time, the time zone and the NTP status at once:
$ timedatectl
Local time: Thu 2019-12-05 11:08:05 EST
Universal time: Thu 2019-12-05 16:08:05 UTC
RTC time: Thu 2019-12-05 16:08:05
Time zone: America/Toronto (EST, -0500)
System clock synchronized: yes
NTP service: active
RTC in local TZ: no
RTC in local TZ: no means the hardware clock is in UTC, as it should be.
| Command | Does |
|---|---|
timedatectl set-time '2011-11-25 14:00:00' |
set date and time (or just HH:MM:SS) |
timedatectl list-timezones |
list the time zone names (long: use grep) |
timedatectl set-timezone Africa/Cairo |
set the time zone |
timedatectl set-ntp no |
turn NTP synchronization off (yes or true turns it on: timedatectl set-ntp true) |
When NTP is not available, timedatectl set-time is recommended over date and hwclock. date and hwclock remain important for older systems.
Time zone names must be exact: Africa/Cairo works, cairo or africa/cairo does not.
$ timedatectl set-timezone Africa/Cairo
$ timedatectl
Local time: Thu 2019-12-05 18:18:10 EET
Universal time: Thu 2019-12-05 16:18:10 UTC
RTC time: Thu 2019-12-05 16:18:10
Time zone: Africa/Cairo (EET, +0200)
System clock synchronized: yes
NTP service: active
RTC in local TZ: no
Universal time did not change, only local time did.
Time zones without timedatectl¶
Time zone rules are stored in /usr/share/zoneinfo/, in subdirectories named after continents: /usr/share/zoneinfo/Europe/Paris, /usr/share/zoneinfo/Asia/Tehran. Each file holds the offset from UTC and the daylight saving rules.
Linux reads the current zone from /etc/localtime. It is a binary file, usually a symbolic link into /usr/share/zoneinfo/, so it stays right when the zone data is updated:
$ ls -l /etc/localtime
lrwxrwxrwx 1 root root 31 Jun 22 11:19 /etc/localtime -> /usr/share/zoneinfo/Asia/Tehran
$ file /usr/share/zoneinfo/Asia/Tehran
/usr/share/zoneinfo/Asia/Tehran: timezone data, version 2, no gmt time flags, no std time flags, no leap seconds, 72 transition times, 8 abbreviation chars
To change the zone by hand, point the link at your zone, then update the hardware clock:
Some distributions also have /etc/timezone, a plain text file with the zone's name, which programs can read to show it:
| File | Is | Used by |
|---|---|---|
/usr/share/zoneinfo/ |
all time zone data | the system |
/etc/localtime |
the current zone, binary, usually a link | the system, to calculate local time |
/etc/timezone |
the current zone's name, text | some distributions and programs |
NTP¶
The most accurate time comes from reference clocks, usually atomic clocks. NTP (Network Time Protocol) lets every computer on the internet synchronize to them. NTP is organised in levels called strata:
reference clocks (atomic clocks)
|
stratum 1 servers attached to them usually not public
|
stratum 2 servers synced from stratum 1 public
|
stratum 3 ... and so on
In a large network, let a few machines sync with public stratum 2 servers and serve time to all the others, so the public servers carry less load.
Terms you will see in the tools:
| Term | Means |
|---|---|
| offset | the difference between system time and NTP time. 12:00:02 against 11:59:58 is an offset of 4 seconds |
| slew | an offset under 128 ms is corrected gradually, by speeding up or slowing down the clock |
| step | an offset over 128 ms is corrected in one jump |
| insane time | an offset over 17 minutes: the NTP daemon refuses to change the clock. You must fix it by hand first |
| drift | two clocks that slowly move apart over time |
| jitter | the drift since the last time the clock was checked |
NTP works on port 123 (UDP). If synchronization fails, check that this port is open.
pool.ntp.org¶
pool.ntp.org is a free, volunteer-run pool of public NTP servers. Each time you ask it, you get a different server at random, which spreads the load. Distributions use their own names in the pool, like 0.debian.pool.ntp.org or 0.centos.pool.ntp.org. For work where wrong time could cause real harm, the pool's own advice is to set up a local, reliable time service instead.
systemd-timesyncd¶
On systemd systems, timedatectl uses the systemd-timesyncd service, which is a simple SNTP client: it keeps this machine on time, but cannot serve time to other machines. It only works while the service runs:
$ systemctl status systemd-timesyncd
● systemd-timesyncd.service - Network Time Synchronization
Loaded: loaded (/lib/systemd/system/systemd-timesyncd.service; enabled; vendor preset: enabled)
Active: active (running) since Thu 2020-01-09 21:01:50 EST; 2 weeks 1 days ago
Status: "Synchronized to time server for the first time 91.189.89.198:123 (ntp.ubuntu.com)."
timedatectl show-timesync --all shows its details. That is enough for a single machine, but to sync many clients in a network, install a full NTP implementation: ntpd or chrony.
ntpd¶
ntpd is the classic NTP daemon. It runs in the background, compares the clock with NTP servers on a schedule, and can also serve time to other machines. Run only one of systemd-timesyncd, ntpd and chrony at a time. Install the ntp package, then start and enable the service (named ntp on Debian, ntpd on Red Hat systems):
# apt install ntp # Debian
# systemctl start ntp
# systemctl enable ntpd && systemctl start ntpd # Red Hat
$ systemctl status ntpd
● ntpd.service - Network Time Service
Loaded: loaded (/usr/lib/systemd/system/ntpd.service; enabled; vendor preset: disabled)
Active: active (running) since Fri 2019-12-06 03:27:21 EST; 7h ago
Main PID: 867 (ntpd)
It asks several sources and picks the best ones. If the network is lost, it uses its history to keep adjusting the clock.
/etc/ntp.conf¶
The servers to use are listed in /etc/ntp.conf:
# Use public servers from the pool.ntp.org project.
server 0.centos.pool.ntp.org iburst
server 1.centos.pool.ntp.org iburst
server 2.centos.pool.ntp.org iburst
server 3.centos.pool.ntp.org iburst
| Line | Means |
|---|---|
server 192.168.1.1 |
always ask this one server (an IP address, or a name if DNS works) |
pool 0.debian.pool.ntp.org |
ask a pool, which hands out a different server each time |
iburst |
send a quick burst of requests at startup, for a faster first sync |
driftfile /var/lib/ntp/ntp.drift |
where ntpd remembers how fast this clock drifts |
restrict ... |
access rules: who may ask this server for time, or change it |
On Debian the defaults look like this:
driftfile /var/lib/ntp/ntp.drift
pool 0.debian.pool.ntp.org iburst
pool 1.debian.pool.ntp.org iburst
pool 2.debian.pool.ntp.org iburst
pool 3.debian.pool.ntp.org iburst
# By default, exchange time with everybody, but don't allow configuration.
restrict -4 default kod notrap nomodify nopeer noquery limited
restrict -6 default kod notrap nomodify nopeer noquery limited
# Local users may interrogate the ntp server more closely.
restrict 127.0.0.1
restrict ::1
Restart the service after changing the file.
ntpdate¶
ntpdate sets the clock once, right now, from a server:
$ sudo ntpdate pool.ntp.org
23 Jun 14:49:55 ntpdate[160138]: adjust time server 31.214.170.254 offset +0.020196 sec
Its main use: when the clock is more than 17 minutes off (insane time), ntpd will not fix it, so you fix it by hand first:
-
Stop the daemon:
systemctl stop ntpd. While it runs, it holds the NTP port andntpdatefails: -
Run
ntpdate pool.ntp.org, more than once if needed. - Save it to the hardware clock with
hwclock -w, and startntpdagain.
ntpq¶
ntpq queries the NTP daemon to check its status. -p prints the servers (peers) it is using, and -n shows IP addresses instead of names. Without options it starts an interactive mode, where ? lists the commands:
$ ntpq -p
remote refid st t when poll reach delay offset jitter
==============================================================================
+37.44.185.42 91.189.94.4 3 u 86 128 377 126.509 -20.398 6.838
+ntp2.0x00.lv 193.204.114.233 2 u 82 128 377 143.885 -8.105 8.478
*inspektor-vlan1 121.131.112.137 2 u 17 128 377 112.878 -23.619 7.959
b1-66er.matrix. 18.26.4.105 2 u 484 128 10 34.907 -0.811 16.123
| Column | Means |
|---|---|
remote |
the NTP server |
refid |
that server's own reference |
st |
its stratum |
when |
seconds since the last query |
poll |
seconds between queries |
reach |
whether the server answered; grows with each success |
delay |
round trip time in ms |
offset |
difference between system time and the server, in ms |
jitter |
the variation since the last query, in ms |
The first character of each line is important: * marks the server currently used as the main reference, + a good candidate, and - a server out of range that is ignored.
chrony¶
chrony is a newer NTP implementation. It handles difficult conditions better than ntpd, like a laptop that is often offline or a busy network, and it is the default on Red Hat 8, SUSE 15 and many other distributions. It has two parts:
chronyd, the daemon. Start and enable it first.chronyc, the command line client. It talks tochronydover TCP or Unix sockets, so it can even monitor a remotechronyd, though remotely it is limited to mostly monitoring commands, for security.
chronyc tracking¶
$ chronyc tracking
Reference ID : 3265FB3D (bras-vprn-toroon2638w-lp130-11-50-101-251-61.dsl.)
Stratum : 3
Ref time (UTC) : Thu Jan 09 19:18:35 2020
System time : 0.000134029 seconds fast of NTP time
Last offset : +0.000166506 seconds
RMS offset : 0.000470712 seconds
Frequency : 919.818 ppm slow
Residual freq : +0.078 ppm
Skew : 0.555 ppm
Root delay : 0.006151616 seconds
Root dispersion : 0.010947504 seconds
Update interval : 129.8 seconds
Leap status : Normal
| Line | Means |
|---|---|
Reference ID |
the server we are synced to |
Stratum |
the number of hops to a reference clock |
System time |
how far the system clock is from NTP time |
Last offset |
the offset at the last update |
RMS offset |
the long-term average offset |
Frequency |
how wrong the clock would run without correction, in ppm (parts per million) |
Leap status |
Normal, Insert second, Delete second or Not synchronised |
chronyc sources and other commands¶
| Command | Shows or does |
|---|---|
chronyc tracking |
the sync status, above |
chronyc sources |
the NTP servers in use |
chronyc activity |
how many sources are online and offline |
chronyc ntpdata |
details of the last NTP update |
chronyc makestep |
steps the clock now, in one jump |
chronyc alone |
an interactive chronyc> prompt for the same commands |
$ chronyc sources
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
^+ brazil.time.system76.com 2 7 377 20 -13ms[ -13ms] +/- 190ms
^+ ohio.time.system76.com 2 7 377 21 +23ms[ +23ms] +/- 171ms
^* paris.time.system76.com 2 7 377 24 -4880us[-1560us] +/- 109ms
As in ntpq, * is the server in use and + a good candidate.
/etc/chrony.conf¶
chrony's configuration is /etc/chrony.conf (/etc/chrony/chrony.conf on Debian and Ubuntu). The servers use the same syntax as ntpd. In this example from Arch Linux the lines start with !, chrony's comment mark, so no source is active yet:
! server 0.arch.pool.ntp.org iburst
! server 1.arch.pool.ntp.org iburst
! server 2.arch.pool.ntp.org iburst
! pool 3.arch.pool.ntp.org iburst
! makestep 1.0 3
Remove the ! to use them. makestep 1.0 3 lets chrony step the clock when it is off by more than 1 second, during the first 3 updates, which fixes a large error at startup. The same file sets the driftfile and keyfile. After editing, restart chronyd, run chronyc makestep to correct the clock at once, and check the result with chronyc tracking:
More examples¶
The same commands once more, with other names and values, as a quick reference:
$ date
Fri Jun 23 01:47:22 PM +0330 2023
$ date -u # the same moment in UTC
$ date +%s # Unix epoch: seconds since 1 Jan 1970
$ sudo date -s "Jan 22 22:22:22 2022" # move the system clock
Sat Jan 22 10:22:22 PM +0330 2022
$ sudo hwclock # hardware clock is unchanged
2023-06-23 13:47:41 +03:30
# hwclock -w # (--systohc) set the hardware clock FROM the system clock
# hwclock -s # (--hctosys) set the system clock FROM the hardware clock
# hwclock -u -w # write it, and record that the hardware clock is in UTC
# hwclock --set --date "2024-01-22 22:22:22" # set the hardware clock to a given time
$ ls -l /etc/localtime
lrwxrwxrwx 1 root root 31 Jun 22 11:19 /etc/localtime -> /usr/share/zoneinfo/Asia/Tehran
# ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime # set it by hand
$ sudo ntpdate pool.ntp.org
23 Jun 14:49:55 ntpdate[160138]: adjust time server 31.214.170.254 offset +0.020196 sec
$ sudo hwclock -w
$ ntpq -p
remote refid st t when poll reach delay offset jitter
==============================================================================
+46.209.14.1 192.168.5.2 4 u 7 64 1 58.300 -15.546 14.519
*194.225.150.25 194.190.168.1 2 u 5 64 1 31.478 -3.870 95.635
-ntp.tums.ac.ir 195.161.115.4 4 u 4 64 1 30.636 2.485 4.025
$ chronyc tracking # how well the clock is synced
Reference ID : 0FED61D6 (paris.time.system76.com)
Stratum : 3
System time : 0.001574947 seconds slow of NTP time
Leap status : Normal
$ chronyc sources # the servers in use, with * for the selected one
$ sudo chronyc makestep # jump the clock to the correct time now
Summary¶
I keep two clocks straight. Linux has a hardware clock on the motherboard, which runs on battery and is read once at boot to set the system clock in the kernel, and then the two run separately. Both should be in UTC, and local time is UTC plus the time zone offset. date shows local time (-u for UTC, +%s for Unix time, seconds since 1970) and date -s sets the system clock. hwclock reads the hardware clock, --systohc (-w) copies the system time into it, so after setting the time by hand I run hwclock -w, --hctosys does the reverse, and -u or --localtime says how it is kept, remembered in /etc/adjtime. On systemd systems, timedatectl shows everything and sets the time, the time zone and NTP.
Time zone data lives in /usr/share/zoneinfo/, the active zone is /etc/localtime, usually a symbolic link into it, and some systems also keep its plain name in /etc/timezone. timedatectl set-timezone changes it, and by hand I relink /etc/localtime and run hwclock --systohc.
To stay accurate automatically I use NTP, which syncs clocks through a hierarchy of strata down from atomic clocks, on port 123. Small offsets are slewed gradually, larger ones stepped, and an offset over 17 minutes is insane time that the daemon will not touch, so I stop it and run ntpdate pool.ntp.org by hand for a one-shot correction. pool.ntp.org hands out a random volunteer server each time. systemd-timesyncd is a simple SNTP client for one machine, while ntpd is a full service configured in /etc/ntp.conf with server and pool lines, and ntpq -p shows its peers, with * marking the chosen one. chrony is the modern alternative that copes better with laptops and flaky networks: chronyd runs as the daemon, it is configured in /etc/chrony.conf, and chronyc tracking, sources and makestep check and correct the clock.