Quick Links

Unix stores time as the number of seconds since Jan. 1, 1970. And that means Linux does too. We explain this seemingly odd system, and why doomsday was scheduled for 2038.

The First Unix Epoch

Goethe (1749-1832) declared "Every second is of infinite value." That's true, we each only have so many seconds here on planet Earth, and we don't know when our last second will be. But we do know our birthday, and when our mortal countdown started.

Unix---like the British Queen---has two birthdays. Or, more accurately, there have been two separate occasions on which it started counting the seconds of its existence. The first time Unix started counting from was midnight Jan 1, 1971.

Related: What Is Unix, and Why Does It Matter?

We can see this quite clearly by reviewing a section of the first edition of the Unix Programmer's Manual, dated November 3, 1971. Scroll down to page 13 of that section, and you'll see a description of the (now defunct)

        time
    

command. We're told that "

        time
    

returns the time since 00:00:00, Jan. 1, 1971, measured in sixtieths of a second."

Calendars and time systems measure time starting at some significant point in the past, such as a cosmological event, the founding of an empire, or the success of a revolution. In operating systems, an arbitrary time and date are chosen as the point from which the counting starts. This is the epoch for that operating system.

Unix used a 32-bit unsigned integer to hold the count of 60ths of a second since the epoch. This is a numeric variable capable of holding values in the range of 0 to 4,294,967,295 (232−1). That sounds like a lot. But the counter incremented at 60 times a second and, as the Programmer's Manual points out, "The chronological---minded user will note that 2**32 sixtieths of a second is only about 2.5 years."

With a rate of consumption of 60 numbers per second, the counter would have hit its maximum value on April 8, 1973, a little less than 829 days later.

The Second Unix Epoch

Needless to say, this was acted upon rapidly. The unsigned integer was replaced with a 32-bit signed integer. It might seem a surprising choice because a signed integer is able to hold a smaller number of positive values---2,147,483,647 (231)---than an unsigned integer. However, the speed of consumption was also reduced from 60ths of a second to whole seconds.

It takes longer to count from 0 to 2,147,483,647 counting one number per second than it does to count from 0 to 4,294,967,295 at 60 counts per second. And by quite a margin. The new scheme wouldn't hit its maximum value for just over 68 years. This seemed so far in the future that the epoch was even reset to an earlier point in time. The new epoch was set to midnight on Jan. 1, 1970, UTC.

That point 68 years in the future is now unnervingly close. To be precise, we'll reach it at 03:14:07 UTC on Jan. 19, 2038.

A Simple But Effective Scheme

Using a single integer to count the number of time steps from a given point in time is an efficient way to store time. You don't need to store complicated structures of years, months, days, and times. and it is country, locale, and time zone independent.

Multiplying the number in the integer by the size of the time step---in this case, one second---gives you the time since the epoch, and converting from that to locale-specific formats with time-zone adjustments is relatively trivial.

It does give you a built-in upper limit though. Sooner or later you're going to hit the maximum value you can hold in your chosen variable type. At the time of writing this article, the year 2038 is only 17 years away.

It's similar but slightly different to the problem with early computer systems from the last century using two digits to store years. When the calendar rolled over into the new year and new century of 2000, would a year value stored as "00" be interpreted as 2000, or 1900?

Related: What Was the Y2K Bug, and Why Did It Terrify the World?

Correcting the so-called "Millenium Bug" is estimated to have cost the U.S. alone over $100 billion, and to have taken thousands of man-years to address globally. There were some issues in the first few days of Jan. 2000, but nothing like the disasters that would have taken place if the bug had been ignored.

Doomsday Is Postponed

Because Linux and all Unix-lookalike operating systems share the same issue, the year 2038 issue has been taken seriously for some time, with fixes being added to the kernel since 2014. This is ongoing with fixes being added to the kernel as recently as Jan. 2020 to address the 32-bit integer problem.

Of course, a working Linux computer contains a lot more than a kernel. All of the operating utilities and userland applications that make use of system time through the various APIs and interfaces need to be modified to expect 64-bit values. File systems too must be updated to accept 64-bit timestamps for files and directories.

Related: Did Linux Kill Commercial Unix?

Linux is everywhere. A catastrophic failure in Linux would mean failures in all sorts of computer-based systems. Linux runs most of the web, most of the public cloud, and even spacecraft. It runs smart homes and self-driving cars. Smartphones have a Unix-derived kernel at their heart. Practically anything---like network firewalls, routers, and broadband modems---that has embedded operating systems inside run on Linux.

It's great that Linux is well on its way to being fixed. We'll install the upgrades and that'll be that. But what are the chances that all of those devices will be patched and updated? A lot of them won't even be in service by then so it will be a moot point, but some will still be plugging away. Tucked away in dark and dusty recesses in server rooms and rack cabinets perhaps, but they'll be there, working quietly, while the seconds tick by until about a quarter past three in the morning of Jan. 19, 2038.

But devices like that should be a tiny minority. The vast majority of systems will see the crunch time come and go without incident. Once again, we'll be able to relax. At least, until the year 2486 approaches, bringing with it the exact same problem for systems that use 64-bit based integers to count the time since the epoch.

The date Command

We can use the date command to verify Linux and other Unix derivatives still use the original, simple scheme of storing the time value as the number of seconds since the epoch.

Using the date command without any parameters prints the current date and time to the terminal window. You're also shown the time zone that the time is adjusted for. EDT is Eastern Daylight Time, which means our test computer is in the Eastern Time Zone, and daylight saving is in effect. When daylight saving time isn't in effect, the Eastern Time Zone uses Eastern Standard Time.

To see the underlying integer value, we can use a display format string. Format strings have a plus sign "+" as their first character. The "%s" format token means "show the seconds since the epoch."

If we take the seconds value returned by date and feed it back into the date command with the

        -d
    

(display time described by a string) option, it'll convert it back to a regular date and time.

date

date +%s

date -d @1633183955

Using date to show the seconds since the Unix epoch

We can show that the integer value really represents the time by displaying the number of seconds, sleeping for 10 seconds, and showing the new number of seconds. The two integer values will be different by exactly 10.

date +%s && sleep 10 && date +%s

Showing two seconds values 10 seconds apart

We've seen that we can pass a number of seconds to the date command and it converts to a time and date for us. If we do just that using zero seconds as input our value, date ought to print the date and time of the Unix epoch.

TZ='UTC' date -d @0 +'%x %R'

Displaying the Unix epoch from an input value of 0 seconds

The command breaks down like this:

  • TZ='UTC': The epoch was set using Coordinated Universal Time (UTC, so we need to tell date to use UTC. The "TZ=" construct sets the effective time zone for the current command only.
  • date: The date command.
  • -d @0: We tell date to use a string as input, not the time "right now." The string we pass in holds zero seconds.
  • +'%x %R': The output format string. The "%x" format token tells date to display the year, month, and day. The "%R" format token instructs date to use the 24-hour format for the hours and minutes. Because there are spaces in the format string, we wrap the entire string in single quotes " ' " so that it the string treated as a single item.

As expected, the output is midnight on Jan. 1, 1970.

Related: How to Display the Date and Time in the Linux Terminal (and Use It In Bash Scripts)

Until Next Time

Simple is often best. Counting seconds from a fixed datum is the simplest way to mark the passage of time. But the passage of time brings new challenges. With the fixes that have been put in place, it looks like we're clear through to the year 2486.

I think it's safe to say we'll worry about that a little closer to the time.