Learn how time tracking is implemented from the hardware.

Time is a linear monotonically increasing value and to keep track of it, a system has to be powered to take note of every tick. For a microcomputer running an operating system that can go on and off, this means there is a need to constantly update time whenever the computer comes on, but that is not the case because of some intelligent mechanisms that computer hardware and operating systems use to keep track of the current time.

Real-Time Clock

Real-Time Clock (RTC) is an electronic hardware component that helps track the current time and date, even when the system is powered off.

How it works

RTC uses an oscillator that generates a stable and precise frequency, typically 32.768 kHz. The pulses from the oscillator are sent to counters within the RTC chip where seconds, minutes, hours, days, and so on are measured. These counters increment to keep track of the current time and date. The values for the current date and time are stored in registers contained within the RTC chipset, these registers also help to keep track of configuration values such as alarms, enabling and disabling the clock, and adjusting for leap years.

RTC chips can be powered by a CMOS RAM battery but are mostly powered internally by an alternate power source, usually a replaceable lithium battery or modern supercapacitors.

Network Time Protocol

Although RTC can keep track of time using oscillators, there is no source of truth for what the current time might be.

NTP is a protocol designed to synchronize the clocks of computers over a network. It aims to keep the system time in sync with more accurate time sources, such as atomic clocks or GPS clocks. It implements the intersection algorithm and uses a client-server model to send time stamps which is accurate to 10 milliseconds over the public internet.

RTC and NTP

As mentioned earlier, time is monotonically increasing, operating systems use a combination of RTP and NTP to maintain a consistent time that users see.

On Windows, support for NTP is inbuilt can be configured through the system settings or the command line, and is managed by Windows Time service. This service can be manually started with:

$$
net start w32time
$$

On Linux, support for NTP is also built-in, but can be installed manually:

$$
sudo apt-get install ntp # Debian/Ubuntu
sudo yum install ntp # CentOS/RHEL
sudo dnf install ntp # Fedora
$$

And can be started as a daemon afterwards:

$$
sudo systemctl enable ntp
sudo systemctl start ntp
$$

RTC on mobile devices

For devices that do not have any networking support but can send and receive radio signals, there is a Radio-based RTC that mobile network providers use to send current time to mobile devices. This can explain why time is always correct on mobile devices even in remote areas without access to the internet.

    Wall Clock and Monotonic Clock

    Computers rely on interrupts and signals to function properly like scheduling processes. Interrupts are implemented with timers that send signals at specific intervals. With the time information provided by RTC, if the time is updated by NTP to an older or future time, this causes problems for the operating system to determine what processes to interrupt or resume.

    To solve this problem, computers use a monotonically increasing counter called the Monotonic Clock. It provides a continuously increasing value that represents the total elapsed time since an unspecified starting point (often the boot time of the system). This introduces a second clock to the operating system, and brought about the name Monotonic Clock, while RTC is referred to as the Wall Clock.

    Monotonic clocks are useful for:

    • accurately measuring the elapsed time between events

    • implementing timeouts and delays in applications where time needs to be measured consistently and without interruption

    • Ensuring reliable timing in distributed systems where synchronized actions are crucial.

    Most programming languages provide access to both time:

    Python

    $$
    import time
    print(“Current time:”, time.time())
    print(“Monotonic time:”, time.monotonic())
    $$

    Ruby

    $$
    current_time = Time.now
    puts “Current time: #{current_time}”
    monotonic_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
    puts “Monotonic time: #{monotonic_time}”
    $$

    image-20240726123100792

    JavaScript

    $$
    console.log(“Current time: ”, Date.now())
    const monotonicTime = performance.now();
    // milliseconds since page load:
    console.log(Monotonic time ${monotonicTime});
    $$

    image-20240726122516502

    Go

    $$
    package main

    import (
    “fmt”
    “time”
    )

    func main() {
    fmt.Println(“Current time: ”, time.Now())

    // Get the current monotonic time
    monotonicTime := time.Now().UnixNano()
    // nanoseconds since epoch
    fmt.Printf("Monotonic time: %d\n", monotonicTime)

    }
    $$

    https://go.dev/play/p/aPgf5HBzSG6

    C

    $$
    #include <time.h>
    #include <stdio.h>

    int main() {
    struct timespec ts;
    clock_gettime(CLOCK_REALTIME, &ts);
    printf(“Current time: %ld.%ld\n”, ts.tv_sec, ts.tv_nsec);


    struct timespec mts;
    clock_gettime(CLOCK_MONOTONIC, &mts);
    printf("Monotonic time: %ld.%ld\n", mts.tv_sec, mts.tv_nsec);
    return 0;

    }
    $$

    image-20240726125536195

    View on Replit

    Conclusion

    This post shared the concept of time in computer system architectures and drilled down to discuss more on the different types of time available within an operating system and examples of how they can be retrieved from different programming languages.

    au revoir!

    Source: https://limistah.dev/posts/time-in-computer-systems/