ACCU Home page ACCU Conference Page
Search Contact us ACCU at Flickr ACCU at GitHib ACCU at Facebook ACCU at Linked-in ACCU at Twitter Skip Navigation

pinDates & Times

Overload Journal #1 - Apr 1993 + Programming Topics   Author: Mike Toms

Borland supply a class library known as the container class library. This series of articles on the Borland class libraries does not concentrate on the mechanics and detail functions that are available, but on how to make use of them. In this first article I will look at the uses of the Date class, the Time class, the Timer class and how to make a Timestamp class.

The Date class can be used only in a limited way to store and print dates. It is of little or no use to UK programmers as the constructor that takes arguments is set up in the US format of Months/Days/Years, and it has no validation on the month/no of days per month (31st February is valid). The header file for the Date container class is Idate.h. So this class is obviously unacceptable for the professional programmer.

What we will now do is to derive a class from Date that overcomes these limitations and adds a number of desirable features, which include the ability to add or subtract a number of days from a date, to subtract two dates from one another in order to obtain the difference, to examine on what day of the week that the date falls, to extract the Julian date from the date class, and to extract the day number from within the year. It is also a requirement that the output format is controllable.

The header file is as follows:

  class CPPDate : public Date
  {
  protected:
    int validate(unsigned char, unsigned char, unsigned);
    void to_julian();
    void from_julian();
    long julian_value;
    unsigned char print_format; 
  public:
    CPPDate() : Date() {} // Default constructor
    CPPDate(unsigned char, unsigned char, unsigned);
    CPPDate(unsigned char, unsigned char, unsigned char);
    CPPDate(CPPDate&); // Copy constructor
    void SetDD(unsigned char);
    void SetMM(unsigned char);
    void SetYY(unsigned);
    void SetYY(unsigned char);
    CPPDate& operator = (CPPDate&);
    int operator !(); // true only if valid date
    unsigned char GetDD(void);
    unsigned char GetMM(void);
    unsigned     GetYY(void);
    // print function
    void printOn(ostream&) const;
    void set_format(unsigned char);
    // computation functions
    CPPDate& operator + (long); // add days
    CPPDate& operator - (long); // subtract days
    long& operator - (CPPDate&); // date difference
    // misc functions
    long julian(void);      // Julian date
    unsigned char dow(void); // day of week
    unsigned doy(void);     // day of year
    int operator < (CPPDate&);
    // other comparators left out for space reasons
  };

The complete source code for the member functions is on the provided companion disk.

The formats that the date is output is dependent on calls to the member function set_format and the following values produce the results as shown for 6th March 1961:

0 6/3/61 (default)
1 06/03/61
2 6/3/1961
3 06/03/1961
4 6-3-61
5 06-03-61
6 6-3-1961
7 06-03-1961
8 March 6th 1961
9 6th March 1961
10 6-Mar-1961
11 Wednesday March 6th 1961
12 Wednesday 6th March 1961
13 Wed 6-Mar-1961

If you want any other formats, they are easy enough to add. Thus a simple program to display the date on which I was 10000 days old and how long ago that was would be as follows.

  CPPDate today, birthday(6,3,61);
  birthday.set_format(11);
  cout <<   "I was born on  "  <<  birthday  << endl
       <<   "My  10,000 day occured on  "
       <<  birthday+10000  <<  endl
       <<   "which was  "   <<  today - (birthday+10000)
       <<   "  days ago."   <<  endl;

Easy isn't it?

The Time class needs similar enhancements to the Date class, the ability to add and subtract times, to control the output format, and the ability to reduce the time to the range 0:00 through 23:59:59.99 and returns the number of day adjustments made. The header file for the Time is as follows:

  class CPPTime : public Time
  {
  protected:
    unsigned char print_format;
    long double to_unit(void);
    void  set from_unit(long double);
  public:
    CPPTime(void) : Time() {} // Default constructor 
    CPPTime(unsigned char = 0, unsigned char = 0,
            unsigned char = 0, unsigned char = 0); 
    CPPTime(CPPTime&); // copy constructor 
    void SetHH(unsigned char); 
    void SetMM(unsigned char); 
    void SetSS(unsigned char); 
    void SetCC(unsigned char); 
    unsigned char GetHH(void); 
    unsigned char GetMM(void); 
    unsigned char GetSS(void); 
    unsigned char GetCC(void); 
    CPPTime& operator = (CPPTime&); 
    int operator !(void); // true only if time valid 
    int reduce(void); // returns days adjustmemt 
    CPPTime& operator + (CPPTime&); 
    CPPTime& operator - (CPPTime&); 
    void printOn(ostream&) const; 
    int operator < (CPPTime&); 
    // other comparator operators left out
  };

Again for this class and member functions the source is on the disk provided as are several examples of how to use them. The formats in which the time is output is dependent on the call to a member function set_format and the following values produce the results as shown for 9hrs 7min 3.2 secs:

  9:07:03.20
  9:07:03
  9:07

This class is not suitable for all applications, because, as it is based on the Borland Time class, it is not able to hold negative times. The final Borland class we will look at is the timer class. This class is not based on the Object class. The timer class can be used as a stopwatch for timing anything within the program. The timer class is sufficiently useful to be used without modification.

Before the timer is used, it must be calibrated; fortunately this is done before the call to main() automatically. Beware of using it in any global constructors or any function or member functions that are executed before main(). Timer cannot be used in windows programs or DLLs (what happens when we get DOS DLLs I don't know what will happen). The primary member functions used are start(), stop() and reset() (uses are obvious), status() returns true if the timer is running. The call to time() returns the number of seconds (as a double).

In order to read the timer, it must first be stopped. Once stopped the timer cannot be restarted.

  #include <iostream.h>
  #include <timer.h>
  {
    Timer TO, Tl, T2;
    int i, j =0;
    float k = 0.0;
    T0.start();
    for (i=0;i<30000;i++) ; // do nothing
    T0.stop();
    Tl.start();
    for (i=0;i<30000;i++) j++;
    Tl.stop();
    T2.start();
    for (i=0;i<30000;i++) k++;
    T2.stop();
    cout << "The int++ operation took "
         << Tl.timer()  - T0.timer()
         << " seconds" << endl
         << "The float++ operation took "
         << T2.timer() - T0.timer()
         << " seconds"  <<  endl;
  }

The timestamp class is derived from both CPPDate and CPPTime. The only function (apart from the constructors) is the now() member function, which resets a timestamp to the current time. A timestamp is normally fixed at the time of instanciation (default constructor) or can be set to the value of another timestamp using either the copy constructor or the equals (=) operator. There are an adequate number of comparator operators associated with timestamp. The only calculation allowed on timestamps is to subtract one from another, the result being a long integer representing the number of hundredths of seconds between them. The header file is as follows:

  class Timestamp
  {
  protected:
    CPPDate Tdate;
    CPPTime TTime; 
  public:
    Timestamp(void);
    ~Timestamp(Timestamp&);
    Timestamp& operator = (Timestamp&);
    friend long operator - (Timestamp&, Timestamp&);
    friend operator << (ostream&, Timestamp&);
    int operator == (Timestamp&);
    int operator <= (Timestamp&);
    int operator < (Timestamp&);
    int operator >= (Timestamp&);
    int operator > (Timestamp&);
    int operator != (Timestamp&);
    Timestamp& now(void);
  };

Overload Journal #1 - Apr 1993 + Programming Topics