Unix and Linux keep track of time in seconds before or after the epoch, which is defined as midnight, January 1, 1970 UTC.[1] Positive time values are after the epoch; negative time values are before the epoch. In order to provide processes with the current time, Linux, like all versions of Unix, provides a system call called time()
:
#include <time.h> time_t time(time_t *t);
time()
returns the number of seconds since the epoch, and if t
is non-null, it also fills in t
with the number of seconds since the epoch.
Some problems require higher resolution. Linux provides another system call, gettimeofday()
, which provides more information:
#include <sys/time.h> #include <unistd.h> int gettimeofday(struct timeval *tv, struct timezone *tz); struct timeval { int tv_sec; /* seconds */ int tv_usec; /* microseconds */ }; struct timezone { int tz_minuteswest; /* minutes west of Greenwich */ int tz_dsttime; /* type of dst correction */ };
On most platforms, including the i386 platform, Linux is able to provide very accurate time measurements. Industry-standard PCs have a hardware clock that provides microsecond-accurate time information. Alpha and SPARC hardware also provides a high-resolution timer. On some other platforms, however, Linux can keep track of time only within the resolution of the system timer, which is generally set to 100Hz, so the tv_usec
member of the timeval
structure may be less accurate on those systems.
Five macros are provided in sys/time.h for operating on timeval
structures:
timerclear(struct timeval *)
This clears a
timeval
structure.
timerisset(struct timeval *)
This checks to see if a timeval
structure has been filled in (that is, if either element is nonzero).
timercmp(struct timeval *t0, struct timeval *t1, operator)
This allows you to compare two timeval
structures in the time domain. It evaluates the logical equivalent of t0 operator t1
, if t0
and t1
were arithmetic types. Note that timercmp()
does not work for the <=
and >=
operators. Use !timercmp(t1, t2, >)
and !timercmp(t1, t2, <)
instead.
timeradd(struct timeval *t0, struct timeval *t1, struct timeval *result)
Adds
t0
tot1
and places the sum inresult
.
timersub(struct timeval *t0, struct timeval *t1, struct timeval *result)
Subtracts
t1
fromt0
and places the difference inresult
.A third representation of time,
struct tm
, puts the time in terms that are more human-oriented:
struct tm { { int tm_sec; int tm_min; int tm_hour; int tm_mday; int tm_mon; int tm_year; int tm_wday; int tm_yday; int tm_isdst; long int tm_gmtoff; const char *tm_zone; };
The first nine elements are standard; the final two are nonstandard but useful when they exist, as they do on Linux systems.
| The number of elapsed seconds in the minute. Will be between 0 and 61 (two extra seconds are allocated to deal with leap seconds). |
| The number of elapsed minutes in the hour. Will be between 0 and 59. |
| The number of elapsed hours in the day. Will be between 0 and 23. |
| The number of the day of the month. Will be between 1 and 31. This is the only member that will never be 0. |
| The number of elapsed months in the year. Will be between 0 and 11. |
| The number of elapsed years since 1900. |
| The number of elapsed days in the week (since Sunday). Will be between 0 and 6. |
The number of elapsed days in the year. Will be between 0 and 365. | |
| Whether some sort of daylight savings time is in effect in the expressed time value in the current time zone, if applicable. |
| This is not portable as it does not exist on all systems. If it exists, it may also be named |
| This is not portable as it does not exist on all systems. If it exists, it may also be named |
Finally, the POSIX.1b real-time processing standard allows even higher resolution than the microsecond resolution available in struct timeval
. struct timespec
uses nanoseconds instead and provides larger places to put the numbers:
struct timespec { long int tv_sec; /* seconds */ long int tv_nsec; /* nanoseconds */ };
Four functions are available for converting among times expressed in terms of time_t
and times expressed in terms of struct tm
. Three are standard and are available on all Linux and Unix systems. The fourth, although useful, is not universally available, although it is available on all current Linux systems. A fifth function, which is standard, calculates the difference in seconds between time_t
times. (Notice that even the time_t
arguments are passed as pointers, not just the struct tm
arguments.)
struct tm * gmtime(const time_t *t)
Short for Greenwich Mean Time,
gmtime()
converts atime_t
value into astruct tm
that expresses that time in UTC.
struct tm * localtime(const time_t *t)
localtime()
acts likegmtime()
except that it creates thestruct tm
expressed in terms of local time. Local time is defined for the whole system by the settings of the zoneinfo files, and that can be overridden by aTZ
environment variable by users who are working from a different time zone than the one the computer is in.
time_t mktime(struct tm *tp);
mktime()
converts astruct tm
to atime_t
, assuming that thestruct tm
is expressed in terms of local time.
time_t timegm(struct tm *tp);
timegm()
acts likemktime()
except that it assumes that thestruct tm
is expressed in terms of UTC. It is not a standard function.
double difftime(time_t time1, time_t time0);
difftime()
returns a floating-point number representing the difference in time in seconds between twotime_t
values. Althoughtime_t
is guaranteed to be an arithmetic type, the unit is not specified by ANSI/ISO C;difftime()
returns the difference in seconds, regardless of the units oftime_t
.
Four more functions are available to convert time between computer-friendly numbers and human-friendly textual representations. Again, the final one is not standard, despite its obvious general usefulness.
char *asctime(struct tm *tp); char *ctime(time_t *t);
asctime()
andctime()
both convert a time value into a standard Unix date string that looks something like this:Tue Jun 17 23:17:29 1997In both cases, the string is 26 characters long and includes a final newline character and the terminating
' '
.The length of the string may not be guaranteed to be 26 characters in all locales, as it is in the default C locale.
ctime()
expresses this date in local time.asctime()
expresses this date in whatever time zone thestruct tm
specifies; if it was created withgmtime()
, it is in UTC, but if it was created withlocaltime()
, it is in local time.
size_t strftime(char *s, size_t max, char *fmt, struct tm *tp);
strftime()
is likesprintf()
for time. It formats astruct tm
according to the formatfmt
and places the result in no more thanmax
bytes (including the terminating' '
) of the strings
.Like
sprintf(), strftime()
uses the%
character to introduce escape sequences into which data is substituted. All of the substituted strings are expressed in terms of the current locale. However, the escape sequences are completely different. In several cases, lowercase letters are used for abbreviations and uppercase letters are used for full names. Unlikesprintf()
, you do not have the option of using numbers in the middle of an escape sequence to limit the length of the substituted string;%
.6 A
is invalid. Likesprintf(), strftime()
returns the number of characters printed into thes
buffer. If it is equal tomax
, the buffer is not large enough for the current locale; allocate a larger buffer and try again.
strftime()
uses the same substitutions used by the date program. These definitions of the substitutions are for the default locale and are here to help you identify the type of information they provide; they may be somewhat different in other locales.
%a
The three-character abbreviation for the name of the weekday.
%A
The full name of the weekday.
%b
The three-character abbreviation for the name of the month.
%B
The full name of the month.
%c
The preferred local expression of the date and time, as returned by
ctime()
andasctime()
.The numeric day of the month, counting from zero.
%H
The hour of the day, in 24-hour time, counting from zero.
%I
The hour of the day, in 12-hour time, counting from zero.
%j
The day of the year, counting from one.
%m
The month of the year, counting from one.
%M
The minute of the hour, counting from zero.
%p
The correct string for the local equivalent of
AM
orPM
.
%S
The second of the minute, counting from zero.
%U
The numeric week of the year, where week one starts on the first Sunday of the year.
%W
The numeric week of the year, where week one starts on the first Monday of the year.
%w
The numeric day of the week, counting from zero.
%x
The preferred local expression of the date only, without the time.
%X
The preferred local expression of the time only, without the date.
%y
The two-digit representation of the year, without the century. (Do not use this—it is a potent source of year-2000 problems.)
%Y
The full four-digit numeric representation of the year.
%Z
The name or standard abbreviation of the time zone.
%%
The literal character
%
.
char *strptime(char *s, char *fmt, struct tm *tp);
Like
scanf(), strptime()
converts a string to a parsed format. It tries to be liberal in interpreting thes
input string according to thefmt
format string. It takes the same escape sequences thatstrftime()
takes, but for each type of input, it accepts both abbreviations and full names. It does not distinguish between upper and lower case, and it does not recognize%U
and%W
.
strptime()
also provides a few extra escape sequences and interprets a few sequences slightly differently than doesstrftime()
. Only the significantly different escape sequences (that is, beyond the changes already mentioned) are documented in this list. Numbers may have leading zeros, but they are not required.
%h
Equivalent to
%b
and%B
.
%c
Reads the date and time as printed by
strftime()
with the format string%x %X
.
%C
Reads the date and time as printed by
strftime()
with the format string%c
.
%e
Equivalent to
%d
.
%D
Reads the date as printed by
strftime()
with the format string%m/%d/%y
.
%k
Equivalent to
%H
.
%l
Equivalent to
%I
.
%r
Reads the time as printed by
strftime()
with the format string%I:%M:%S %p
.
%R
Reads the time as printed by
strftime()
with the format string%H:%M
.
%T
Reads the time as printed by
strftime()
with the format string%H:%M:%S
.
%y
Reads the year within the twentieth century. 1900 is added to the value, and only values of 0-99 are allowed.
Reads the full year. Use this instead of
%y
if you possibly can, to avoid year-2000 problems.
strptime()
returns a pointer to the character ins
one character beyond the final character that it reads while parsing.
The strptime()
function is, unfortunately, specified neither by ANSI/ISO nor POSIX, which limits its portability.
On 32-bit Linux systems, like most Unix systems, time_t
is a signed integer 32 bits long. This means that it will overflow Monday, January 18, 2038, at 10:14:07 PM. So Monday, January 18, 2038, 10:14:08 PM will be represented as Friday, December 13th, 3:45:52 PM, 1901. As you can see, Linux did not exhibit a year-2000 problem (as far as the native time libraries are concerned), but it does have a year-2038 problem.
On 64-bit platforms, time_t
is instead a 64-bit signed long. This is effectively forever; signed 64-bit time is truly astronomical, as it will not overflow until well after the sun is predicted to envelop the Earth as it becomes a red giant.
To find the beginning of time, the current time, and the end of time for the system you are using, you can build and run this program, daytime.c:
1: /* daytime.c */ 2: 3: #include <stdio.h> 4: #include <sys/time.h> 5: #include <unistd.h> 6: 7: int main() { 8: struct timeval tv; 9: struct timezone tz; 10: time_t now; 11: /* beginning_of_time is smallest time_t-sized value */ 12: time_t beginning_of_time = 1L<<(sizeof(time_t)*8 - 1); 13: /* end_of_time is largest time_t-sized value */ 14: time_t end_of_time = ~beginning_of_time; 15: 16: printf("time_t is %d bits long ", sizeof(time_t)*8); 17: 18: gettimeofday(&tv, &tz); 19: now = tv.tv_sec; 20: printf("Current time of day represented as a struct timeval: " 21: "tv.tv_sec = 0x%08x, tv.tv_usec = 0x%08x " 22: "tz.tz_minuteswest = 0x%08x, tz.tz_dsttime = 0x%08x ", 23: tv.tv_sec, tv.tv_usec, tz.tz_minuteswest, tz.tz_dsttime); 24: 25: printf("Demonstrating ctime()%s: ", 26: sizeof(time_t)*8 <= 32 ? "": 27: " (may hang after printing first line; press " 28: "control-C)"); 29: printf("time is now %s", ctime(&now)); 30: printf("time begins %s", ctime(&beginning_of_time)); 31: printf("time ends %s", ctime(&end_of_time)); 32: 33: exit (0); 34: }
Unfortunately, the ctime()
function is iterative by nature, which means that it (for all practical purposes) never terminates on 64-bit systems for astronomical dates like the 64-bit beginning and end of time. Use Control-C to terminate the program when you become tired of waiting for it to complete.
A timer is simply a way of scheduling an event to happen at some point in the future. Instead of looping around, looking at the current time, and wasting CPU cycles, a program can ask the kernel to notify it when at least a certain amount of time has passed.
There are two ways to use timers: synchronously and asynchronously. The only way to use a timer synchronously is to wait for the timer to expire—sleeping. Using a timer asynchronously, like every other asynchronous facility, involves signals. What may be surprising is that using a timer synchronously may also involve signals.
A process requesting that it not be scheduled for at least a certain amount of time is called sleeping. Four functions are available for sleeping; each measures time in different units. They also have slightly different behavior and interact with other parts of the system differently.
unsigned int sleep(unsigned int seconds);
sleep()
causes the current process to sleep at leastseconds
seconds or until a signal that the process does not ignore is received by the process. On most platforms,sleep()
is implemented in terms of theSIGALRM
signal, and therefore it does not mix well with using thealarm()
system call, creating aSIGALRM
handler, ignoring theSIGALRM
signal, or usingITIMER_REAL
interval timers (described later), which share the same timer and signal.If
sleep()
does not sleep for the full time allotted, it returns the number of seconds left to sleep. If it has slept at least as long as requested, it returns zero.
void usleep(unsigned long usec);
usleep()
causes the current process to sleep at leastusec
microseconds. No signals are used. On most platforms,usleep()
is implemented viaselect()
.
int select(0, NULL, NULL, NULL, struct timeval tv);
select()
, documented in Chapter 13, provides a portable way to sleep for a precise amount of time. Simply fill in thestruct timeval
with the minimum amount of time you wish to wait, and do not wait for any events to occur.
int nanosleep(struct timespec *req, struct timespec *rem);
nanosleep()
causes the current process to sleep at least the amount of time specified inreq
(see page 484 fortimespec
), unless a signal is received by the process. Ifnanosleep()
terminates early due to a received signal, it returns -1 and setserrno
toEINTR
and, ifrem
is notNULL
, setsrem
to represent the amount of time remaining in the sleep period.
nanosleep()
is currently the least portable of these functions, because it was specified as part of the POSIX.1b (previously called POSIX.4) real-time specification, which is not implemented on all versions of Unix. However, all new Unix implementations implement it, because the POSIX.1b functions are now a standard part of the Single Unix Specification.Not all platforms that provide the
nanosleep()
function provide high accuracy, but Linux, like other real-time operating systems, attempts to honor short waits with extreme accuracy for real-time processes. See Programming for the Real World [Gallmeister, 1995] for more information on real-time programming.
Interval timers, once enabled, continually deliver signals to a process on a regular basis. Exactly what regular means depends on which interval timer you use. Each process has three interval timers associated with it.
ITIMER_REAL
Tracks time in terms of the clock on the wall—real time, regardless of whether the process is executing—and delivers a
SIGALRM
signal. It conflicts with thealarm()
system call, which is used by thesleep()
function. Use neitheralarm()
norsleep()
if you have a real itimer active.
ITIMER_VIRTUAL
Counts time only when the process is executing—excluding any system calls the process makes—and delivers a
SIGVTALRM
signal.
ITIMER_PROF
Counts time when the process is executing—including the time the kernel spends executing system calls on the behalf of the process, but not including any time spent processing interrupts on behalf of the process—and delivers a
SIGPROF
signal. Accounting for time spent processing interrupts would be so expensive that it would change the timings.
The combination of ITIMER_VIRTUAL
and ITIMER_PROF
is often used for profiling code.
Each of these timers generates its associated signal within one system clock tick (normally 1-10 milliseconds) of the timer expiring. If the process is currently running when the signal is generated, it is delivered immediately; otherwise, it is delivered soon afterward, depending on system load. Since ITIMER_VIRTUAL
is tracked only when the process is running, it is always delivered immediately.
Use a struct itimerval
to query and set itimers:
struct itimerval { struct timeval it_interval; struct timeval it_value; };
The it_value
member is the amount of time left until the next signal is sent. The it_interval
member is the amount of time between signals; it_value
is set to this value each time the timer goes off.
There are two system calls for dealing with interval timers. Both take a which
argument that specifies which timer to manipulate.
int getitimer(int which, struct itimerval *val);
Fills in
val
with the current state of thewhich
timer.
int setitimer(int which, struct itimerval *new, struct itimerval *old);
Sets the
which
timer tonew
and fills inold
with the previous setting if it is non-NULL
.
Setting a timer’s it_value
to zero immediately disables it; the timer will no longer be called. Setting a timer’s it_interval
to zero disables it after the next time the timer triggers.
In the following example, a parent process starts a child process, runs a one-second ITIMER_REAL
timer, sleeps for 10 seconds, and then kills the child process:
1: /* itimer.c */ 2: 3: #include <stdio.h> 4: #include <stdlib.h> 5: #include <sys/wait.h> 6: #include <unistd.h> 7: #include <string.h> 8: #include <signal.h> 9: #include <sys/time.h> 10: 11: 12: void catch_signal (int ignored) { 13: static int iteration=0; 14: 15: printf("caught interval timer signal, iteration %d ", 16: iteration++); 17: } 18: 19: pid_t start_timer (int interval) { 20: pid_t child; 21: struct itimerval it; 22: struct sigaction sa; 23: 24: if (!(child = fork())) { 25: memset(&sa, 0, sizeof(sa)); 26: sa.sa_handler = catch_signal; 27: sigemptyset(&sa.sa_mask); 28: sa.sa_flags = SA_RESTART; 29: 30: sigaction(SIGALRM, &sa, NULL); 31: 32: memset(&it, 0, sizeof(it)); 33: it.it_interval.tv_sec = interval; 34: it.it_value.tv_sec = interval; 35: setitimer(ITIMER_REAL, &it, NULL); 36: 37: while (1) pause(); 38: } 39: 40: return child; 41: } 42: 43: void stop_timer (pid_t child) { 44: kill (child, SIGTERM); 45: } 46: 47: int main (int argc, const char **argv) { 48: pid_t timer = 0; 49: 50: printf("Demonstrating itimers for 10 seconds, " 51: "please wait... "); 52: timer = start_timer(1); 53: sleep(10); 54: stop_timer(timer); 55: printf("Done. "); 56: 57: return 0; 58: }
[1] UTC: Universal Coordinated Time, also sometimes improperly referred to as UCT; roughly equivalent to Greenwich Mean Time (GMT) and Zulu. Time zone designations involve technical detail far beyond the scope of this book.
3.16.68.121