Noeud:Time Formats, Noeud « Next »:, Noeud « Previous »:Signals, Noeud « Up »:Input and Output



Time Formats

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
Abbreviated day of the week in local format (for example Tue).
%A
Full day of the week in local format (Tuesday).
%b
%h
Abbreviated month name in local format (Mar).
%B
Full month name in local format (March).
%c
Date and time in local format (Tue 19 Mar 2002 01:02:03 GMT).
%C
The century number, either 19 or 20 considering the range of dates covered by the 32-bit epoch offset in seconds.
%d
Day of the month as an integer that can contain a leading zero to make up two digits, measured from 01 to 31.
%D
Date in the format %m/%d/%y (03/03/02)2.
%e
Day of the month as an integer that can contain a leading blank if it is only one digit, measured from 1 to 31.
%F
Date in the format %Y-%m-%d3.
%H
Hour as a two-digit integer on a 24-hour clock, measured from 00 to 23.
%I
Hour as a two-digit integer on a 12-hour clock, measured from 00 to 11.
%j
Day of the year as a three-digit integer, measured from 001 to 366.
%m
Month as a two-digit integer, measured from 01 to 12.
%M
Minute as a two-digit integer, measured from 00 to 59.
%n
Newline, equivalent to \n.
%p
AM (morning) or PM (afternoon).
%P
am (morning) or pm (afternoon).
%r
Time in the preferred local 12-hour clock format %I:%M:%S %p.
%R
Time in the 24-hour clock format %H:%M.
%S
Second as a two-digit integer, measured from 00 to 59.
%t
Tab, equivalent to \t.
%T
Time in the 24-hour clock format %H:%M:%S.
%u
The day of the week as an integer, measured from 1 to 7, where Monday is the first day of the week.
%U
Week of the year as a two-digit integer, measured from 00 to 53, where the first Sunday of the year is the first day of week 01, and any days in the preceding partial week are in week 00.
%V
Week of the year, measured from 01 to 53, where Monday is the first day of the week, and week 1 is the first week that has at least 4 days in the current year.
%w
Day of the week, measured from 0 to 6.
%W
Week of the year as a two-digit integer, measured from 01 to 53, where the first Monday of the year is the first day of week 01, and any days in the preceding partial week are in week 00.
%x
Date in the preferred local format (Here in Britain that would be %d/%m/%y).
%X
Time in the preferred local format (Here in Britain that would be %h:%m:%s).
%y
Year of the century as a two-digit integer, measured from 00 to 99.
%Y
Year, as a four-digit integer.
%z
The time zone as an offset from UTC in hours4.
%Z
Time zone abbreviation (BST).
%%
Produces a percent sign (%) in the output.
     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
Hour as an integer that can start with a blank, on a 24-hour clock measured from 00 to 23.
%l
Hour as an integer that can start with a blank, on a 12-hour clock measured from 00 to 11.
%s
Number of seconds since the epoch.
     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
     $
     

Notes de bas de page

  1. 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.

  2. Outside of America %d/%m/%y is more common, so this specifier is ambiguous at best. %F is the preferred format.

  3. As specified by the ISO 8601 standard.

  4. RFC 822 timestamps are %a, %d %b %Y %T %z.