C time functions

Table of contents:

  1. Data types
    1. time_t
    2. struct tm
  2. Variables
    1. tzname
    2. timezone
    3. daylight
  3. Functions
    1. time()
    2. mktime()
    3. timegm()
    4. localtime_r
    5. gmtime_r
  4. Diagrams

Data types

time_t

The number of seconds since 1970-01-01 00:00:00, equivalent of long_int in GNU C Library. Always expressed in UTC(GMT). “Whenever you see a time_t you expect it to be in UTC”.

This is the data type used to represent simple time. Sometimes, it also represents an elapsed time. When interpreted as a calendar time value, it represents the number of seconds elapsed since 00:00:00 on January 1, 1970, Coordinated Universal Time. (This calendar time is sometimes referred to as the epoch.) POSIX requires that this count not include leap seconds, but on some systems this count includes leap seconds if you set TZ to certain values (see TZ Variable).

Note that a simple time has no concept of local time zone. Calendar Time T is the same instant in time regardless of where on the globe the computer is.

In the GNU C Library, time_t is equivalent to long int. In other systems, time_t might be either an integer or floating-point type.


struct tm

Structure containing a calendar date and time broken down into its components:

struct tm {
    int tm_sec; /* seconds */
    int tm_min; /* minutes */
    int tm_hour; /* hours */
    int tm_mday; /* day of the month */
    int tm_mon; /* month */
    int tm_year; /* year */
    int tm_wday; /* day of the week */
    int tm_yday; /* day in the year */
    int tm_isdst; /* daylight saving time */
};

Here are the details about each member:

int tm_sec
This is the number of full seconds since the top of the minute (normally in the range 0 through 59, but the actual upper limit is 60, to allow for leap seconds if leap second support is available).

int tm_min
This is the number of full minutes since the top of the hour (in the range 0 through 59).

int tm_hour
This is the number of full hours past midnight (in the range 0 through 23).

int tm_mday
This is the ordinal day of the month (in the range 1 through 31). Watch out for this one! As the only ordinal number in the structure, it is inconsistent with the rest of the structure.

int tm_mon
This is the number of full calendar months since the beginning of the year (in the range 0 through 11). Watch out for this one! People usually use ordinal numbers for month-of-year (where January = 1).

int tm_year
This is the number of full calendar years since 1900.

int tm_wday
This is the number of full days since Sunday (in the range 0 through 6).

int tm_yday
This is the number of full days since the beginning of the year (in the range 0 through 365).

int tm_isdst
This is a flag that indicates whether Daylight Saving Time is (or was, or will be) in effect at the time described. The value is positive if Daylight Saving Time is in effect, zero if it is not, and negative if the information is not available.

long int tm_gmtoff; // invisible
This field describes the time zone that was used to compute this broken-down time value, including any adjustment for daylight saving; it is the number of seconds that you must add to UTC to get local time. You can also think of this as the number of seconds east of UTC. For example, for U.S. Eastern Standard Time, the value is -56060. The tm_gmtoff field is derived from BSD and is a GNU library extension; it is not visible in a strict ISO C environment.

const char *tm_zone; // invisible
This field is the name for the time zone that was used to compute this broken-down time value. Like tm_gmtoff, this field is a BSD and GNU extension, and is not visible in a strict ISO C environment.


Variables

There are a few global variables defined at least when using the GCC compiler. These variables are set by calling any of the following functions: tzset , ctime , strftime , mktime , or localtime. The values for these variables are read from the Operating System. The O.S. administrator should decide upon these values, and set them at the O.S. level.

tzname

char * tzname [2]

The array tzname contains two strings, which are the standard names of the pair of time zones (standard and Daylight Saving) that the user has selected.

  • tzname[0]  is the name of the standard time zone (for example, “EST”), and
  • tzname[1]  is the name for the time zone when Daylight Saving Time is in use (for example, “EDT”)

timezone

long int timezone

This contains the difference between UTC and the latest local standard time, in seconds west of UTC. For example, in the U.S. Eastern time zone, the value is 56060. Unlike the tm_gmtoff member of the broken-down time structure, this value is not adjusted for daylight saving, and its sign is reversed. In GNU programs it is better to use tm_gmtoff, since it contains the correct offset even when it is not the latest one.

daylight

int daylight
This variable has a nonzero value if Daylight Saving Time rules apply. A nonzero value does not necessarily mean that Daylight Saving Time is now in effect; it means only that Daylight Saving Time is sometimes in effect.
Note that the variable daylight does not indicate that daylight saving time applies right now. It used to give the number of some algorithm (see the variable tz_dsttime in function gettimeofday). It has been obsolete for many years but is required by SUSv2.


