Hardware Clock and hwclock: Syncing the System Clock and RTC on Linux
AI generated
$
/etc
Linux · hwclock · RTC · Server Administration
Hardware Clock and hwclock
Syncing the System Clock and RTC on Linux

Alongside the system clock the kernel keeps in memory, almost every physical and virtual machine has a battery backed hardware clock that keeps running even while the machine is powered off. Anyone who does not know the difference between the system clock and the hardware clock will sooner or later be puzzled by wrong boot timestamps, mistimed certificate checks, or a dual boot system that shows a different time after every Windows startup. This article explains how hwclock works, how to set the hardware clock correctly, and how to keep it reliably synchronized with the system clock.

16 min read hwclock · adjtime · RTC · timedatectl Debian · Ubuntu · RHEL · systemd

1. System clock and hardware clock: two separate timekeepers

A Linux system practically always has two independent clocks. The system clock is a software counter inside the kernel that gets initialized at boot and then keeps ticking driven by the CPU timer interrupt. The hardware clock, also called RTC or Real Time Clock, is a separate chip on the mainboard with its own battery that keeps counting seconds even while the machine is switched off. The hwclock command is the classic interface between these two worlds and is responsible at boot time for making the system clock take over the value stored in the hardware clock.

The practical difference becomes visible as soon as a machine stays powered off longer than planned, or when the hardware clock battery runs empty. While the system clock starts with an arbitrary, often wrong value on the next boot, the RTC usually provides a usable starting point as long as the battery still works. For servers that validate certificates, correlate logs, or timestamp database transactions, a correctly set hardware clock is therefore not a minor detail but a basic requirement for correct operation right after startup, before network time synchronization can even take effect.

2. The RTC in detail: battery, chip, and resolution

Physically, the RTC consists of a small, extremely power efficient chip, usually based on a quartz oscillator, powered by a coin cell battery or a capacitor. This battery lasts several years depending on the model, which is why a laptop that has been sitting in a drawer for a long time still shows a roughly correct time. On Linux the RTC appears as a device file under /dev/rtc0 and exposes additional information under /sys/class/rtc/rtc0/, including the current value, supported wakeup features, and the name of the underlying driver.

An important difference from the system clock: the hardware clock stores only seconds in many implementations, no sub second resolution. That is unproblematic for a pure boot timestamp, but it makes the RTC unsuitable as the sole time source for applications with millisecond requirements. In addition, practically every quartz oscillator drifts over time, usually within a range of a few seconds per month, depending on temperature and component quality. This drift is the actual reason why combining the RTC with network time makes more sense than relying exclusively on the hardware clock.


# Inspect the RTC device and its capabilities
ls /sys/class/rtc/
cat /sys/class/rtc/rtc0/name
cat /sys/class/rtc/rtc0/since_epoch

# Read the raw RTC time directly from the kernel driver
sudo hwclock --show --verbose

3. hwclock in practice: show, systohc, hctosys

The hwclock tool has three core operations. hwclock --show reads the hardware clock and displays it without changing anything, ideal for a quick diagnosis. hwclock --systohc writes the current system clock into the hardware clock and is typically called after a successful network synchronization so the RTC provides an up to date value on the next cold boot. hwclock --hctosys goes the opposite direction and sets the system clock from the hardware clock, a step systemd already performs automatically at boot, before network services are even started.

In practice you rarely call hwclock manually, because modern distributions automate the process through systemd services. Still, the manual invocation is indispensable for diagnostics, for example to check whether there is a discrepancy between the system clock and the hardware clock, or to deliberately reset the hardware clock after a BIOS update or battery replacement. It is important to never call hwclock in parallel with a running NTP daemon like chrony without briefly pausing it, since otherwise two processes try to correct the same clock at once.


# Show the current hardware clock value without changing anything
sudo hwclock --show

# Write the (already synced) system clock into the hardware clock
sudo hwclock --systohc

# Set the system clock from the hardware clock (normally done at boot)
sudo hwclock --hctosys

# Manually set a specific hardware clock value (rare, for recovery only)
sudo hwclock --set --date="2026-07-30 14:32:00"

4. UTC vs. local time in the hardware clock

