The tv_sec
holds the whole number of seconds since the Unix Epoch — 1970-01-01 00:00:00 +00:00 — and the tv_usec
(or tv_nsec
when working with the more modern struct timespec
) holds the fractional part — values [0..999,999] microseconds for struct timeval
and [0..999,999,999] nanoseconds for struct timespec
.
In the days before 64-bit integers were widespread, time_t
was a 32-bit signed type, and that 'runs out' in January 2038 — there will have been more 2 billion seconds since the epoch. There was no room to store sub-second units in a single integer.
-2147483647 = 1901-12-13 20:45:53 +00:00
+2147483647 = 2038-01-19 03:14:07 +00:00
Even now, if dealing with nanoseconds, you need 30 bits to represent up to 999,999,999 nanoseconds (and 20 bits to represent up to 999,999 microseconds). The requirements for nanoseconds means that it is not sensible to try scaling a 64-bit number to represent seconds and nanoseconds — the Y2K38 problem would be deferred by something like 280 years, whereas the two-part solution puts it off until after the universe ends, which should be long enough for everyone. (I plan to start working on the Y10K problem on 5000-01-02, if I'm still around. )
So, although not ideal, the two part structure makes it easy to use the regular formatting functions that take a time_t
value — there are lots of them, and the ones that take a struct tm
derived from a time_t
value. And the arithmetic on them isn't hard.
I note that, in some respects, both struct timeval
and struct timespec
are under-specified by POSIX. What is the sign of the tv_usec
or tv_nsec
portion of a struct timeval
or struct timespec
if the tv_sec
component is negative (see Seconds Since the Epoch — If the year is <1970 or the value is negative, the relationship is undefined). POSIX leaves the behaviour of negative values of tv_sec
undefined, which is probably sensible, but does make life a bit difficult. Of course, there are also the issues of "when did which part of which country switch between the Julian and Gregorian calendars?" and "was there a year zero?" that would also have to be dealt with. When time_t
was a 32-bit number, it reached back as far as December 1901, which largely avoids the problems (but Russia didn't switch from Julian to Gregorian until after the October Revolution, which occurred in November in the Gregorian calendar). Now that time_t
is usually a 64-bit number, years BC (or BCE) also become representable.
Be careful when printing the tv_usec
or tv_nsec
part. Remember to add enough leading zeros by using %.6d
for microseconds, %.9ld
for nanoseconds, where the necessary conversion specifier (d
vs ld
vs …) for tv_usec
is not clearly defined in POSIX — but d
is usually correct. (The tv_nsec
member is a long
; that's easy and reliable.)