D.3.1 64-bit time symbol handling in the GNU C Library

With respect to time handling, GNU C Library configurations fall in two classes depending on the value of __TIMESIZE:

__TIMESIZE == 32

These dual-time configurations have both 32-bit and 64-bit time support. 32-bit time support provides type time_t and cannot handle dates beyond Y2038. 64-bit time support provides type __time64_t and can handle dates beyond Y2038.

In these configurations, time-related types have two declarations, a 64-bit one, and a 32-bit one; and time-related functions generally have two definitions: a 64-bit one, and a 32-bit one which is a wrapper around the former. Therefore, for every time_t-related symbol, there is a corresponding __time64_t-related symbol, the name of which is usually the 32-bit symbol’s name with __ (a double underscore) prepended and 64 appended. For instance, the 64-bit-time counterpart of clock_gettime is __clock_gettime64.

__TIMESIZE == 64

These single-time configurations only have a 64-bit time_t and related functions, which can handle dates beyond 2038-01-19 03:14:07 (aka Y2038).

In these configurations, time-related types only have a 64-bit declaration; and time-related functions only have one 64-bit definition. However, for every time_t-related symbol, there is a corresponding __time64_t-related macro, the name of which is derived as in the dual-time configuration case, and which expands to the symbol’s name. For instance, the macro __clock_gettime64 expands to clock_gettime.

These macros are purely internal to the GNU C Library and exist only so that a single definition of the 64-bit time functions can be used on both single-time and dual-time configurations, and so that glibc code can freely call the 64-bit functions internally in all configurations.

Note: at this point, 64-bit time support in dual-time configurations is work-in-progress, so for these configurations, the public API only makes the 32-bit time support available. In a later change, the public API will allow user code to choose the time size for a given compilation unit.

64-bit variants of time-related types or functions are defined for all configurations and use 64-bit-time symbol names (for dual-time configurations) or macros (for single-time configurations).

32-bit variants of time-related types or functions are defined only for dual-time configurations.

Here is an example with localtime:

Function localtime is declared in time/time.h as

extern struct tm *localtime (const time_t *__timer) __THROW;
libc_hidden_proto (localtime)

For single-time configurations, __localtime64 is a macro which evaluates to localtime; for dual-time configurations, __localtime64 is a function similar to localtime except it uses Y2038-proof types:

#if __TIMESIZE == 64
# define __localtime64 localtime
#else
extern struct tm *__localtime64 (const __time64_t *__timer) __THROW;
libc_hidden_proto (__localtime64)
#endif

(note: type time_t is replaced with __time64_t because time_t is not Y2038-proof, but struct tm is not replaced because it is already Y2038-proof.)

The 64-bit-time implementation of localtime is written as follows and is compiled for both dual-time and single-time configuration classes.

struct tm *
__localtime64 (const __time64_t *t)
{
  return __tz_convert (*t, 1, &_tmbuf);
}
libc_hidden_def (__localtime64)

The 32-bit-time implementation is a wrapper and is only compiled for dual-time configurations:

#if __TIMESIZE != 64

struct tm *
localtime (const time_t *t)
{
  __time64_t t64 = *t;
  return __localtime64 (&t64);
}
libc_hidden_def (localtime)

#endif