One of the most common sources of confusion is whether the hardware clock stores UTC or local time. Linux distributions default to assuming UTC in the RTC, which is the right choice for several reasons: timezone changes and daylight saving transitions then only affect how the system clock interprets the time, not the raw values stored in the hardware clock itself. Windows, on the other hand, historically stores local time in the RTC, which leads to a shift of several hours on dual boot systems whenever you switch between the two operating systems.

The command timedatectl set-local-rtc 1 switches Linux to local RTC time, which can be a practical solution on pure dual boot desktops but should absolutely be avoided on servers. Servers should consistently stay at timedatectl set-local-rtc 0, meaning UTC in the hardware clock, because that is the only setting that works without additional pitfalls with automated deployments, container hosts, and virtual machines. The setting itself lives in the file /etc/adjtime, which besides the RTC mode also stores the most recently measured drift rate.


# /etc/adjtime — persisted state used by hwclock
# Line 1: measured drift factor (seconds per day) and last calibration timestamp
# Line 2: last time hwclock was called
# Line 3: RTC mode, either UTC or LOCAL

0.123456 1785500000 0.500000
1785500000
UTC

5. Interaction with systemd and timedatectl during boot

On systemd systems, either systemd-timesyncd or chrony implicitly takes over most of the classic hwclock tasks at boot. Right after the kernel starts, systemd reads the hardware clock, sets the system clock from it, and then starts network time synchronization. Once that succeeded, systemd can be configured to periodically write the new, precise time back into the hardware clock, so a later cold boot benefits from a reasonably accurate starting value, even if the network is briefly unreachable at the next boot.

The timedatectl command is the modern, systemd native view of both clocks at once and shows in its output both the local time and the RTC status, plus whether time is synchronized via NTP. Anyone who carries over old init scripts or cron based hwclock calls from pre systemd times into a current system risks race conditions with the built in systemd mechanisms. On modern distributions it is almost always enough to set timedatectl set-ntp true and let chronyd handle fine grained synchronization as well as periodically updating the hardware clock.

6. Measuring clock drift and correcting it with adjtime

Every quartz oscillator has an individual, usually temperature dependent deviation from its nominal frequency, referred to as drift. The kernel measures this drift automatically once the hardware clock is regularly compared against an accurate external source, and stores the determined rate in seconds per day in /etc/adjtime. hwclock then uses this stored rate to pre correct the RTC between two synchronizations, so the deviation is practically unnoticeable in day to day operation.

In practice, checking the drift value is especially worthwhile on older server hardware or virtual machines with an emulated RTC, where unusually high drift values can point to an underlying problem in the hypervisor. A drift of more than a few seconds per day is a warning sign and justifies a closer look at the virtualization layer, since a working network time synchronization masks the underlying drift but does not fix the actual problem at the hypervisor level.

7. The RTC in virtual machines and cloud instances

Virtual machines do not have a real, battery backed hardware clock, but rather an RTC emulated by the hypervisor. KVM, VMware, and most cloud platforms mimic the behavior of a physical clock but additionally couple its accuracy to the timing of the host system. This leads to a well known phenomenon: under high host load, or after restoring a snapshot, the emulated time of the guest VM can drift noticeably from the real time, sometimes by several minutes, until a network synchronization corrects the error.

For cloud instances it is therefore recommended to run chronyd with short poll intervals and, where available, use the internal time source provided by the cloud vendor instead of relying exclusively on public NTP pools. After restoring a snapshot or after a live migration, an immediate, forced time correction makes sense, for example with chronyc makestep, so applications do not start with an outdated clock while the regular, gradual correction is still in progress.


# Force an immediate time step instead of gradual slewing (use after snapshot restore)
sudo chronyc makestep

# Check current offset and whether the system is considered synchronized
chronyc tracking

# On cloud VMs: verify which RTC device is actually exposed to the guest
dmesg | grep -i rtc

8. Typical symptoms of a wrong hardware clock

An incorrectly set or drifting hardware clock rarely shows up directly, but rather through symptoms elsewhere. TLS connections fail with certificate errors because the validity window of a certificate is barely missed. Log entries from different systems can no longer be correlated correctly because timestamps are systematically shifted. Scheduled backups run at the wrong time or overlap because cron jobs are triggered based on a wrong system time before network time synchronization has even taken effect.

The first diagnostic step for such symptoms is always the same: compare hwclock --show with date and check whether both values differ significantly. A deviation in the range of minutes or hours points to an empty RTC battery, a wrong UTC or local time mode, or a failed boot sync. A deviation in the range of seconds that repeats regularly is usually normal drift, which is continuously corrected anyway by a working network time synchronization and does not require manual intervention.

