./ahmedhashim

Clock Drift

My Arch desktop had drifted a minute ahead of two clocks I never question: my radio-controlled Casio GW-B5600 and my phone. The watch receives a longwave time signal to set itself. The phone gets network time. They agreed with each other, so my desktop was the odd one out.

timedatectl was my first stop:

$ timedatectl status
               Local time: Sat 2025-01-04 08:11:01 PST
           Universal time: Sat 2025-01-04 16:11:01 UTC
                 RTC time: Sat 2025-01-04 16:11:01
                Time zone: America/Los_Angeles (PST, -0800)
System clock synchronized: no
              NTP service: inactive
          RTC in local TZ: no

Lines to note are System clock synchronized: no and NTP service: inactive, which implied nothing was adjusting the clock. When Linux boots, it grabs the time from the RTC (the battery-backed clock on the motherboard). Then it just ticks away with its own hardware timers. With no NTP running, nothing ever validates that count against another source.

RTC in local TZ: no was good news. That meant the hardware clock was already using UTC, which is what I want on Linux anyway. Done deal.

The solution was to enable time syncing, which turns on and starts systemd-timesyncd:

sudo timedatectl set-ntp true

timedatectl looked much better after a couple of packets:

$ timedatectl status
               Local time: Sat 2025-01-04 08:18:42 PST
           Universal time: Sat 2025-01-04 16:18:42 UTC
                 RTC time: Sat 2025-01-04 16:18:42
                Time zone: America/Los_Angeles (PST, -0800)
System clock synchronized: yes
              NTP service: active
          RTC in local TZ: no

timedatectl timesync-status displays all the details:

$ timedatectl timesync-status
       Server: 141.11.228.173 (0.arch.pool.ntp.org)
Poll interval: 34min 8s (min: 32s; max 34min 8s)
         Leap: normal
      Version: 4
      Stratum: 2
    Reference: 11FD0225
    Precision: 1us (-26)
Root distance: 1.052ms (max: 5s)
       Offset: +4.917ms
        Delay: 81.811ms
       Jitter: 3.721ms
 Packet count: 8
    Frequency: +4.873ppm

Here’s what some of the useful fields above mean:

  • Server is the NTP server chosen from the pool. The IP address isn’t important.
  • Poll interval is how frequently the client requests the time. It begins at 32 seconds and expands as the local clock demonstrates consistency.
  • Stratum is the distance from the source of time, for example how many hops away a server is from GPS hardware or a radio clock. A stratum 2 server means it’s synchronized from a stratum 1 server, which is typical for a desktop connected to the public internet.
  • Root distance is the server’s best guess as to its maximum error relative to that primary reference. It’s about a millisecond here, safely below the five-second threshold where timesyncd would change servers.
  • Offset is how far my clock is ahead or behind theirs. A few milliseconds is normal over the public internet.
  • Delay is the round-trip time to the server. 82ms isn’t shocking for public NTP.
  • Jitter is how much your samples differ from one another. Lower is better, and a few ms is good.
  • Packet count is how many replies you’ve received from this server so far.

Leap indicates if a leap second is impending. Version is the NTP protocol version being used. Reference and Precision describe the server’s upstream source and its own clock. They’re mainly useful if you’re debugging the server itself.

This leaves us with Frequency, the ppm correction that the kernel has learned for the local oscillator. If the value is positive, the kernel is speeding the clock up. Left unchecked, the system clock would lose ~4.9 microseconds per second:

4.873 ppm * 86,400 seconds/day = 0.421 seconds/day

A slow clock would lag behind, but the desktop was ahead, so the additional minute had come from the RTC. That’s a separate crystal that keeps time when the machine is powered off, and each time the machine boots, its time is copied into the system clock. With no NTP running, nothing had been adjusting it either. RTC crystals are often rated at ±20ppm, or up to about 1.7 seconds per day, so a minute only takes a month or two to accrue.

While synchronized, the kernel writes the system time back to the RTC every 11 minutes. You can make it write now as well:

sudo hwclock --systohc --utc

Either way, after the next boot it starts off at the correct time rather than whatever the RTC had drifted to. With NTP enabled, the desktop checks in with the outside world just like the watch and phone do, and its offset is only a few milliseconds.