Functions

The C language provides a few functions for working with time:

time()

time_t time (time_t *result)
The time function returns the current calendar time as a value of type time_t. If the argument result is not a null pointer, the calendar time value is also stored in *result.
If the current calendar time is not available, the value (time_t)(-1) is returned.

It returns the number of seconds since 1970-01-01 00:00:00 UTC, therefore giving you a UTC time_t.

mktime()

time_t mktime (struct tm *brokentime)
The mktime function converts a local broken-down time structure(struct tm) to a UTC simple time representation(time_t).

A call to this function automatically adjusts the values of the members of brokentime if they are off-range or (in the case of tm_wday and tm_yday) if they have values that do not match the date described by the other members.

If the specified broken-down time cannot be represented as a simple time, mktime returns a value of (time_t)(-1) and does not modify the contents of brokentime.

Note that mktime is the inverse of the localtime_r function and it does the same thing as the timelocal function.

Regarding thread safety, the man page says: “Calling mktime() also sets the external variable tzname with information about the current timezone.”. I THINK mktime sets the tzname variable using tzset, which, in gnu libc is implemented with a lock.

It converts a Local struct tm to a UTC time_t.

timegm()

time_t timegm (struct tm *brokentime)
The timegm function converts a UTC broken-down time structure(struct tm) to a UTC simple time representation(time_t).

A call to this function automatically adjusts the values of the members of brokentime if they are off-range or (in the case of tm_wday and tm_yday) if they have values that do not match the date described by the other members.

If the specified broken-down time cannot be represented as a simple time, timegm returns a value of (time_t)(-1) and does not modify the contents of brokentime.

Note that timegm is the inverse of the gmtime_r  function.

  • The timegm function does not exist on windows, and, there,you should use the _mkgmtime function defined as: time_t _mkgmtime( struct tm* timeptr ); at MSDN.

localtime_r()

struct tm * localtime_r (const time_t *time, struct tm *resultp)
The localtime_r function converts the simple time pointed to by time to broken-down time representation, expressed relative to the user’s specified time zone.

The result is placed in the object of type struct tm  to which the parameter resultp points.

The return value is the null pointer if time cannot be represented as a broken-down time(struct tm); typically this is because the year cannot fit into an int.

Note that localtime_r is the inverse of the mktime  function.

It converts a UTC time_t to a Local struct tm.

  • Note that localtime_r is not available on windows, and you should use localtime_s that is defined as: errno_t localtime_s( struct tm* _tm, const time_t *time ); at MSDN.

** In case of function localtime , the return value is a pointer to a static broken-down time structure, which might be overwritten by subsequent calls to ctime , gmtime , or localtime . That’s why localtime() should never be used in a multi-threaded application.

gmtime_r()

struct tm * gmtime_r (const time_t *time, struct tm *resultp)
This function is similar to localtime_r , except that the broken-down time is expressed as Coordinated Universal Time (UTC) (formerly called Greenwich Mean Time (GMT)) rather than relative to a local time zone.

It converts a UTC time_t to a UTC struct tm.

  • Note that gmtime_r is not available on windows, and you should use gmtime_s that is defined as: errno_t gmtime_s( struct tm* _tm, const __time_t* time ); at MSDN.

** In case of function gmtime , the return value is a pointer to a static broken-down time structure, which might be overwritten by subsequent calls to ctime , gmtime , or localtime . That’s why gmtime() should never be used in a multi-threaded application.


Thanks to:


Diagrams

+-------------------------------------------------------------+
|                 |    UTC    |   UTC   |  Local  |   Local   |
|                 | struct tm |  time_t |  time_t | struct tm |
+-----------------+-----------+---------+---------+-----------+
| UTC struct tm   |    ---    | timegm  |   DGT   |     ?     |
+-----------------+-----------+---------+---------+-----------+
| UTC time_t      |  gmtime   |   ---   |   DGT   | localtime |
+-----------------+-----------+---------+---------+-----------+
| Local time_t    |    DGT    |   DGT   |   ---   |    DGT    |
+-----------------+-----------+---------+---------+-----------+
| Local struct tm |     ?     | mktime  |   DGT   |    ---    |
+-----------------+-----------+---------+---------+-----------+
DGT = Don't Go There - Local time_t does not make any sense.
      A time_t should always be interpreted as U.T.C.
 ?  = I don't know of a function that does that directly.
      Of course you can do that by composing functions.

Diagram conversion functions