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
.
When __TIMESIZE
is set to 64, the GNU C Library will also define
the__USE_TIME_BITS64
macro. It is used by the Linux kernel ABI
to set the expected time_t
size used on some syscalls.
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