Some notes on different ways of measuring time

Morten Hauke Solvang

I’m by no means an expert on the topic of time.

But from time to time, the topic comes up for some project, and I have to do some learning, to make sure that the code I write has at least a chance of being correct.

This page just contains my rough notes on the topic.

One page I like for finding further information is leapsecond.com.

Epochs

t=0 is defined as
Unix January 1st 1970, 00:00:00
GPS January 6th 1980, 00:00:00

For the other time types, t=0 is not well defined.

When writing code, this means that int64_t unix_time_sec or int64_t gps_time_sec are (fairly) unambiguous. On the other hand, if we want to store TAI/UTC/UT1 time as a seconds counter, we’d have to clarify relative to what the counter is, e.g. int64_t tai_seconds_since_unix_epoch.

Properties of common time types

UT1 UTC Unix TAI GPS
One second is a fixed length
One day is a fixed number of seconds
The epoch (t=0) is well defined

One second is a fixed length

This glosses over a lot of details about how the length of a second is measured.

UTC, TAI, GPS and unix time all share the same second: Seconds are the same length, and clocks tick from one second to the next at the same time.

UT1 works completely differently: It is based on the rotation of the earth, so as the rotation of the earth slows down or speeds up, the length of a UT1 second changes.

Unix time does something funky. If a positive leap second is inserted, the unix second at midnight is the same length as two UTC/TAI/GPS seconds. The second goes on for two seconds! Similarly, if a negative leap second is inserted (though this has never happened so far), there will be a unix second with a duration of zero.

The reason unix time does this is to a) stay in agreement with UTC about date / time of day, and b) make it easy to convert from unix-seconds-since-unix-epoch to days/hours/minutes/seconds.

On day is a fixed number of seconds

A normal day is 86400 seconds.

Having a day always be 86400 makes math easy: If you have a timestamp represented as seconds-since-known-date, you can divide by 86400 to get days-since-known-date. From there, all you need is a calendar to figure out what date your timestamp is.

The only case where this isn’t always true is UTC. When a leap second happens, a UTC day is 1 second longer for a total of 86401 seconds. (Or 1 second shorter, but a negative leap second has never happened so far).

To convert from UTC-seconds-since-known-date to days/hours/minutes-since-known-date, you need a leap second table. And a way of updating your leap second table, in case new leapseconds get announced.

About leap seconds

In UTC, leap seconds are inserted to keep the time aligned with the UT1, i.e. with the rotation of earth. In unix time, the length of a second is instead changed to stay aligned with UT1 / UTC.

TAI and GPS don’t stay aligned with the rotation of the earth.

Offsets

The offset between time types answers the question: “When clock X shows midnight, how many seconds before/after midnight is clock Y”.

By talking about midnight, we get rid of any questions about what epoch we are using. We just take readings from our clocks, and if necessary convert them to date+time format, and then we compare them. (We don’t have to look specifically at midnight, I just find it easier to think about that way.)

When UTC shows midnight, TAI shows 00:00:37.
When UTC shows midnight, GPS shows 00:00:18.
When GPS shows midnight, TAI shows 00:00:19.

NB This is correct as of 2025. If new leap seconds get added, the offsets will change.

Unix time isn’t in the table. Unix and UTC always are in sync, except in the second where a leap second is inserted.