Linux time and date functions – A must read for developers

By | 11/10/2012

In this pacing world, time plays an important role in every aspect of Life. Even in industries like embedded, automotive etc time plays a very important role. Seems like everyone is working just to minimize this parameter called time. If we talk about software industry, here too, minimising the time complexity is the most prominent objective driving thick and thin. Moreover, Benchmarking software and programs are taken much seriously these days in research as well as in industry. However, talking in terms of software running on an OS, what is time and how do we measure it? Here in this article we shall be learning about various Linux time and date functions.

Linux time and date functions

The Clocks

To measure time, every machine has clocks and timers. At a system level, there are various ways to keep track of time. In the machine, one basic clock is just like our real world clock, which keeps ticking and tells the machine the current time. This clock runs on a battery and even keeps running when our system is turned off. However, when the system boots up, it initialises other Linux clocks which now have their separate axis of reference, though still ticking with the frequency of the underlying hardware.

There is another clock in Linux, which just keep ticking to let you know how many ticks have occurred since the system has booted up. Howsoever, unless and until our program is to show/work on the current local time, the developers mostly work on the time intervals i.e. how much time elapsed by a particular function or a sleep for a particular interval of time, etc.

From a developer’s point of view, there are various functions available for fetching timing information from Linux system. It might sometimes get confusing as to why we have so many methods, structs and how do they differ with each other. Lets understand each function one by one.

1. The time(), ctime() and asctime() functions

The time() function is used to fetch the local time in seconds.

Here is more on this function from the man page :

NAME
time – get time in seconds

SYNOPSIS
#include <time.h>
time_t time(time_t *t);

DESCRIPTION
time() returns the time as the number of seconds since the Epoch, 1970-01-01 00:00:00
+0000 (UTC). If t is non-NULL, the return value is also stored in the memory pointed to
by t.

RETURN VALUE
On success, the value of time in seconds since the Epoch is returned. On error,
((time_t) -1) is returned, and errno is set appropriately.

This function accepts a pointer to ‘time_t’ as an argument, through which it returns the time along with a return value. hence, it works fine even passing a NULL, where it will just return the time value. Note, ‘time_t’ internally is of ‘long int’ type.

So how does this ‘long int’ value stores time? Well, it just stores the number of seconds passed since a reference point which is taken as January 1, 1970 (termed as Epoch).

There are some methods and C structures offered by Linux to convert these number of seconds to compute the date/time in human readable form. Here is a summary of these functions from respective man pages :

#include <time.h>
char *asctime(const struct tm *tm);
char *ctime(const time_t *timep);

To know more on how these methods and structures work and their variations, please refer the man page.

So, now lets see how these methods work and how to use them.

Here is an example :

#include <stdio.h>
#include <time.h>

int main()
{
    time_t currTime;
    struct tm *localTime;
    currTime = time(NULL);

    printf("For Linux, curr time is %ld\n", currTime);
    printf("For humans, curr time is %s\n", ctime(&currTime));

    localTime = localtime (&currTime);
    printf("For Linux, Local time = %d:%d:%d  %d:%d:%d\n", localTime->tm_hour, localTime->tm_min, localTime->tm_sec, localTime->tm_mon, localTime->tm_mday, localTime->tm_year);

    printf("For Humans, Local time is %s\n", asctime(localTime));
    return 0;
}

Here is the output:

For Linux, curr time is 1349805572
For humans, curr time is Tue Oct  9 13:59:32 2012

For Linux, Local time = 13:59:32  9:9:112
For Humans, Local time is Tue Oct  9 13:59:32 2012

This method can also be used to determine the time elapsed by a program in seconds. It uses the system clock or sometimes which is termed as the kernel clock. However, keep in mind, the precision would be in seconds.

2. The gettimeofday() function

Here is an excerpt of the details from it’s man page :

NAME
gettimeofday – get / set time

SYNOPSIS
#include <sys/time.h>
int gettimeofday(struct timeval *tv, struct timezone *tz);

Comparatively, this one gives time with a precision better than the above mentioned method. This uses the system clock for the time computation. All the time values are updated in ‘timeval’ struct and supposedly ‘timezone’ struct as well. However, struct ‘timezone’ is obsolete now and is rarely used. The return value is success/failure.

