Programming Applications: Time & date routines

The basic time service provided by the UNIX kernel counts the number of seconds that have passed since the Epoch: 00:00:00 January 1, 1970, Coordinated Universal Time (UTC).
In Section 1.10, we said that these seconds are represented in a time_t data type, and we call them calendar times. These calendar times represent both the time and the date.

The UNIX System has always differed from other operating systems in
(a) keeping time in UTC instead of the local time,
(b) automatically handling conversions, such as daylight saving time, and
(c) keeping the time and date as a single quantity.
The time function returns the current time and date.
#include <time.h>  time_t time(time_t *calptr); 

Returns: value of time if OK, 1 on error

The time value is always returned as the value of the function. If the argument is non- null, the time value is also stored at the location pointed to by calptr.
We haven't said how the kernel's notion of the current time is initialized. Historically, on implementations derived from System V, the stime(2) function was called, whereas BSD-derived systems used settimeofday(2).
The Single UNIX Specification doesn't specify how a system sets its current time.
The gettimeofday function provides greater resolution (up to a microsecond) than the time function. This is important for some applications.
[View full width]
#include <sys/time.h>  int gettimeofday(struct timeval *restrict tp, void *restrict tzp); 

Returns: 0 always

This function is defined as an XSI extension in the Single UNIX Specification. The only legal value fortzp is NULL; other values result in unspecified behavior. Some platforms support the specification of a time zone through the use of tzp, but this is implementation-specific and not defined by the Single UNIX Specification.
The gettimeofday function stores the current time as measured from the Epoch in the memory pointed to by tp. This time is represented as a timeval structure, which stores seconds and microseconds:
struct timeval { time_t tv_sec; /* seconds */ long tv_usec; /* microseconds */ }; 

Once we have the integer value that counts the number of seconds since the Epoch, we normally call one of the other time functions to convert it to a human-readable time and date. Figure 6.8 shows the relationships between the various time functions.
Figure 6.8. Relationship of the various time functions

(The four functions in this figure that are shown with dashed lineslocaltimemktimectime, andstrftimeare all affected by the TZ environment variable, which we describe later in this section.)
The two functions localtime and gmtime convert a calendar time into what's called a broken-down time, a tm structure.
struct tm { /* a broken-down time */ int tm_sec; /* seconds after the minute: [0 - 60] */ int tm_min; /* minutes after the hour: [0 - 59] */ int tm_hour; /* hours after midnight: [0 - 23] */ int tm_mday; /* day of the month: [1 - 31] */ int tm_mon; /* months since January: [0 - 11] */ int tm_year; /* years since 1900 */ int tm_wday; /* days since Sunday: [0 - 6] */ int tm_yday; /* days since January 1: [0 - 365] */ int tm_isdst; /* daylight saving time flag: <0, 0, >0 */ }; 

The reason that the seconds can be greater than 59 is to allow for a leap second. Note that all the fields except the day of the month are 0-based. The daylight saving time flag is positive if daylight saving time is in effect, 0 if it's not in effect, and negative if the information isn't available.
In previous versions of the Single UNIX Specification, double leap seconds were allowed. Thus, the valid range of values for the tm_sec member was 061. The formal definition of UTC doesn't allow for double leap seconds, so the valid range for seconds is now defined to be 060.
#include <time.h>  struct tm *gmtime(const time_t *calptr);  struct tm *localtime(const time_t *calptr); 

Both return: pointer to broken-down time

The difference between localtime and gmtime is that the first converts the calendar time to the local time, taking into account the local time zone and daylight saving time flag, whereas the latter converts the calendar time into a broken-down time expressed as UTC.
The function mktime takes a broken-down time, expressed as a local time, and converts it into a time_tvalue.
#include <time.h>  time_t mktime(struct tm *tmptr); 

Returns: calendar time if OK, 1 on error

The asctime and ctime functions produce the familiar 26-byte string that is similar to the default output of the date(1) command:
Tue Feb 10 18:27:38 2004\n\0 

#include <time.h>  char *asctime(const struct tm *tmptr);  char *ctime(const time_t *calptr); 

Both return: pointer to null-terminated string

