Calendar Time Under Linux

  • Post author:
  • Post last modified:August 23, 2023
  • Reading time:9 mins read

1.0 The system calendar time since the Epoch, 1970-01-01 00:00:00, UTC

The Linux kernel maintains a system calendar time, which is initialized from the hardware real time clock (RTC) at the boot time and is incremented with the timer interrupt. The system calendar time is the number of seconds passed since January 1, 1970 00:00:00 UTC. Or, to put it differently, the system calendar time is the number of seconds since the year 1969. January 1, 1970 00:00:00 UTC is the Epoch for keeping time in Linux.

2.0 date command

The system calendar time can be read or set using the date command,

$ date 
Sun Oct 16 19:48:10 IST 2011 
$ sudo date 101621012011.34   
Sun Oct 16 21:01:34 IST 2011

time system call

Programs can find the system calendar time using the time system call. For example,

....
#include <time.h> 
time_t ts; 
if ((ts = time (NULL)) == -1) 
    perror ("time"); 
....

After that, the variable, ts, contains the system calendar time at the instant the time system call was made.

3.0 Local time

3.1 Time Zone

The Coordinated Universal Time (UTC) is the reference time at the Prime Meridian at 0° longitude and is not adjusted for daylight saving time. As we travel east or west along a parallel of latitude, there are different local times at any given instant of time. Since the Earth rotates 360° in 24 hours, the difference in local time of two places on meridians differing by a degree in longitude should be 4 minutes. However, the parts of the globe are divided in time zones and all places in a time zone have the same local time for all commercial, legal and social purposes. Some time zones follow Daylight Saving Time (DST), wherein, the clock is advanced by an hour in the summer so as to make the evening longer by an hour and make better use of the daylight. Some time zones have followed DST at some time such as during an energy crisis but do not follow it now.

A user's time zone is kept in the environment variable TZ. The function tzset initializes the global variable tzname from TZ. If TZ is not set, the system timezone is used. The system time zone is set by copying or linking a file in
tzfile(5) format to /etc/localtime. tzset function also sets the timezone and daylight global variables. tzset function is automatically called by time conversion functions that depend upon the time zone.

#include <stdio.h>
#include <time.h>
int main (int argc, char **argv)
{
     extern char *tzname[2];
     extern long timezone;
     extern int daylight;

     tzset ();

     printf ("daylight = %d, timezone = %ld seconds tzname = %s/%s\n",
               daylight, timezone, tzname [0], tzname [1]);
}

We can compile and run the above program.

$ gcc tzinfo.c -o tzinfo
$ ./tzinfo
daylight = 1, timezone = -19800 seconds tzname = IST/+0630

A value of 1 for daylight indicates that either the timezone observes Daylight Saving Time at present or it did observe DST sometime in the past. The value of timezone is the difference between the UTC and the time zone local time. tzname is an array of two strings. The tzname [0] string should be used to refer to the time zone when DST is not being observed and tzname [1] should be used when DST is being observed.

3.2 Converting system calendar time to local time

There are multiple functions to convert the system calendar time to a readable local time string giving the day of the month, month, year, hours, minutes, seconds, day of the week and the local timezone. There is the struct tm in the include file, time.h,

struct tm
{
  int tm_sec;                   /* Seconds.     [0-60] (1 leap second) */
  int tm_min;                   /* Minutes.     [0-59] */
  int tm_hour;                  /* Hours.       [0-23] */
  int tm_mday;                  /* Day.         [1-31] */
  int tm_mon;                   /* Month.       [0-11] */
  int tm_year;                  /* Year - 1900.  */
  int tm_wday;                  /* Day of week. [0-6] */
  int tm_yday;                  /* Days in year.[0-365] */
  int tm_isdst;                 /* DST.         [-1/0/1]*/

# ifdef __USE_MISC
  long int tm_gmtoff;           /* Seconds east of UTC.  */
  const char *tm_zone;          /* Timezone abbreviation.  */
# else
  long int __tm_gmtoff;         /* Seconds east of UTC.  */
  const char *__tm_zone;        /* Timezone abbreviation.  */
# endif
};

