Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unix time, but with leap seconds

Unix time is useful for measuring time, whereas other formats are more useful for telling the time. This is because, apart from when time synchronization occurs, it just ticks forward one second at a time. For example, it doesn't change when there is an artificial hour change for daylight savings time.

However, there does seem to be one exception. It ignores leap seconds, meaning when there is a leap second, it basically jumps back a second. Here is the explanation on Wikipedia:

It is the number of seconds that have elapsed since the Unix epoch, minus leap seconds

I'm wondering is there a similar format to Unix time that also includes leap seconds and has no special cases at all? In other words, one that simply measures the number of SI seconds that have passed since an arbitrary reference point.

Here is an example of a leap second jump in Unix time from Wikipedia:

Enter image description here

In particular, I am interested in a time that doesn't have skips or doubles. Perhaps I am misunderstanding the above table, but it appears that a single Unix time instant can represent two different physical instants?

Can this be clarified in detail, with precise terminology like "instant" instead of "time", so that there isn't any ambiguity?

like image 879
David Callanan Avatar asked Oct 28 '25 07:10

David Callanan


1 Answers

In particular I am interested in a time that doesn't have skips or doubles.

What about CLOCK_MONOTONIC or CLOCK_MONOTONIC_RAW?

They give you the most direct access to your system's clock that I know of. The value represents the amount of "what your system thinks is a second" since boot.

I'm wondering is there a similar format to Unix time that also includes leap seconds and has no special cases at all? In other words, one that simply measures the number of SI seconds that have passed since an arbitrary reference point.

That reference point would be the time your system has booted for the MONOTONIC times.

If you want to persist across reboots, I'd use TAI as a format, as @awwright suggested in the comments. You can also pass it to clock_gettime(), like the other two options, but it changes when CLOCK_REALTIME changes. Maybe you also want to look into linuxptp and how to synchronize your device time to a GPS signal here or here, to get a very precise clock.

Some practical stuff

To put my musings into perspective: for audio clocks it's a big no-no when your clock shifts or jumps (unexpectedly) by a few ms, that's why we're using CLOCK_MONOTONIC_RAW on the device, and PTP in case multiple devices need to be in sync.

Here's some example code to check how the clocks behave on your system:

#include <stdlib.h>
#include <stdio.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>

void print_times() {
    struct timespec ts_tai;
    struct timespec ts_mono;
    struct timespec ts_raw;
    struct timespec ts_real;

    // Clocks ordered by "rawness"
    clock_gettime(CLOCK_REALTIME, &ts_real);
    clock_gettime(CLOCK_TAI, &ts_tai);
    clock_gettime(CLOCK_MONOTONIC, &ts_mono);
    clock_gettime(CLOCK_MONOTONIC_RAW, &ts_raw);
    printf("CLOCK_REALTIME : %010ld.%03ld\n", (long)ts_real.tv_sec, ts_real.tv_nsec);
    printf("CLOCK_TAI      : %010ld.%03ld\n", (long)ts_tai.tv_sec, ts_tai.tv_nsec);
    printf("CLOCK_MONOTONIC: %010ld.%03ld\n", (long)ts_mono.tv_sec, ts_mono.tv_nsec);
    printf("CLOCK_MONOT_RAW: %010ld.%03ld\n", (long)ts_raw.tv_sec, ts_raw.tv_nsec);
    printf("Diff(REAL, RAW): %ld\n\n", (long)ts_real.tv_sec - (long)ts_raw.tv_sec);
}

int main() {
    struct timeval delta, olddelta;

    print_times();
    system("date -s '5 seconds'");
    printf("\n");
    print_times();

    // Slowly adjusts the time. Takes minutes at least. Same way NTP works
    delta.tv_sec = 60;
    delta.tv_usec = 0;
    if (adjtime(&delta, &olddelta) != 0) {
        perror("Failed to adjtime");
        return 1;
    }
    printf("wait for adjtime\n");
    for (int i = 0; i < 5000; i++) {
        print_times();
        sleep(10);
    }
    return 0;
}

Here's example output on my desktop. CLOCK_TAI changes with UTC in my case. CLOCK_MONOTONIC_RAW is unaffected by setting the time and shouldn't be affected by NTP as well.

mo@ubuntu:~/tmp$ sudo ./a.out 
CLOCK_REALTIME : 1740603028.854429141
CLOCK_TAI      : 1740603028.854429247
CLOCK_MONOTONIC: 0000025902.191573356
CLOCK_MONOT_RAW: 0000025899.944398869
Diff(REAL, RAW): 1740577129

Wed Feb 26 08:50:33 PM UTC 2025

CLOCK_REALTIME : 1740603033.857140674
CLOCK_TAI      : 1740603033.857140756
CLOCK_MONOTONIC: 0000025902.194447183
CLOCK_MONOT_RAW: 0000025899.947271188
Diff(REAL, RAW): 1740577134

wait for adjtime
CLOCK_REALTIME : 1740603033.857162899
CLOCK_TAI      : 1740603033.857162951
CLOCK_MONOTONIC: 0000025902.194469338
CLOCK_MONOT_RAW: 0000025899.947293294
Diff(REAL, RAW): 1740577134
like image 102
Mo_ Avatar answered Oct 30 '25 11:10

Mo_



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!