Lets see a simple implementation using ‘gettimeofday’

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

int main()
{
    struct timeval localTime;
    gettimeofday(&localTime, NULL); //Time zone struct is obsolete, hence NULL

    printf("The curr time in seconds %ld\n", localTime.tv_sec);
    printf("The curr time in microseconds %ld\n", localTime.tv_usec);

    return 0;
}

Here is the output:

The curr time in seconds 1349810620
The curr time in microseconds 708991

This method can be used to determine the time interval with the precision of micro-seconds. To know more about this method, you can go through it’s man page.

3. The clock_gettime() function

Here are some details about this function from man page :

#include <time.h>
int clock_gettime(clockid_t clk_id, struct timespec *tp);

The tp argument is a timespec structure, as specified in <time.h>:

struct timespec {
time_t   tv_sec;        /* seconds */
long     tv_nsec;       /* nanoseconds */
};

This method gives time with precision on nanoseconds. This method uses a different struct for time values, “struct timespec” which its members as secs and nanosecs. This method also offers for the developer to use various available clocks to determine time. How these available clocks vary is, how they run. Like, the system clock just sends an interrupt at every tick, and increments the time. There are some clocks, which measure the time for a process, some for a thread which is very useful to determine precise time taken by a control flow.

These different clocks are specified by the parameter of the method,

clockid_t clk_id

Here is a list of all available clocks generally in Linux as of today.

  • CLOCK_REALTIME : As the name says, it is the real time clock, which matches the system wide time. Hence, this needs special privileges to set. Interestingly, this clock can be adjusted by the Network Time Protocol (NTP) to be in sync with the external sources.
  • CLOCK_MONOTONIC :This one keep on running at its pace, and cannot be set or modified.
  • CLOCK_MONOTONIC_RAW : This one is similar to CLOCK_MONOTONIC, however it gives the hardware based time.
  • CLOCK_PROCESS_CPUTIME_ID : This one is a clock specific to a process with times as per the process. They use CPU timers and different than the above mentioned clocks.
  • CLOCK_THREAD_CPUTIME_ID : This one is a clock specific to a thread with times as per the thread. It is similar to CLOCK_PROCESS_CPUTIME_ID and use CPU timers.

Prior to we start playing with this method, important to note that, this method is provided by an external library.

librt.so

Hence, we need to link our code using ‘clock_gettime’ with this library. It is part of the gcc libs and hence available. Therefore, you would not need to install it explicitly.

Here is an example of this function

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

#define MAX 500000

int main()
{
    int array[MAX];
    int i;

    struct timespec starttime, endtime, ttime;
    double timeinterval;

    //initialise whole array with 0
    memset ((int*)array, 0, (MAX * sizeof(int)));

    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &starttime);
    for (i = 0; i < MAX; i++)
    array[i] = i;

    sleep(1);

    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &endtime);
    ttime.tv_sec = endtime.tv_sec - starttime.tv_sec;
    ttime.tv_nsec = endtime.tv_nsec - starttime.tv_nsec;
    timeinterval = ttime.tv_sec * 1000000000 + ttime.tv_nsec;

    printf("Time in milliseconds %lf ms \n", (double) timeinterval/1000000);
    printf("Time in nanoseconds %lf ns \n", (double) timeinterval);

    return 0;
}

Here is how the code is compiled :

$ gcc mytime.c -Wall -o mytime -lrt

Here is the output :

Time in milliseconds 2.163321 ms
Time in nanoseconds 2163321.000000 ns

4. The clock() function

Here is some information from the man page :

NAME
       clock - Determine processor time

SYNOPSIS
       #include <time.h>
       clock_t clock(void);

DESCRIPTION
       The clock() function returns an approximation of processor time used by the program.

RETURN VALUE
       The  value  returned is the CPU time used so far as a clock_t; to get the number of seconds used, divide by CLOCKS_PER_SEC.
       If the processor time used is  not  available  or  its  value  cannot  be  represented,  the  function  returns  the  value
       (clock_t) -1.

The way it can be used is to note the start time, by calling this function before the code block starts. Then determine by end time after the code block and compute the time elapsed.

Here is a pseudo code :

startClock = clock();