9. hwclock, timedatectl, and chronyc compared

All three tools relate to time on Linux but cover different layers and do not exclude each other. Knowing which tool is responsible for which task saves a lot of misdiagnosis and unnecessary manual intervention in systems that actually already work correctly on their own.

Tool Responsible for Typical use Automated?
hwclock Direct access to the RTC Diagnosis, manual correction, recovery No
timedatectl Timezone, NTP status, RTC mode Status queries, timezone changes Partially
chronyc Network time synchronization Ongoing offset correction, monitoring Yes
adjtime file Stored drift rate and RTC mode Automatically maintained by hwclock Yes

Usually the tools work together automatically: chronyd keeps the system clock precise, systemd ensures the initial synchronization with the hardware clock at boot, and hwclock remains in the background as a manual diagnostic and recovery tool. Only in special cases like dual boot systems, old init systems, or hardware without a working RTC battery do you actually have to intervene manually and understand the relationships between the three layers in detail.

Mironsoft

Linux server administration and operational practice for hosting environments

Want your servers' time issues reliably solved?

We check the hardware clock, system clock, and time synchronization on your servers, identify drift problems, and set up a robust configuration for boot timestamps, certificate checks, and log correlation.

Time audit

Systematically check RTC mode, drift rate, and synchronization status

Configuration

Cleanly set up UTC mode, chrony fine tuning, and boot ordering

Monitoring

Build alerting for drift and synchronization failures

10. Summary

The hardware clock and the system clock are two separate timekeepers, connected through hwclock at boot and afterward through systemd. The RTC keeps running on battery power while the machine is off, but it drifts over time and only offers second level resolution. UTC is the correct mode for the hardware clock on servers, local time does not belong there and should at most be used on dual boot desktops. The drift rate is automatically stored in /etc/adjtime and used by hwclock for pre correction.

In virtual machines the RTC is emulated and can deviate noticeably for a short time after snapshots or migrations, which is why a forced time step with chronyc makestep makes sense. Symptoms of a wrong hardware clock usually show up indirectly, through certificate errors, shifted logs, or wrongly triggered cron jobs, not through an obvious error message. Anyone who understands hwclock, timedatectl, and chronyc as complementary tools operating at different layers diagnoses time problems much faster.

Hardware clock and hwclock on Linux, the essentials at a glance

Two separate clocks

System clock in kernel RAM, hardware clock battery backed on the mainboard. hwclock connects both at boot.

Always UTC on servers

timedatectl set-local-rtc 0 keeps the RTC in UTC. Local time only belongs in the hardware clock on dual boot desktops.

Drift is normal

Every quartz drifts slightly. /etc/adjtime stores the rate, chrony compensates the rest continuously.

VMs need makestep

After snapshot restore or migration use chronyc makestep instead of waiting for slow slewing.

11. FAQ: Hardware Clock and hwclock on Linux

1System clock vs. hardware clock?
The system clock only runs while the machine is on. The RTC is battery backed and provides the starting value at boot.
2UTC or local time in the RTC?
Always UTC on servers. Local time only on dual boot desktops with Windows, which historically expects local time.
3What does hwclock --systohc do?
Writes the current system clock into the hardware clock, usually after a successful network synchronization.
4Empty RTC battery, what happens?
The clock loses its value and starts with an arbitrary date. Network synchronization fixes it quickly, but certificate checks can fail in the meantime.
5Why does the RTC drift?
Quartz oscillators have slightly different natural frequencies, influenced by temperature and manufacturing. That accumulates into measurable drift.
6Where is the drift rate stored?
In /etc/adjtime, along with the timestamp of the last calibration and the RTC mode.
7Why is a VM clock less accurate?
The RTC of a VM is emulated and coupled to the hypervisor timing. Under host load or after snapshots it can deviate noticeably.
8Force an immediate time jump?
chronyc makestep. Especially useful after snapshot restore when the deviation is too large for normal slewing.
9Use hwclock and chronyd together?
Yes, as long as hwclock is not called manually while chronyd is actively running. systemd coordinates that automatically at boot.
10How do I diagnose a wrong RTC value?
Compare hwclock --show with date. A minute or hour level deviation points to an empty battery or wrong mode, not normal drift.