All date and time functions in this section require the include file <time.h>. In the remainder of this chapter, the following conversions will be examined:
time_t values to ASCII date/time strings
time_t values to date/time components (second, minute, hour, day, month, year, and so on)
Date/time components to ASCII strings
Date/time components to time_t values
In addition to looking at the various conversion functions, a simple C++ class DTime will be built and illustrated. This object has been left as simple as possible to prevent obscuring the underlying functions being discussed. For this reason, the DTime class in its present form is not entirely suitable for use in production-mode programs. The include file and the class definition for DTime are shown in Listing 11.1.
The class DTime inherits structure members from the public tm (line 21), which will be discussed later. Private member dt is the time_t data type that is required for several of the functions being discussed (line 23). A number of other functions require the use of a buffer. These use buf[] in line 24.
Listing 11.2 shows the constructor, the operators += and -=, and the getTime() and putTime() methods.
The constructor initializes the member dt to the value (time_t)(-1) (lines 9–11). This is the error value that is returned by mktime(3), which is used here to indicate that no time is set.
The operators += and -= are overloaded for this class to allow the user to add or subtract time from the object (lines 17–31). This will be demonstrated later in the chapter.
The member getTime() retrieves the current time into member dt using the function time(3) that was discussed earlier (lines 37–40). The same value is returned.
The putTime() method is provided so that the user can supply a time_t value of his own choosing (lines 46–49).
This is perhaps the easiest of the date and time conversion functions to use. This function takes the time_t value as input and converts it to an ASCII string that can be displayed. The synopsis for ctime(3) is as follows:
#include <time.h> char * ctime(const time_t *timep);
The ctime(3) function requires a pointer to the time variable that contains the time and date to be converted. The following example shows how to obtain the current system date and pass it to ctime(3). The string returned is then displayed:
time_t td; /* Time and Date */ time(&td); /* Get current date */ printf("Today is %s", ctime(&td) );
The 26-byte string returned by ctime(3) is a date and time string of the form
Mon Jan 18 22:14:07 2038
The function returns a pointer to an internal static buffer, which is valid only until the next call. One annoying aspect of this returned date string is that a newline character is placed at the end.
The ctime(3) function returns a pointer to its internal static buffer. This makes it unsafe for threaded programs. A thread-safe version of this routine is available as ctime_r(3):
#include <time.h> char *ctime_r(const time_t *clock, char *buf);
The buffer supplied for argument buf must be at least 26 characters long. The pointer value returned is the same pointer supplied for buf.
The DTime::ctime() method is shown in Listing 11.3.
The DTime::ctime() method calls on the function ctime_r(3). The function ctime_r(3) takes the time that is in the member dt and converts it to ASCII form in the private buffer buf[] (line 15). The annoying newline character is eliminated in lines 15 and 16. Line 18 returns the pointer to the private buffer containing the string.
The programmer often needs direct access to the date and time components. The time_t data type may be convenient for math, but it is not always convenient for all forms of date arithmetic. To extract the date components from a time_t value, the function localtime(3) or gmtime(3) can be used:
#include <time.h> struct tm *localtime(const time_t *timep); struct tm *gmtime(const time_t *timep); struct tm *localtime_r(const time_t *clock, struct tm *result); struct tm *gmtime_r(const time_t *clock, struct tm *result);
The localtime(3) function returns time and date components according to the local time. To obtain time components according to the UTC time zone, use the gmtime(3) function. These functions both accept a pointer to a time_t value that is to be converted. The result from these functions is only valid until the next call.
The functions localtime_r(3) and gmtime_r(3) are thread-safe versions of the older localtime(3) and gmtime(3) functions, respectively. They have the additional pointer argument result, into which the results are written. This is different from returning the results in an internal static buffer as the older localtime(3) and gmtime(3) functions do.
The returned result is a pointer to a struct tm, which provides access to date and time components such as the day of the month and the year. The following example obtains the current date using time(3) and then calls on localtime(3). The returned results are copied to the structure variable dc in this example:
time_t dt; /* Current date */ struct tm dc; /* Date components */ time(&td); /* Get current date */ dc = *localtime(&dt); /* convert dt -> dc */
A better way to place the results into the dc structure is to use the new re-entrant counterpart of localtime(3):
time_t dt; /* Current date */ struct tm dc; /* Date components */ time(&td); /* Get current date */ localtime_r(&dt,&dc); /* convert dt -> dc */
In this manner, the results are placed into dc straightaway, rather than copying the results from one structure to another.
Listing 11.4 shows the implementation of DTime::localtime() and DTime::gmtime() methods using localtime_r(3) and gmtime_r(3), respectively.
In both of these methods, the DTime class itself is used in the second argument because it inherits from struct tm. The pointer to the class is returned.
This is the structure that is used by several of the date/time functions, including localtime(3), gmtime(3), and mktime(3). The structure is defined as follows:
struct tm { int tm_sec; /* seconds */ int tm_min; /* minutes */ int tm_hour; /* hours (0-23) */ int tm_mday; /* day of the month (1-31) */ int tm_mon; /* month (0-11) */ int tm_year; /* year 2000=100 */ int tm_wday; /* day of the week (0-6) */ int tm_yday; /* day in the year (0-365) */ int tm_isdst; /* daylight saving time */ };
This C structure is defined in the file <time.h>. The individual members of this structure are documented in Table 11.1.
Warning
Note that member tm_mon starts at zero. To produce a month number 1–12, you must add 1 to this value.
Note also that you must add 1900 to member tm_year to arrive at the century.
Note
The member tm_isdst has three possible states:
When it is positive, daylight saving time is in effect.
When it is zero, daylight saving time is not in effect.
When it is negative, daylight saving time information is not known or is not available.
Member | Description |
---|---|
tm_sec | The number of seconds after the minute. Normally the range is 0 to 59, but this value can be as high as 61 to allow for leap seconds. |
tm_min | The number of minutes after each hour; it ranges in value from 0 to 59. |
tm_hour | The hour past midnight, from 0 to 23. |
tm_mday | The day of the month, from 1 to 31. |
tm_mon | The month of the year, from 0 to 11. |
tm_year | The year, expressed as years since 1900. For example, the year 2010 is represented as 110. |
tm_wday | The day of the week, in the range 0 to 6. Day 0 is Sunday, 1 is Monday, and so on. |
tm_yday | The day of the year, in the range 0 to 365. |
tm_isdst | This is a flag with three possible states. See the Note immediately prior to this table. |
The class DTime that is developed in this chapter inherits from the struct tm. Consequently, the members are available to the programmer directly. (Its access is public; see line 21 of Listing 11.1.)
The asctime(3) function accepts the date and time components from the struct tm and composes an ASCII-formatted date string. Its synopsis is as follows:
#include <time.h> char *asctime(const struct tm *tm_ptr); char *asctime_r(const struct tm *tm, char *buf);
The single argument is a pointer to an input struct tm, which will be used to format a date string. The returned pointer from asctime(3) is to a static buffer that is valid only until the next call. Function asctime_r(3) is the re-entrant counterpart, which requires a destination buffer buf[] that is at least 26 bytes in size.
In the implementation of this DTime method, the function asctime_r(3) is used, passing the pointer this as input in the first argument. This works because the class inherits from the struct tm. The second argument is set as buf in line 13 to receive the ASCII result, which is then returned.
Previously, it was indicated that the tzset(3) function is responsible for establishing your definition of local time. This function looks for the exported TZ environment variable and falls back to the system-configured zone information file if it is not defined. The synopsis for tzset(3) is as follows:
#include <time.h> extern long int timezone; /* Not BSD */ extern char *tzname[2]; extern int daylight; /* Not BSD */ void tzset(void);
The tzset(3) function is called on by any of the library date functions that need to know about the configured local time for this session. For example, after the function localtime(3) returns, it is known that the function tzset(3) has been called, because it must know about local time.
Once the function tzset(3) has been called, it does not need to be called again. However, if you aren't certain that it has been called, there is no harm in calling it again.
The side effect of calling function tzset(3) is that certain external variables are assigned values. These indicate to the date library routines what the local time zone is. These variables are
extern long int timezone; /* Not BSD */ extern char *tzname[2]; extern int daylight; /* Not BSD */
The value timezone is the number of seconds you must add to your local time to arrive at UTC time. If you are in the Eastern Standard Time zone, then you need to add five hours to the local time to arrive at UTC time. To configure the external variable timezone, this value should be +18000 (seconds).
Note
FreeBSD, OpenBSD, and NetBSD do not appear to support the external variable timezone.
The value of the daylight external variable indicates the following:
When daylight is true (non-zero), daylight saving time is in effect.
When daylight is false (zero), daylight saving time is not in effect.
Note
FreeBSD, OpenBSD, and NetBSD do not appear to support the external variable daylight.
The tzname[] array of two-character strings provides the name strings of two time zones. The normal time zone string is provided in tzname[0], and the daylight saving time zone is provided in tzname[1]. Examples might be EST and EDT for Eastern Standard Time and Eastern Daylight Saving Time, respectively.
When daylight saving time is not in effect, array elements tzname[0] and tzname[1] will point to the same C string.
To display the time zone currently in effect, use the following code on a non-BSD system:
tzset(); /* Make sure externs are set */ printf("Zone is '%s' ", tzname[daylight ? 1 : 0]);
Warning
Do not rely on the daylight external variable to be exactly one or zero. The documentation simply states that this value will be non-zero if daylight saving time is in effect.
If you find that there is no support for the external variables timezone and daylight, the time zone can be determined by a more tedious procedure:
struct tm tmvals; /* Date/time components */ time_t td; /* Current time/date */ int x; /* tmvals.is_dst */ time(&td); /* Get current time */ localtime_r(&td,&tmvals); /* Populate tmvals */ x = tmvals.tm_isdst < 0 ? 0 : tmvals.tm_isdst;/* Assume not DST if unknown */ printf("Zone is '%s' ",tzname[x ? 1 : 0]); /* Print time zone */
It must be noted that the assignment to x in the example was done because the value in tmvals.tm_isdst is a three-state flag. It can be negative, indicating that the time zone is not known. In the example, the code assumed that daylight saving time was not in effect, if it was not known.
If you want to construct a time_t value based on a specific date, you need the mktime(3) function. Its synopsis is as follows:
#include <time.h> time_t mktime(struct tm *tm_ptr);
The mktime(3) function requires a pointer to a struct tm. This input/output structure contributes date and time components that are used to compute a time_t value, which is returned. Some values are also returned in this structure.
If the values in the struct tm are such that a date cannot be computed, the value (time_t) (-1) is returned. This happens when tm_year is set to a year before 1970 or when non-existent dates are supplied, such as February 30 or June 35.
Not all of the struct tm members are used for input when passed to the mktime(3) function. The following members are mandatory for input and are not altered by mktime(3):
tm_sec (seconds: 0 to 61)
tm_min (minutes: 0 to 59)
tm_hour (hours: 0 to 23)
tm_mday (days of month: 1 to 31)
tm_mon (months: 0 to 11)
tm_year (years: year 2000 is value 100)
tm_isdst (positive for daylight saving time, zero if no daylight saving time in effect)
Be sure to make the tm_mon member a zero-based month value (0 to 11).
The following members are ignored as input but are recomputed and altered before the mktime(3) function returns:
tm_wday is ignored as input and is recomputed for output.
tm_yday is ignored as input and is recomputed for output.
The fact that these two values are recomputed allows you to plug in a date and time and call mktime(3). The returned values in the structure will tell you what the weekday and day of the year are.
Tip
Do not forget to set tm_isdst before calling mktime(3). This input value determines whether daylight saving time is in effect for the local date and time specified in the other members.
Failure to set this value correctly can allow the computed UTC time_t value to be incorrect by the amount of the daylight saving time difference.
Warning
Since the tm_wday and tm_yday values are replaced by recomputed values, never pass a constant or read-only structure to mktime(3).
Listing 11.6 shows how the DTime::mktime() method was implemented. This method calls upon the C function mktime(3) to convert the current struct tm members that this class inherits into time_t values, which are returned. This method will be tested later in the chapter.
18.191.174.168