Noeud:Time Formats, Noeud « Next »:Formatted Printing, Noeud « Previous »:Signals, Noeud « Up »:Input and Output
Knowing the current time is important in many programs for various
reasons. On UNIX systems, the time
call gets the current
time in seconds from the operating system. The time is simply a long
integer that contains the number of seconds since an arbitrary
moment - midnight at the beginning of January 1, 19701 - referred to as the epoch.
time_t time (time_t *clock) | system function |
This function returns the number of seconds elapsed since the epoch, and
additionally stores the same number in the memory pointed to by clock
(unless clock is NULL ).
|
char *ctime (time_t *clock) | glibc function |
Returns a canonical 26-character string that displays the time
represented by the integer in clock - for example Tue Mar
19 19:39:46 2002 .
|
The time
and ctime
calls are precise enough for mundane
tasks like displaying the date and time to the user, but you have to
convert the time_t
into the more meaningful struct tm
format in order to measure elapsed time accurately:
struct tm { int tm_sec; /* measured from 0 to 60 (incase of leap second) */ int tm_min; /* measured from 0 to 59 */ int tm_hour; /* measured from 0 to 23 */ int tm_mday; /* day of the month, measured from 1 to 31 */ int tm_mon; /* month, measured from 0 to 12 */ int tm_year; /* year, where zero is 1900 */ int tm_wday; /* day of the week, measured from 0 to 6 */ int tm_yday; /* day of the year, measured from 0 to 365 */ int tm_isdst; /* 1 is daylight saving time, else 0 */ char* tm_zone; /* name of timezone */ long tm_gmtoff; /* timezone's distance from UTC in seconds */ };
Each element of the time that you'd be interested in is contained in a separate member of the structure. Watch those integers! They're not consistent. The day of the month is measured starting at 1, whereas the other integer values start at zero.
The calls listed below are used to convert from time_t
to
struct tm
types, and then turn them into human readable strings.
They all require you to include the file time.h
.
struct tm *gmtime (time_t *clock) | glibc function |
Breaks down the time reported by clock into a tm structure,
using the UTC (Greenwich Mean time) time zone. The returned
structure points to static memory which is overwritten by subsequent
calls, making this function unsafe in a multi-threaded program.
|
struct tm *gmtime_r (time_t *clock, struct tm *brokentime) | glibc function |
Much the same as gmtime , except that the broken down time is
stored in the memory pointed to by brokentime, to avoid problems
with multi-threaded programs. This function conforms to the POSIX
standard, and is thus supported by most modern platforms.
|
struct tm *localtime (time_t *clock) | glibc function |
Much the same as gmtime , except the conversion is performed for
the local time zone.
|
struct tm *localtime_r (time_t *clock, struct tm *brokentime) | glibc function |
Again, in accordance with POSIX, as localtime , except that
the broken down time is stored in the memory pointed to by
brokentime.
|
Universal Coordinated Time or UTC [sic] used to be known as
Greenwich Mean Time. It's the worldwide standard for reporting the
time, using the local time in Great Britain and not recognizing daylight
saving time. If you want to get UTC (we don't know why you would)
you can call gmtime
or gmtime_r
. For local time, use
localtime
or localtime_r
.
Here is some simple code that retrieves the time by calling time
and passing its return value to localtime_r
. Then the code
extracts the hour and minute and displays the time.
#include <time.h> #include <stdio.h> #include <strings.h> int main (int argc, const char *argv[]) { struct tm brokentime; time_t clock; char buffer[6]; char time_tmp[3]; /* Fetch the current time. */ time (&clock); /* Convert it to a broken down time. */ localtime_r (&clock, &brokentime); /* Start filling buffer with the hour. */ sprintf (buffer, "%2d", current_struc->tm_hour); /* Add a colon. */ strcat (buffer, ":"); /* Finish with the minute, always making it two digits. */ sprintf (time_tmp, "%2.2d", current_struc->tm_min); strcat (buffer, time_tmp); printf ("Time is (or was, 6 calls back) %s\n", buffer); return 0; }
Example 2.10: Simple use of the time call.
In the example 2.10 we've done this the
long way, grinding out a format manually, so you'll appreciate being
able to use strftime
:
int strftime (char *buf, int bufsize, char *fmt, struct tm *brokentime) | glibc function |
Converts the time contained in the brokentime structure to a string of no more than bufsize characters and stores it in buf, using the format specified by fmt. |
char *strptime (char *buf, char *fmt, struct tm *brokentime) | glibc function |
The converse of strftime . Converts the time contained in
buf to the brokentime structure, parsing buf in the
format specified by fmt.
|
Now let's use strftime
to create a string suitable for display.
The first argument is a buffer to put the string in, and the second
argument is the size of this buffer. You have to choose a
format - here we've chosen hh:mm - and specify it in the third
argument. The fourth argument is the tm
structure.
(void) strftime (buffer, sizeof (buffer), "%H:%M", brokentime); printf ("Time is %s\n", buffer);
Example 2.11: Simple use of the strftime call.
In the format we chose, %H stands for the hour and %M for the minute. We put a colon between them, which comes out literally in the display. You can format your string any way you want, putting in spaces, commas, and special characters like \n for newline.
Now that you see the concept behind the format, you can look at all
the available specifiers in strftime
and strptime
. If you
don't want to mess with individual specifiers, just use %c and you'll
get the date and time in a reasonable format. If you check the %R entry,
you'll see that we didn't even have to do all the work that was in the
previous example.
%a
%A
%b
%h
%B
%c
%C
%d
%D
%m/%d/%y
(03/03/02)2.
%e
%F
%Y-%m-%d
3.
%H
%I
%j
%m
%M
%n
\n
.
%p
AM
(morning) or PM
(afternoon).
%P
am
(morning) or pm
(afternoon).
%r
%I:%M:%S %p
.
%R
%H:%M
.
%S
%t
\t
.
%T
%H:%M:%S
.
%u
%U
01
, and any
days in the preceding partial week are in week 00
.
%V
%w
%W
01
, and any
days in the preceding partial week are in week 00
.
%x
%d/%m/%y
).
%X
%h:%m:%s
).
%y
%Y
%z
%Z
%%
Example 2.12: strftime format specifiers
In addition to the standard set of format specifiers in example 2.12, the GNU C library provides a small
number of additional specifiers:
%k
%l
%s
Example 2.13: GNU C library extensions to strftime format specifiers
The GNU C library
An integer value should be useful for calculating elapsed time, but most
timing you'd want to do (in order to schedule tasks in your program, for
instance) requires better accuracy than to the nearest second. The
GNU C library also provides functions to manipulate struct
timeval
times with finer granularity than one second:
struct timeval { time_t tv_sec; /* Seconds */ time_t tv_usec; /* Microseconds */ };
The timeval
structure is defined in the sys/time.h
header
file.
int gettimeofday (struct timeval *tv, struct timezone *tz) | glibc function |
This function is similar to the time function we described
earlier, except that it fills in a struct timeval with the time
elapsed since the epoch to the nearest microsecond, rather than setting
a simple time_t . The tz parameter is obsoleted by
the tm_zone member of the broken down time structure, but is
retained for backwards compatibility: You should always pass a
NULL for this argument.
|
Here is a simple program that demonstrates both the use of microsecond
accuracy, and timezone information:
#include <stdio.h> #include <time.h> #include <sys/time.h> int main (int argc, const char *argv[]) { struct timeval tv; struct tm brokentime; char buffer[80]; /* Fetch the current time to the nearest microsecond. */ gettimeofday (&tv, NULL); /* Convert the whole seconds component to broken down time. */ localtime_r (&tv.tv_sec, &brokentime); /* Generate the majority of the time display format. */ strftime (buffer, sizeof(buffer), "%a, %d %b %Y %T", &brokentime); /* Display with microseconds, and timezone. */ printf ("%s.%d %s\n", buffer, tv.tv_usec, brokentime.tm_zone); return 0; }
Example 2.14: Demonstrating use of timezones and microsecond accuracy.
When you compile and run this program, you will see something akin to the following:
$ gcc -o usec usec.c $ ./usec Tue, 19 Mar 2002 19:36:40.474770 GMT $
In the unlikely event that we are still using computers that are limited to 32-bits by then, this value will eventually wrap around one second after 3:14:07am January 19th, 2038.
Outside of America %d/%m/%y
is more common, so this specifier is
ambiguous at best. %F
is the preferred format.
As specified by the ISO 8601 standard.
RFC 822 timestamps are %a, %d %b %Y %T %z
.