//........control flow

stopClock = clock();

However, it does not give accurate discuss and not even to much precision.

Here is a working example :

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

#define MAX 500000

int main()
{
int array[MAX];
int i;

clock_t startClock, stopClock;
startClock = clock();
for (i = 0; i < MAX; i++)
array[i] = i;
sleep(5);

stopClock = clock();
printf("The CPU Time = %lf\n", (double)((stopClock - startClock)/(double)CLOCKS_PER_SEC));

return 0;
}

Here is the output :

The CPU Time = 0.040000

 

Conclusion

In this article we learned about various time and date functions in Linux through working examples. You will also be able to have a good judgement where to use which method as per one’s requirement. However, there are still certain things which may affect the accuracy of times in certain conditions like SMP machines, context switches etc.

For many circumstances, profilers could be a better option to use instead of time functions. Basically, it all depends on your precision requirements, machine specifications and software requirements.

3 thoughts on “Linux time and date functions – A must read for developers

  1. Vinay N

    Hi Rupali,

    Is there a way to initialize the timeval structure to current time without using the gettimeofday() function? Like, using mktime() or just time(NULL) ?

    Reply
  2. Akanksha

    I am migrating a code from UNIX to linux in pro c that needs to get age of a file.
    code is something like
    #include
    #include
    #include
    #include
    #include
    #include
    #include

    int vflag = 0; /* Verbose Flag */
    int sflag = 0; /* Format Seconds Flag */
    int mflag = 0; /* Format Minute Flag */
    int hflag = 0; /* Format Hours Flag */
    int dflag = 0; /* Format Days Flag */

    struct stat filestat;

    int handle_option(int argc, char *argv[]);
    void display_option(void);
    time_t get_date_time(void);
    time_t get_file_time(char *file);

    int main(int argc, char *argv[])
    {
    char file[100];
    time_t filetime, datetime;
    int i;

    I am getting error
    getfileage.c:163: error: expected â=â, â,â, â;â, âasmâ or â__attribute__â before âget_date_timeâ
    getfileage.c:164: error: expected â=â, â,â, â;â, âasmâ or â__attribute__â before âget_file_timeâ
    getfileage.c: In function âmainâ:
    getfileage.c:169: error: âtime_tâ undeclared (first use in this function)
    getfileage.c:169: error: (Each undeclared identifier is reported only once
    getfileage.c:169: error: for each function it appears in.)
    getfileage.c:169: error: expected â;â before âfiletimeâ
    getfileage.c:180: warning: incompatible implicit declaration of built-in function âstrcpyâ
    getfileage.c:182: error: âdatetimeâ undeclared (first use in this function)
    getfileage.c:184: error: âfiletimeâ undeclared (first use in this function)
    getfileage.c:186: warning: incompatible implicit declaration of built-in function âfprintfâ
    getfileage.c:186: error: âstderrâ undeclared (first use in this function)
    getfileage.c:190: warning: incompatible implicit declaration of built-in function âprintfâ
    getfileage.c: In function âhandle_optionâ:
    getfileage.c:224: error: âvflagâ undeclared (first use in this function)
    getfileage.c: In function âdisplay_optionâ:
    getfileage.c:249: warning: incompatible implicit declaration of built-in function âprintfâ
    getfileage.c:260: warning: incompatible implicit declaration of built-in function âexitâ
    getfileage.c: At top level:
    getfileage.c:263: error: expected â=â, â,â, â;â, âasmâ or â__attribute__â before âget_date_timeâ
    getfileage.c:276: error: expected â=â, â,â, â;â, âasmâ or â__attribute__â before âget_file_timeâ
    make[2]: *** [getfileage.o] Error

    Can someone help

    Reply
  3. Saba

    Hello

    I am a new programmer in LINUX. I want to grab incoming packets after every 3 seconds intervals. Will you help me obtaining this.
    My current logic is like this:

    m using

    sec = time(NULL);
    t = sec- sec_ref;

    {

    — code–

    }

    sec_ref = sec;
    t=0;

    But the time tick value is not correct in this way, I always get time “t” value 0 pr 1 or in rare cases 2 , 3 or 4..but It must be incrementing with every second.

    Please help me and reply on the given email ID

    Regards

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *