1. Data types

1.1. 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.

1.2. struct tm

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

struct tm {
  /**
   * seconds.
   * 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_sec;

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

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

  /**
   * day of the month
   * 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_mday;

  /**
   * month
   * 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_mon;

  /**
   * year
   * This is the number of full calendar years since 1900.
   */
  int tm_year;

  /**
   * day of the week
   * This is the number of full days since Sunday (in the range 0 through 6).
   */
  int tm_wday;

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

  /**
   * daylight saving time
   * 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.
   */
  int tm_isdst;

private:
  /**
   * 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.
   */
  long int tm_gmtoff;

  /**
   * 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.
   */
  const char *tm_zone;
};

2. 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.

/**
 * 2.1. tzname
 * 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")
 */
char * tzname [2];

/**
 * 2.2. 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.
 */
long int timezone;

/**
 * 2.3. 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 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.
 */
int daylight;

3. Functions

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

/**
 * 3.1. time()
 * 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.
 */
time_t time (time_t *result);

/**
 * 3.2. mktime()
 * 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 Note that mktime is the inverse of the localtime_r function and it does
 * the same thing as the timelocal function.
 * @warning 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.
 * This function converts a Local struct tm to a UTC time_t.
 */
time_t mktime (struct tm *brokentime);

/**
 * 3.3. timegm()
 * 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 Note that timegm is the inverse of the gmtime_r function.
 * @note 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: https://msdn.microsoft.com/en-us/library/2093ets1.aspx
 */
time_t timegm (struct tm *brokentime);

/**
 * 3.4. localtime_r()
 * 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 Note that localtime_r is the inverse of the mktime function.
 * This function converts a UTC time_t to a Local struct tm.
 * @note 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: https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/localtime-s-localtime32-s-localtime64-s?redirectedfrom=MSDN&view=vs-2019
 * @note 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.
 */
struct tm * localtime_r (const time_t *time, struct tm *resultp);

/**
 * 3.5. gmtime_r()
 * 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.
 * This function converts a UTC time_t to a UTC struct tm.
 * @note 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: https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/gmtime-s-gmtime32-s-gmtime64-s?redirectedfrom=MSDN&view=vs-2019
 * @note 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.
 */
struct tm * gmtime_r (const time_t *time, struct tm *resultp);

Thanks to:

  1. https://www.gnu.org/software/libc/manual/html_node/Simple-Calendar-Time.html
  2. https://www.gnu.org/software/libc/manual/html_node/Broken_002ddown-Time.html
  3. https://www.gnu.org/software/libc/manual/html_node/Time-Zone-Functions.html

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