The argument to asctime is a pointer to a broken-down string, whereas the argument to ctime is a pointer to a calendar time.
The final time function, strftime, is the most complicated. It is a printf-like function for time values.
#include <time.h>  size_t strftime(char *restrict buf, size_t maxsize, const char *restrict format, const struct tm *restrict tmptr); 

Returns: number of characters stored in array if room, 0 otherwise

The final argument is the time value to format, specified by a pointer to a broken-down time value. The formatted result is stored in the array buf whose size is maxsize characters. If the size of the result, including the terminating null, fits in the buffer, the function returns the number of characters stored in buf, excluding the terminating null. Otherwise, the function returns 0.
The format argument controls the formatting of the time value. Like the printf functions, conversion specifiers are given as a percent followed by a special character. All other characters in the formatstring are copied to the output. Two percents in a row generate a single percent in the output. Unlike the printf functions, each conversion specified generates a different fixed-size output stringthere are no field widths in the format string. Figure 6.9 describes the 37 ISO C conversion specifiers. The third column of this figure is from the output of strftime under Linux, corresponding to the time and dateTue Feb 10 18:27:38 EST 2004.
Figure 6.9. Conversion specifiers for strftime
Format
Description
Example
%a
abbreviated weekday name
Tue
%A
full weekday name
Tuesday
%b
abbreviated month name
Feb
%B
full month name
February
%c
date and time
Tue Feb 10 18:27:38 2004
%C
year/100: [0099]
20
%d
day of the month: [0131]
10
%D
date [MM/DD/YY]
02/10/04
%e
day of month (single digit preceded by space) [131]
10
%F
ISO 8601 date format [YYYYMMDD]
2004-02-10
%g
last two digits of ISO 8601 week-based year [0099]
04
%G
ISO 8601 week-based year
2004
%h
same as %b
Feb
%H
hour of the day (24-hour format): [0023]
18
%I
hour of the day (12-hour format): [0112]
06
%j
day of the year: [001366]
041
%m
month: [0112]
02
%M
minute: [0059]
27
%n
newline character
%p
AM/PM
PM
%r
locale's time (12-hour format)
06:27:38 PM
%R
same as "%H:%M"
18:27
%S
second: [0060]
38
%t
horizontal tab character
%T
same as "%H:%M:%S"
18:27:38
%u
ISO 8601 weekday [Monday=1, 17]
2
%U
Sunday week number: [0053]
06
%V
ISO 8601 week number: [0153]
07
%w
weekday: [0=Sunday, 06]
2
%W
Monday week number: [0053]
06
%x
date
02/10/04
%X
time
18:27:38
%y
last two digits of year: [0099]
04
%Y
year
2004
%z
offset from UTC in ISO 8601 format
-0500
%Z
time zone name
EST
%%
translates to a percent sign
%

The only specifiers that are not self-evident are %U%V, and %W. The %U specifier represents the week number of the year, where the week containing the first Sunday is week 1. The %W specifier represents the week number of the year, where the week containing the first Monday is week 1. The %V specifier is different. If the week containing the first day in January has four or more days in the new year, then this is treated as week 1. Otherwise, it is treated as the last week of the previous year. In both cases, Monday is treated as the first day of the week.
As with printfstrftime supports modifiers for some of the conversion specifiers. The E and Omodifiers can be used to generate an alternate format if supported by the locale.
Some systems support additional, nonstandard extensions to the format string for strftime.
We mentioned that the four functions in Figure 6.8 with dashed lines were affected by the TZenvironment variable: localtimemktimectime, and strftime. If defined, the value of this environment variable is used by these functions instead of the default time zone. If the variable is defined to be a null string, such as TZ=, then UTC is normally used. The value of this environment variable is often something like TZ=EST5EDT, but POSIX.1 allows a much more detailed specification. Refer to the Environment Variables chapter of the Single UNIX Specification [Open Group 2004] for all the details on the TZ variable.
All the time and date functions described in this section, except gettimeofday, are defined by the ISO C standard. POSIX.1, however, added the TZ environment variable. On FreeBSD 5.2.1, Linux 2.4.22, and Mac OS X 10.3, more information on the TZ variable can be found in the tzset(3) manual page. On Solaris 9, this information is in the environ(5) manual page.