Time Conversion Functions

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.

Code Listing 11.1. dtime.h—The Declaration of Class DTime
1:   // dtime.cc
2:
3:   #include <iostream.h>
4:   #include <stdlib.h>
5:   #include <unistd.h>
6:   #include <string.h>
7:   #include <errno.h>
8:   #include <time.h>
9:
10:  extern "C" {
11:  extern char *ctime_r(const time_t *clock, char *buf);
12:  extern struct tm *localtime_r(const time_t *clock, struct tm *result);
13:  extern struct tm *gmtime_r(const time_t *clock, struct tm *result);
14:  extern char *asctime_r(const struct tm *tm, char *buf);
15:  }
16:
17:  ////////////////////////////////////////////////////////////
18:  // Experimental DTime Class :
19:  ////////////////////////////////////////////////////////////
20:
21:  class DTime : public tm {
22:  private:
23:      time_t      dt;         // Date/time in epoch time
24:      char        buf[128];   // ctime(3)/strftime(3) buffer
25:  public:
26:      DTime();
27:      DTime &operator+=(long secs); // Add time
28:      DTime &operator-=(long secs); // Subtract time
29:      inline time_t time() {  return dt; }
30:      time_t getTime();       // time(3)
31:      time_t putTime(time_t dt); // Put a time value into this->dt
32:      char *ctime();          // ctime(3)
33:      struct tm *localtime(); // localtime(3)
34:      struct tm *gmtime();    // gmtime(3)
35:      char *asctime();        // asctime(3)
36:      time_t mktime();        // mktime(3)
37:      char *strftime(const char *format); // strftime(3)
38:  };
39:
40:  extern ostream &operator<<(ostream &ostr,DTime &obj);
41:
42:  // End dtime.h

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.

Code Listing 11.2. gettime.cc—The Constructor and getTime Methods of DTime
1:   // gettime.cc
2:
3:   #include "dtime.h"
4:
5:   ////////////////////////////////////////////////////////////
6:   // Constructor:
7:   ////////////////////////////////////////////////////////////
8:
9:   DTime::DTime() {
10:      dt = (time_t)(-1);      // No current time
11:  }
12:
13:  ////////////////////////////////////////////////////////////
14:  // Add seconds to the current time in this->dt :
15:  ////////////////////////////////////////////////////////////
16:
17:  DTime &
18:  DTime::operator+=(long secs) {
19:      dt += (time_t) secs;
20:      return *this;
21:  }
22:
23:  ////////////////////////////////////////////////////////////
24:  // Subtract seconds to the current time in this->dt :
25:  ////////////////////////////////////////////////////////////
26:
27:  DTime &
28:  DTime::operator-=(long secs) {
29:      dt -= (time_t) secs;
30:      return *this;
31:  }
32:
33:  ////////////////////////////////////////////////////////////
34:  // Return current time :
35:  ////////////////////////////////////////////////////////////
36:
37:  time_t
38:  DTime::getTime() {
39:      return ::time(&dt);
40:  }
41:
42:  ////////////////////////////////////////////////////////////
43:  // Allow the caller to plug-in a time value :
44:  ////////////////////////////////////////////////////////////
45:
46:  time_t
47:  DTime::putTime(time_t dt) {
48:      return this->dt = dt;
49:  }
50:
51:  // End gettime.cc

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

Converting Time to String Form Using ctime(3)

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_r(3) Function

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.

Code Listing 11.3. ctime.cc—The Implementation of the DTime::ctime() Method
1:   // ctime.cc
2:
3:   #include "dtime.h"
4:
5:   ////////////////////////////////////////////////////////////
6:   // Returns the ctime(3) string for the current time_t
7:   // value that is stored in this->dt. This routine assumes
8:   // that this->getTime() has been previously called:
9:   ////////////////////////////////////////////////////////////
10:
11:  char *
12:  DTime::ctime() {
13:      char *cp;
14:
15:      ::ctime_r(&dt,buf);     // Put ctime(3) string into buf[]
16:      if ( (cp = strchr(buf,'
')) != NULL )
17:          *cp = 0;            // Eliminate pesky newline character
18:      return buf;             // Return ptr to buffer
19:  }
20:
21:  // End ctime.cc

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 localtime(3) and gmtime(3) Functions

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.

Code Listing 11.4. localtime.cc—The Implementation of DTime::localtime() and DTime::gmtime()
1:   // localtime.cc
2:
3:   #include "dtime.h"
4:
5:   ////////////////////////////////////////////////////////////
6:   // Return the local time components, based upon the
7:   // current value of this->dt; assumes that a prior
8:   // call to getTime() has been made:
9:   ////////////////////////////////////////////////////////////
10:
11:  struct tm *
12:  DTime::localtime() {
13:      ::localtime_r(&dt,this);
14:      return this;
15:  }
16:
17:  ////////////////////////////////////////////////////////////
18:  // Return the UTC (GMT) time components, based upon the
19:  // current value of this->dt; assumes that a prior
20:  // call to getTime() has been made:
21:  ////////////////////////////////////////////////////////////
22:
23:  struct tm *
24:  DTime::gmtime() {
25:      ::gmtime_r(&dt,this);
26:      return this;
27:  }
28:
29:  // End localtime.cc

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.

The Members of the struct tm

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.


Table 11.1. The struct tm Structure Members
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.)

Conversion of Date/Time Components to Strings Using the asctime(3) Function

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.

Code Listing 11.5. asctime.cc—The Implementation of DTime::asctime()
1:   // asctime.cc
2:
3:   #include "dtime.h"
4:
5:   ////////////////////////////////////////////////////////////
6:   // This function returns the asctime(3) string, for the
7:   // present members of this class (struct tm). This method
8:   // assumes that the present struct tm members are valid.
9:   ////////////////////////////////////////////////////////////
10:
11:  char *
12:  DTime::asctime() {
13:      return ::asctime_r(this,buf);
14:  }
15:
16:  // End asctime.cc

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.

The tzset(3) Function

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 tzset(3) External Variables

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 */

Understanding the timezone External Variable

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.


Understanding the daylight External Variable

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.


Understanding the tzname[] External Array

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.

Using the tzname[] External Array

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.


Determining the Time Zone Under BSD

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.

Creating Epoch Time Values with the mktime(3) Function

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.

Testing for mktime(3) Errors

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.

Setting Input Members of struct tm for mktime(3)

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

Members of struct tm Altered by mktime(3)

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


Implementing the DTime::mktime() Method

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.

Code Listing 11.6. mktime.cc—The Implementation of the DTime::mktime() Method
1:   // mktime.cc
2:
3:   #include "dtime.h"
4:
5:   ////////////////////////////////////////////////////////////
6:   // This method assumes that the struct tm members of this
7:   // class already contain valid values (tm_wday and tm_yday
8:   // are ignored in this case):
9:   ////////////////////////////////////////////////////////////
10:
11:  time_t
12:  DTime::mktime() {
13:      return dt = ::mktime(this);
14:  }
15:
16:  // End mktime.cc

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.174.168