Leap seconds in Linux

What are leap seconds

You can read more than you’ll ever want to know on the web, but I recommend the Unix Leap Second Mess as a good introduction. It’s quite long and complicated though so if you want to get on with your day I’ll try to summarise it.

There are four time standards in common use which came as some surprise to me:

  • TAI (International Atomic Time)
  • UT1 (mean solar day)
  • UTC (somewhere between TAI and UT1).
  • Posix (something else)

UT1 is what you think is the time when you use your high-precision sun dial. When you compare it to your atomic clock, you find that the solar day is usually slightly longer than 86400 seconds, and what’s worse, it varies from day today. If you’ve had your sundial and atomic clock a few thousand years you’ll have noticed that the mean solar day is getting longer on average. (A second is an SI unit and it never varies so we don’t need to worry about solar seconds and atomic seconds.)

UTC is a compromise between TAI and UT1. A UTC day exactly 86399, 86400 or 86401 seconds. The short and long days will only ever fall at the end of December or June (or possibly March or September but that hasn’t been used yet). We will always have at least three months’ notice of a leap second but they are essentially unpredictable because the earth wobbles. The last leap second was at the end of June 2012 and the next one is at the end of June 2015. So far we haven’t had any short days, but it’s possible.

Posix specifies seconds since the epoch as a value that approximates the number of seconds since the Epoch. Since this is a little circular and vague it specifies it exactly as a value obtained from a UTC time and date:

tm_sec + tm_min*60 + tm_hour*3600 + tm_yday*86400 + (tm_year-70)*31536000 + ((tm_year-69)/4)*86400 - ((tm_year-1)/100)*86400 + ((tm_year+299)/400)*86400

This takes into account leap years, but not leap seconds. A Posix day is exactly 86400 seconds but things like localtime(3) convert from seconds since the epoch to a UTC time. The problem of what to do with leap seconds is handled by the system adding or deleting a second from the day. So at the end of June 2015, you’ll get 1435708799 twice: once normal and once as a leap second.

Impact of Leap Seconds

Everyone knows that there are 60 seconds in a minute, 60 minutes in an hour, and 24 hours in a day. Programmers since the dawn of time (1970) have added and subtracted from a value counting seconds assuming just that. This assumption is deeply ingrained and the Posix definition of seconds since the epoch simply codifies that.

If you include leap seconds in the seconds since the epoch value then time would be accurate but programs that expect to be able to do arithmetic with time will break. For something like cron(8) whose maximum resolution is one minute, being a second out is not important. For some applications, though, an accurate timestamp or knowing exactly when midnight is can be quite important. Especially when it’s midnight UTC at the beginning of July which is lunchtime in New Zealand.

Fortunately, there’s something you can do about this if you have an application that cares that much.

How does Linux handle leap seconds?

Linux uses NTP to keep accurate time and ntpd cooperates with the kernel to ensure that time is accurate before, during, and after a leap second. (If a leap second is being deleted, rather than inserted, then “during” is no time at all.) The process takes quite a long time from beginning to end. It starts with an upstream NTP server that knows about leap seconds. At the start of the UTC day it sets a “leap indicator” which will be passed on to its downstream servers over the course of the next 15 minutes or so (ntp servers in steady state typically check upstream every 1024 seconds). A stratum 4 ntp server may get the leap indicator over an hour after the start of the day.

When a Linux ntpd gets the leap indicator it uses adjtimex(2) to tell the kernel that a leap second is going to be inserted (or deleted) at midnight UTC. The NTP daemon is not responsible for actually handling the leap second, it defers that to the kernel. If you call adjtimex(2) during the day leading up to the leap second, it will return TIME_INS. The ntptime is a convenient way of doing this.

At 10ns before midnight (depending on the precision of the timer) the kernel is about to advance the time to 00:00:00 and at this point it checks the leap status. If the status is TIME_INS then the kernel subtracts one from the seconds counter. Crucially, the time status returned by adjtimex(2) is now set to TIME_OOP to indicate that a leap second is in progress. When the clock gets to 10ns before midnight for a second time, the time status is set to TIME_OK and, in recent kernels, a TAI Offset incremented.

Time now runs normally until the next leap second!