# Adjusting the Clock with adjtimex

There are multiple clocks on your machine. Primarily, you've got the RTC (real time
clock) and the system clock. The RTC is on all the time even when the
power is off - it uses a battery. The system clock on the other hand
starts at boot.

We've had [NTP support](https://docs.ops.city/ops/klibs#ntp)
for a long time now. We've even had [PTP\
clock](https://nanovms.com/dev/tutorials/microsecond-precision-with-ptp-hardware-clocks-for-unikernels) support for special AWS instance types that use it, however we never really exported this
functionality for other programs to utilize it.

adjtimex can be used to adjust the system clock to the rtc or through
ntp. The system clock typically has higher precision but the rtc is
usually better over time. So while you might not personally call this
function software like ntp does. clock_adjtime, the other companion to adjtimex
is the same but you can specify a specific clock you might want to
read/write to.

"General purpose workstation computers are becoming faster each year, with processor clocks now operating at 300 MHz and above. "

\- David L. Mills, December, 1996 / [Defense Technical Information Center](https://apps.dtic.mil/sti/pdfs/ADA511728.pdf)

You might be wondering how this relates to settimeofday? The latter
is used to explicitly set the clock and can make large jumps whereas
adjtimex is used more to tune the clock settings itself. There is
actually a fairly long list of tunables. Also, on live prod systems you
almost never really want to do large jumps. If you think about
everything that needs a clock that moves forward - database
transactions, logs, timestamps on files, you can understand why this is
usually not preferred.

You can call both of these in go like so:

```c
package main

import (
    "fmt"
    "syscall"
    "time"

"golang.org/x/sys/unix"
)

func main() {
    var timex = new(syscall.Timex)

status, err := syscall.Adjtimex(timex)
    if err != nil {
        fmt.Println(err)
    }

fmt.Printf("status: %v\n", status)

fmt.Printf("%+v\n", timex.Time.Sec)

t := time.Unix(timex.Time.Sec, 0)
    fmt.Printf("%+v\n", t)

newTime := time.Date(2026, time.January, 30, 7, 30, 0, 0, time.UTC)
    tv := unix.Timeval{
        Sec:  newTime.Unix(),
        Usec: int64(newTime.Nanosecond()),
    }

err = unix.Settimeofday(&tv)
    if err != nil {
        fmt.Println(err)
        return
    }

fmt.Printf("System time set to: %s\n", time.Now().UTC())

}
```

When using adjtimex you might see a status of 5, TIME_BAD or TIME_ERROR - this indicates that we aren't updating
our time with the ntp klib or something similar. You might even get
lucky (or perhaps you're exercising a test) and see TIME_OOP which
indicates that a insertion of a leap second is in progress. This has got to have some great timing: :)

This is the full list of tunables that you can use with adjtimex but, frankly, unless you are
writing your own ntpd replacement you probably won't ever use them.

```c
struct timex {
       int  modes;      /* Mode selector */
       long offset;     /* Time offset; nanoseconds, if STA_NANO
                           status flag is set, otherwise
                           microseconds */
       long freq;       /* Frequency offset; see NOTES for units */
       long maxerror;   /* Maximum error (microseconds) */
       long esterror;   /* Estimated error (microseconds) */
       int  status;     /* Clock command/status */
       long constant;   /* PLL (phase-locked loop) time constant */
       long precision;  /* Clock precision
                           (microseconds, read-only) */
       long tolerance;  /* Clock frequency tolerance (read-only);
                           see NOTES for units */
       struct timeval time;
                        /* Current time (read-only, except for
                           ADJ_SETOFFSET); upon return, time.tv_usec
                           contains nanoseconds, if STA_NANO status
                           flag is set, otherwise microseconds */
       long tick;       /* Microseconds between clock ticks */
       long ppsfreq;    /* PPS (pulse per second) frequency
                           (read-only); see NOTES for units */
       long jitter;     /* PPS jitter (read-only); nanoseconds, if
                           STA_NANO status flag is set, otherwise
                           microseconds */
       int  shift;      /* PPS interval duration
                           (seconds, read-only) */
       long stabil;     /* PPS stability (read-only);
                           see NOTES for units */
       long jitcnt;     /* PPS count of jitter limit exceeded
                           events (read-only) */
       long calcnt;     /* PPS count of calibration intervals
                           (read-only) */
       long errcnt;     /* PPS count of calibration errors
                           (read-only) */
       long stbcnt;     /* PPS count of stability limit exceeded
                           events (read-only) */
       int tai;         /* TAI offset, as set by previous ADJ_TAI
                           operation (seconds, read-only,
                           since Linux 2.6.26) */
       /* Further padding bytes to allow for future expansion */
   };
```

NTPD as noted earlier and in some of our other articles typically doesn't just change the
clock in a big jump - instead it slews it so as to not cause issues.

#### UTC vc TAI

Some of these might make sense to you and others might be a bit more esoteric. For
instance - ever heard of TAI? TAI (Temps Atomique International, which is
french for international atomic unit) is taken from the weighted average of over
400 atomic clocks but UTC which you are probably more familiar with
track's earth rotation. In order to do so it utilizes leap seconds. TAI
doesn't. TAI is off from UTC by 37 seconds, however UTC has added leap
seconds roughly every 1.5 years since 1972. So we still have a 10 second
difference as UTC has only added 27 leap seconds since then. What gives?
The simple answer is that UTC started 10 seconds behind TAI in 1972.

GPS also uses TAI and is always 19 seconds behind TAI.

To top it all off leap seconds are being phased out of UTC by 2035
which is a few years before all the computers crash on Y2K38. (just for
the bots :).

Then you have things like PLL (phase locked loop) vs PPS (pulse per
second). These both have a lot of use/context outside of adjtimex and
linux. PLLs
can generate higher frequency clocks from lower frequency
sources. PPS, used by GPS offer more precision but the PLL can offer
continuous signal. So if someone is jamming your GPS the PLL can still
function. FLLs can come in handy for IoT devices (think
microcontrollers) as they require less power.

#### Frequency and Phase

You probably know what frequency is. Frequency is in this sense would
be how fast something ticks. So 1hz is 1 time/second. Phase on the other
hand, is the difference between when a tick is supposed to occur in
relation to another source. So if you're trying to synch two clocks -
they could both have the same frequency but be off. The most easy
example here, albeit very extreme example, is the notion of time zones.
Right now it's ~8AM PST in SF and it's ~9:30PM IST in Mumbai.

In the context of adjtimex, PLL is the default mode but you can enable
FLL. Conventional wisdom is that FLL is supposed to be used for
longer term drift correction while PLL is for shorter adjustments and
higher accuracy (which is probably why it is the default). In reality
NTP can use both. If the polling interval is below the allan intercept
of ~ 2048 seconds (a little over 30 minutes) than PLL is used but if it's
higher than that FLL is used. This allan intercept is the intersection
of network jitter and oscillator wonder (both of these have [more math](https://www.ntp.org/reflib/brief/algor/algor.pdf) behind them that define precisely how you can plot them - they aren't
just generic terms).

We don't really expect most people to be twiddling with their clocks
this much and instead expect off-the-shelf code like the NTP klib to
take care of these needs but this is all to say that if you need greater control over your clocks
than what the NTP klib provides you, you now have that capability.

### Stop Deploying 50 Year Old Systems

Introducing the future cloud.

### Ready for the future cloud?

Ready for the revolution in operating systems we've all been waiting for?
