UNIX Time Format Demystified

UNIX format timestamps have an extensive range of use. You will find out the main reasons that back up this claim, but for now, let’s say that it is because working with dates and times in the UNIX time format is easier and more resource efficient. In this article, our goal is to demystify the concept, learn the theory that lies behind it, and ultimately write algorithms and implementations that convert dates back and forth from the traditional ISO standard to UNIX format.

UNIX time, which is sometimes referred to as POSIX time, is a relatively “simple” format that represents time using its very own system. I’ve opted for the quotations around simple because, despite how it’s going to look at first glance, by the time you finish reading this article, I am sure that you’re going to find them quite simple and effective.

(Image Courtesy of Cubus)

Let me give you some examples of dates in UNIX time if for whatever reason you haven’t been able to come across any until now. Check out the example below:

962452800 -> 2000-07-01T12:00:00+00:00 -> Sat, 01 Jul 2000 12:00:00 +0000

1215129600 -> 2008-07-04T00:00:00+00:00 -> Fri, 04 Jul 2008 00:00:00 +0000

1577909730 -> 2020-01-01T20:15:30+00:00 -> Wed, 01 Jan 2020 20:15:30 +0000

In the above example, the first column is the time specified in UNIX time format, the second is in the widely popular ISO 8601 standard, and the latter is in RFC 2822 format, which is also called Internet Message Format. For a detailed guide and information regarding the RFC 2822, I’d suggest checking out this document. It is the official abstract related to the standard and its outlines.

Now that you’ve seen some examples of UNIX time, those strings of digits must seem a bit odd, right? It’s weird when somebody suggests that they represent valid dates and times. On the next page, we’re going to explain the theory and the mathematics behind it.

{mospagebreak title=The Theory}

In short, the UNIX time format stands for the count of seconds elapsed since midnight UTC (Coordinated Universal Time) of January 1, 1970, without considering leap seconds. I won’t go into the details and point out the definitions of UTC and GMT because the difference between the two of them never exceeds 0.9 seconds, and it would be beyond the scope of this article. So, basically, we can say it’s the GMT, too.

Just as its name suggests, it’s related to UNIX. The UNIX epoch is the time 00:00:00 UTC on January 1st, 1970. In the ISO 8601 standard format, this epoch can be considered 1970-01-01T00:00:00Z. Basically, it is a reference point from which this measurement unit (UNIX time) starts. Therefore, the zero UNIX time is exactly at the reference point—the one we mentioned earlier.

The UNIX time format is not a linear representation of time because it does not count in leap seconds; therefore, it does not correspond to the UTC. There are workarounds to count in leap seconds as well, but that’s not what we care about right now. What’s important to us is that any date and time can be transcoded into UNIX format.

This is critical because we can get away with just a simple scalar real number. From a programmer’s point of view then, let’s call these a sequence of bits (digits). I mentioned earlier that one of the main advantages of UNIX time format is that it makes working with dates and times very easy. The reason why is simple.

Consider the following scenario where you need to move forward and increase a date variable three (3) months. The situation can get tricky when the starting initial timestamp looks like “2008-07-04T00:00:00” (I’ve stripped the +00:00 from the end; it’s in UTC/GMT locale). You need to consider that July has 31 days, as does August, but September has only 30. And then you need to find which section stands for the month, year, and days. Different locales have different habits.

Isn’t it easier when you have the sequence “1215129600” and adding three months can be narrowed down to adding 90 days to the initial date/time variable? We know that UTC days are 86400 seconds long. That means in order to move forward 90 days, we need to add the initial sequence of digits with 90 * 86400. The result is the following: “1222905600” — voila! No hassle at all.

As you can see, working with UNIX time formats isn’t a black art—ultimately, it can be turned into simple mathematics. Explain this to a kid that goes to the elementary school and s/he might be fascinated by it.

Now let’s see a step-by-step calculation where we count in leap years. We start out with the following date: Mon, 31 Mar 2008 21:15:30. At first, we need to calculate the offset from the year 1970 (UNIX epoch). 2008 – 1970 = 38 . Every 4 years, a leap year occurs. 38 / 4 = 9.5 (but we’ll consider this a 9 because the decimals can be ignored).

The calculation continues and now we need to convert those 38 years to a number of days: 38 * 365 = 13870. We also add the approximated amount of 9 days due to leap years and that gives us 13879 days. Moving on, we need to calculate the offset from January 1, 31 + 29 (February has 29 days this year) + 31 = 91 days. Right after, we add these 91 days to our original expression: 13879 + 91 = 13970 days.

As stated earlier, each day has 86,400 seconds. Let’s multiply this amount with our count of days: 13970 * 86400 = 1207008000. All that’s left is adding the time. 09 PM is hour 21 – thus, the offset is from 21hours since midnight. Each hour is 3600 seconds. 21 * 3600 = 75600. Then we also have 15 minutes and 30 seconds. A minute is 60 seconds, so we end up with 15 * 60 + 30 = 930 seconds. 75600 + 930 = 76530.

And finally, we need to add our sequence of digits with the aforementioned number of seconds. That’s how we’ll end up with the final result: 1207008000 + 76530 = 1207084530. Class dismissed. End of math for today—programming is next!

{mospagebreak title=Conversion Examples}

First, let’s start with a C# sample code. We’re going to use its built-in DateTime function and its .AddSeconds method. The algorithm is simple: we ask the user to type in a UNIX time, then we parse to double, and right after, we create a new date that starts from 1970, 1, 1 (January 1) and we add the specified number of seconds to it. Ultimately, we can print this out, since it’s in the preformatted DateTime format.

Console.Write("Enter the source UNIX time: ");