One way of printing the local time is to use the above structure, tm,

 .... 
 struct tm *tms;  
 time_t ts;

 if ((ts = time (NULL)) == -1)  
     perror ("time");                

 if ((tms = localtime (&ts)) == NULL)  
     perror ("localtime");                    

 printf ("Time is %d/%02d/%d %d:%02d:%02d %s\n", tms -> tm_mday,   
     tms -> tm_mon + 1, tms -> tm_year + 1900, tms -> tm_hour,      
     tms -> tm_min, tms -> tm_sec, tms -> tm_zone); 
 ....

The above program segment prints a string like,

Time is 17/10/2011 16:21:19 IST

There is a function ctime, which converts the system clock time stamp into a local time string.

    .... 
    time_t ts;  
    if ((ts = time (NULL)) == -1)   
        perror ("time");   
    printf ("%s", ctime (&ts));  
    ....

This prints a string like,

Mon Dec 10 07:43:59 2018

3.3 Converting local time to system calendar time

The function mktime converts local time in struct tm to system calendar time.

#include <time.h>

time_t mktime (struct tm *tm);

mktime ignores the values specified in the tm_wday and tm_yday fields of struct tm. If tm_isdst field is positive, mktime applies the DST. If tm_isdst is zero, DST is not applied. If tm_isdst is negative, mktime has to figure out on its own using timezone information and system databases whether DST is to be used for the given time. Calling mktime sets the global variable tzname with the details of the current time zone. mktime returns the system calendar time or -1 in case of error. The following example finds the system calendar time for a given local time.

// findts: find system calendar time for given local time

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

int main (int argc, char **argv)
{
    // find system time for January 1, 2019, 16:45:00 IST
    struct tm tm;

    tm.tm_sec = 0;
    tm.tm_min = 45;
    tm.tm_hour = 16;
    tm.tm_mday = 1;
    tm.tm_mon = 0; // for January
    tm.tm_year = 2019 - 1900;
    tm.tm_isdst = -1;

    time_t ts;

    if ((ts = mktime (&tm)) == (time_t) -1)
        perror ("mktime");

    struct tm *tms;
    if ((tms = localtime (&ts)) == NULL)
        perror ("localtime");

    printf ("Time is %02d/%02d/%d %02d:%02d:%02d %s (%ld)\n", tms -> tm_mday,
        tms -> tm_mon + 1, tms -> tm_year + 1900, tms -> tm_hour,
        tms -> tm_min, tms -> tm_sec, tms -> tm_zone, tms -> tm_gmtoff);
}

We can compile and run the above program.

$ gcc findts.c -o findts
$ ./findts
Time is 01/01/2019 16:45:00 IST (19800)

4.0 gettimeofday system call

The above examples give calendar time to the resolution of a second. However, it is possible to get the system time with microsecond resolution with the gettimeofday system call. There is a structure, timeval,

struct timeval { 
    time_t      tv_sec;   /* seconds */   
    suseconds_t tv_usec;  /* microseconds */  
};

which has seconds and microseconds as members. We get the system calendar time in terms of seconds and microseconds since the Epoch with the gettimeofday system call. The syntax of the call is,

#include <sys/time.h> 

int gettimeofday (struct timeval *tv, NULL);

For example, we can get time since Epoch using gettimeofday and convert it into local time using localtime,

....
#include <time.h> 
#include <sys/time.h> 
....
    struct timeval tval;   
    struct tm *tms;

    if (gettimeofday (&tval, NULL) == -1)   
        perror ("gettimeofday");    

    printf ("%ld %ld\n", tval.tv_sec, tval.tv_usec);  

    if ((tms = localtime (&tval.tv_sec)) == NULL)  
        perror ("localtime"); 

    printf ("Time is %d/%02d/%d %d:%02d:%02d.%03ld.%03ld %s\n",   
             tms -> tm_mday, tms -> tm_mon + 1, tms -> tm_year + 1900,    
             tms -> tm_hour, tms -> tm_min, tms -> tm_sec, tval.tv_usec / 1000,    
             tval.tv_usec % 1000, tms -> tm_zone);
....

The above code prints an output like,

Time is 17/10/2011 23:31:24.080.623 IST

6.0 See also

  1. Linux process execution time
  2. Alarm, sleep and High Resolution Timers
  3. hwclock, the hardware clock query and set program
  4. Synchronize your computer’s clock using the NTP
Share

Karunesh Johri

Software developer, working with C and Linux.
0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments