Keeping Time without External Synchronization
This discussion is based on the following conditions:
• Nothing is running that alters the date-time clocks, such as
NTP daemon or a cron job."
• The system timezone is configured for the correct local time.
See below, under POSIX vs 'RIGHT'
.
• Early during startup the following are called, in this order:
adjtimex --tick
value --frequency
value hwclock --hctosys
• During shutdown the following is called: hwclock --systohc
• Systems without adjtimex
may use ntptime
.
Whether maintaining precision time with NTP daemon or not, it
makes sense to configure the system to keep reasonably good
date-time on its own.
The first step in making that happen is having a clear
understanding of the big picture. There are two completely
separate hardware devices running at their own speed and drifting
away from the 'correct' time at their own rates. The methods and
software for drift correction are different for each of them.
However, most systems are configured to exchange values between
these two clocks at startup and shutdown. Now the individual
device's time keeping errors are transferred back and forth
between each other. Attempt to configure drift correction for
only one of them, and the other's drift will be overlaid upon it.
This problem can be avoided when configuring drift correction for
the System Clock by simply not shutting down the machine. This,
plus the fact that all of hwclock
's precision (including
calculating drift factors) depends upon the System Clock's rate
being correct, means that configuration of the System Clock
should be done first.
The System Clock drift is corrected with the adjtimex
(8)
command's --tick
and --frequency
options. These two work
together: tick is the coarse adjustment and frequency is the fine
adjustment. (For systems that do not have an adjtimex
package,
ntptime -f
ppm may be used instead.)
Some Linux distributions attempt to automatically calculate the
System Clock drift with adjtimex
's compare operation. Trying to
correct one drifting clock by using another drifting clock as a
reference is akin to a dog trying to catch its own tail. Success
may happen eventually, but great effort and frustration will
likely precede it. This automation may yield an improvement over
no configuration, but expecting optimum results would be in
error. A better choice for manual configuration would be
adjtimex
's --log
options.
It may be more effective to simply track the System Clock drift
with sntp
, or date -Ins
and a precision timepiece, and then
calculate the correction manually.
After setting the tick and frequency values, continue to test and
refine the adjustments until the System Clock keeps good time.
See adjtimex(2) for more information and the example
demonstrating manual drift calculations.
Once the System Clock is ticking smoothly, move on to the
Hardware Clock.
As a rule, cold drift will work best for most use cases. This
should be true even for 24/7 machines whose normal downtime
consists of a reboot. In that case the drift factor value makes
little difference. But on the rare occasion that the machine is
shut down for an extended period, then cold drift should yield
better results.
Steps to calculate cold drift:
1
Ensure that NTP daemon will not be launched at startup.
2
The System Clock time must be correct at shutdown!
3
Shut down the system.
4
Let an extended period pass without changing the Hardware
Clock.
5
Start the system.
6
Immediately use hwclock
to set the correct time, adding the
--update-drift
option.
Note: if step 6 uses --systohc
, then the System Clock must be set
correctly (step 6a) just before doing so.
Having hwclock
calculate the drift factor is a good starting
point, but for optimal results it will likely need to be adjusted
by directly editing the /etc/adjtime file. Continue to test and
refine the drift factor until the Hardware Clock is corrected
properly at startup. To check this, first make sure that the
System Time is correct before shutdown and then use sntp
, or date
-Ins
and a precision timepiece, immediately after startup.
LOCAL vs UTC
Keeping the Hardware Clock in a local timescale causes
inconsistent daylight saving time results:
• If Linux is running during a daylight saving time change, the
time written to the Hardware Clock will be adjusted for the
change.
• If Linux is NOT running during a daylight saving time change,
the time read from the Hardware Clock will NOT be adjusted
for the change.
The Hardware Clock on an ISA compatible system keeps only a date
and time, it has no concept of timezone nor daylight saving.
Therefore, when hwclock
is told that it is in local time, it
assumes it is in the 'correct' local time and makes no
adjustments to the time read from it.
Linux handles daylight saving time changes transparently only
when the Hardware Clock is kept in the UTC timescale. Doing so is
made easy for system administrators as hwclock
uses local time
for its output and as the argument to the --date
option.
POSIX systems, like Linux, are designed to have the System Clock
operate in the UTC timescale. The Hardware Clock's purpose is to
initialize the System Clock, so also keeping it in UTC makes
sense.
Linux does, however, attempt to accommodate the Hardware Clock
being in the local timescale. This is primarily for dual-booting
with older versions of MS Windows. From Windows 7 on, the
RealTimeIsUniversal registry key is supposed to be working
properly so that its Hardware Clock can be kept in UTC.
POSIX vs 'RIGHT'
A discussion on date-time configuration would be incomplete
without addressing timezones, this is mostly well covered by
tzset(3). One area that seems to have no documentation is the
'right' directory of the Time Zone Database, sometimes called tz
or zoneinfo.
There are two separate databases in the zoneinfo system, posix
and 'right'. 'Right' (now named zoneinfo-leaps) includes leap
seconds and posix does not. To use the 'right' database the
System Clock must be set to (UTC + leap seconds), which is
equivalent to (TAI - 10). This allows calculating the exact
number of seconds between two dates that cross a leap second
epoch. The System Clock is then converted to the correct civil
time, including UTC, by using the 'right' timezone files which
subtract the leap seconds. Note: this configuration is considered
experimental and is known to have issues.
To configure a system to use a particular database all of the
files located in its directory must be copied to the root of
/usr/share/zoneinfo. Files are never used directly from the posix
or 'right' subdirectories, e.g., TZ='right/Europe/Dublin'. This
habit was becoming so common that the upstream zoneinfo project
restructured the system's file tree by moving the posix and
'right' subdirectories out of the zoneinfo directory and into
sibling directories:
/usr/share/zoneinfo, /usr/share/zoneinfo-posix,
/usr/share/zoneinfo-leaps
Unfortunately, some Linux distributions are changing it back to
the old tree structure in their packages. So the problem of
system administrators reaching into the 'right' subdirectory
persists. This causes the system timezone to be configured to
include leap seconds while the zoneinfo database is still
configured to exclude them. Then when an application such as a
World Clock needs the South_Pole timezone file; or an email MTA,
or hwclock
needs the UTC timezone file; they fetch it from the
root of /usr/share/zoneinfo , because that is what they are
supposed to do. Those files exclude leap seconds, but the System
Clock now includes them, causing an incorrect time conversion.
Attempting to mix and match files from these separate databases
will not work, because they each require the System Clock to use
a different timescale. The zoneinfo database must be configured
to use either posix or 'right', as described above, or by
assigning a database path to the TZDIR environment variable.