double unixTime = double.Parse(Console.ReadLine());

DateTime convTime = new DateTime(1970, 1, 1).AddSeconds(unixTime);

Console.WriteLine("The converted time is: " + convTime);

And check out its output:

Enter the source UNIX time: 1206959497

The converted time is: 3/31/2008 10:31:37 AM

Press any key to continue . . .

Now let’s write the other way around. Here we work with the current time. We use the DateTime’s .Now property to extract the current time. Then we create a new double, which is going to represent the time in UNIX format. We can calculate its value if we somehow find out the offset between today’s date and 1970, 1, 1. We can do this with subtraction. Right after, we use the .TotalSeconds to build up the double.

DateTime currentTime = DateTime.Now;

Console.WriteLine("The current time now is: " + currentTime);

double currentUnixTime = (currentTime –

new DateTime(1970, 1, 1)).TotalSeconds;

Console.WriteLine("The current UNIX time now: " +

Math.Round(currentUnixTime,0));

Of course, here’s the output. Right at the time of writing this article, that is…

The current time now is: 3/31/2008 2:06:03 PM

The current UNIX time now: 1206972364

Press any key to continue . . .

Since working with UNIX timestamps is almost always necessary when working in UNIX or *NIX operating systems, I bookmarked this blog post (entry) right away when I found it. And I strongly suggest you do the same. It covers a few solutions for doing conversions in bash—perl and awk (scripting and programming languages).

Check out the following code snippets. The EPOCH variable is the source Unix time.

!#/bin/bash

EPOCH=1000000000

DATE=$(perl -e "require ‘ctime.pl’; print &ctime($EPOCH); ")

echo $DATE

DATE=$(perl -e "print scalar(localtime($EPOCH)) ")

echo $DATE

DATE=$(echo $EPOCH|awk ‘{print strftime(”%c”,$1)}’)

echo $DATE

DATE=$(awk “BEGIN { print strftime(”%c”,$EPOCH) }”)

echo $DATE

You could also use the following command under UNIX operating systems:

date -d "dategoeshere" +%s

As you can see from the example above, the syntax of Perl’s localtime is the following:

perl -e "print scalar localtime()"

Server-side programmers are familiar with situations where MySQL requires the timestamp in the Y-m-d H:i:s format. And almost all of the techniques that “grab” the current time and date are returned in UNIX time format. The solution is conversion. And we can do this in PHP. Check out the attached code snippet below, where we’ve created two functions—conversion back and forth.

<?php

function unixToMySQL($unixtime)

{

return date(‘Y-m-d H:i:s’, $timestamp);

}

… rest of the code goes here …

function convertToUnix($plaintime)

{

$plaintime = explode("/",$plaintime);

return mktime(0,0,0,$plaintime[1],$plaintime[2],plaintime[0]);

}

… rest of the code goes here …

?>

The algorithm is pretty straightforward. The date function does what we need when we want to convert from UNIX time format to any other“traditional” format. We just need to specify the requested format, such as Y-m-d H:i:s in this case. But this becomes more interesting when the situation is reversed and we need to split the string parameter into three parts (with the explode function at each slash “/”).

We use the mktime() function to make the time giving the necessary parameters. Please note that we’ve opted for 0, 0, and 0 as the first three parameters. This means that we’ve created a UNIX time at 00:00:00. We are purely focusing on splitting the date string and its conversion. Then we specify those parameters in terms of month, day, and year.

The following PHP solution is shorter, but does not behave reliably with DD/MM/YY:

# behaves erroneously with DD/MM/(YY)YY timestamps

strtotime($date);

Furthermore, I have also found this blog post where you can read about an ORACLE command that grabs the system time (SYSDATE) and converts it to a somewhat standard format (DD-MMM-YYYY). It’s based on the multiplication of 86400, but first we just calculate the offset from 01-JAN-1970.

SELECT (sysdate – to_date(’01-JAN-1970′,’DD-MON-YYYY’)) * (86400) AS dt FROM dual;

Let me add the following MySQL example, too. Check out their syntax!

mysql> SELECT UNIX_TIMESTAMP(’2008-03-31 16:34:14′);

1206977654

UNIX_TIMESTAMP() —> Return a UNIX timestamp

 

FROM_UNIXTIME() —> Format date as a UNIX timestamp

{mospagebreak title=Final Thoughts}

We’ve come to the end of this article. On these pages, I’ve shown you how to work with UNIX timestamps. Most importantly, we’ve demystified this concept. Those long strings of digits are all around us and some people haven’t a clue how the heck they can represent a date when they seem silly and sometimes even random.

It’s really important to understand the mathematical theory that lies within UNIX timestamps, because if we have a strong grasp on it, we can do the conversions ourselves—even by hand on a sheet of paper with a pen. Of course, we can also write our own convert functions in any programming language.

(Image Courtesy of Softpedia)

After we learned the UNIX timestamps, we moved on to some practical real-world examples. Basically, you found lots of conversion implementations in various programming languages (even shell scripting). I explained the code samples and we also examined the syntax of the functions we opted to use.

Should you have more questions or uncertainties, don’t hesitate to join the Dev Hardware Forums. It’s an ever-growing place with a very friendly and professional community made up of lots of technology experts and enthusiasts. Our focus lies mostly on hardware, software, and consumer electronics.

You may want to also check out the communities of our sister sites, such as the Dev Shed Forums and ASP Free Forums.

I hope that you’ve found this article informative and educational. Hopefully, you won’t be scared away the next time you notice a long string of digits representing a date, and you won’t think that the “coder” who is mumbling about dates is insane. On top of this, you learned how to convert plain English-like dates (along with times) back and forth to UNIX time.

Google+ Comments

Google+ Comments