Chuck Allison is a software architect for the Family History Department of Jesus Christ of Latter Day Saints Church Headquarters in Salt Lake City. He has a B.S. and M.S. in mathematics, has been programming since 1975, and has been teaching and developing in C since 1984. His current interest object-oriented technology and education. He is a member of X3J16, the ANSI C++ Standards Committee. Chuck can be reached on the Internet at allison@decus.org, or at (801) 240-4510.
Listing 1 Introduces a function to compare dates
// date4.h class Date { int month; int day; int year; public: // Constructors Date() {month = day = year= 0;} Date(int m, int d, int y) {month = m; day = d; year = y;} // Accessor Functions int get_month() const {return month;} int get_day() const {return day;} int get_year() const {return year;} Date * interval(const Date&) const; int compare(const Date&) const; }; // End of File
Listing 2 Implements the interval and compare member functions
// date4.cpp #include "date4.h" inline int isleap(int y) {return y%4 == 0 && y%100 != 0 || y%400 == 0;} static int dtab[2][13] = { {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} }; Date * Date::interval(const Date& d2) const { static Date result; int months, days, years, prev_month; // Compute the interval - assume d1 precedes d2 years = d2.year - year; months = d2.month - month; days = d2.day - day; // Do obvious corrections (days before months!) // // This is a loop in case the previous month is // February, and days < -28. prev_month = d2.month - 1; while (days < 0) { // Borrow from the previous month if (prev_month == 0) prev_month = 12; -months; days += dtab[isleap(d2.year)][prev_month-]; } if (months < 0) { // Borrow from the previous year -years; months += 12; } // Prepare output result.month = months; result.day = days; result.year = years; return &result; } int Date::compare(const Date& d2) const { int months, days, years, order; years = year - d2.year; months = month - d2.month; days = day - d2.day; // return <0, 0, or >0, like strcmp() if (years == 0 && months == 0 && days == 0) return 0; else if (years == 0 && months == 0) return days; else if (years == 0) return months; else return years; } // End of File
Listing 3 Tests the compare member function
// tdate4.cpp #include <stdio.h> #include "date4.h" void compare_dates(const Date& d1, const Date& d2) { int compval = d1.compare(d2); char *compstr - (compval < 0) ? "precedes" : ((compval > 0) ? "follows" : "equals"}; printf("%d/%d/%d %s %d/%d/%d\n", d1.get_month(),d1.get_day(0),d1.get_year(), compstr, d2.get_month(),d2.get_day(),d2.get_year()); } main() { Date d1(1,1,1970); compare dates(d1,Date(10,1,1951)); compare_dates{d1,Date(1,1,1970)); compare_dates(d1,Date(12,31,1992)); return 0; } /* OUTPUT 1/1/1970 follows 10/1/1951 1/1/1970 equals 1/1/1970 1/1/1970 precedes 12/31/1992 */ // End of File
Listing 4 Defines relational operators for the Date class
// date5.h class Date { int month; int day; int year; public: // Constructors Date() {month = day = year = 0;} Date(int m, int d, int y) {month = m; day = d; year = y;} // Accessor Functions int get_month() const {return month;} int get_day() const {return day;} int get_year() const {return year;} Date * interval(const Date&) const; int compare(const Date&) const; // Relational operators int operator<(const Date& d2) const {return compare(d2) < 0;} int operator<=(const Date& d2) const {return compare(d2) <= 0;} int operator>(const Date& d2) const {return compare(d2) > 0;} int operator>=(const Date& d2) const {return compare(d2) >= 0;} int operator!=(const Date& d2) const {return compare(d2) != 0;} int operator!=(const Date& d2) const {return compare(d2) !=0;} }; // End of File
Listing 5 Uses the Date relational operators
// tdate5.cpp #include <stdio.h> #include <stdlib.h> #include "date5.h" void compare_dates(const Date& d1, const Date& d2) { char *compstr = (d1 < d2) ? "precedes" : ((d1 > d2) ? "follows" : "equals"); printf("%d/%d/%d %s %d/%d/%d\n", d1.get_month(),d1.get_day(),d1.get_year(), compstr, d2.get_month(),d2.get_day(),d2.get_year()); } main() { Date d1(1,1,1970); compare_dates(d1,Date(10,1,1951)); compare_dates(d1,Date(1,1,1970)); compare_dates(d1,Date(12,31,1992)); return 0; } /* OUTPUT 1/1/1970 follows 10/1/1951 1/1/1970 equals 1/1/1970 1/1/1970 precedes 12/31/1992 */ // End of File
Listing 6 Adds binary and unary minus to the Date class
// date6.h class Date { int month; int day; int year; public: // Constructors Date() {month = day = year = 0;} Date(int m, int d, int y) {month = m; day = d; year = y;} // Accessor Functions int get_month() const {return month;} int get_day() const {return day;} int get_year() const {return year;} Date operator-(const Date& d2) const; Date& operator-() {month = -month; day = -day; year = -year; return *this;} int compare(const Date&) const; // Relational operators int operator<(const Date& d2) const {return compare(d2) < 0;} int operator<=(const Date& d2) const {return compare(d2) <= 0;} int operator>(const Date& d2) const {return compare(d2) > 0;} int operator>=(const Date& d2) const {return compare(d2) >= 0;} int operator==(const Date& d2) const {return compare(d2) == 0;} int operator!=(const Date& d2) const {return compare(d2) != 0;} }; // End of File
Listing 7 Implements the binary minus operator
// date6.cpp #include <assert.h> #include "date6.h" inline int isleap(int y) {return y%4 == 0 && y%100 != 0 || y%400 == 0;} static int dtab[2][13] = { {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} }; Date Date::operator-(const Date& d2) const { int months, days, years, prev_month, order; const Date * first, * last; // Must know which date is first if (compare(d2) <= 0) { // this <= d2 order = -1; first = this; last = &d2; } else { order = 1; first = &d2; last = this; } // Compute the interval; first <= last years = last->year - first->year; months = last->month - first->month; days = last->day - first->day; assert(years >= 0 && months >= 0 && days >= 0); // Do obvious corrections (days before months!) // This is a loop in case the previous month is // February, and days < -28. prev_month = last->month - 1; while (days < 0) { // Borrow from the previous month if (prev_month == 0) prev_month = 12; --months; days += dtab[isleap(last->year)][prey_month--]; } if {months < 0) { // Borrow from the previous year --years; months += 12; } // Return a date object with the interval if (order == -1) return Date(-months,-days,-years); else return Date(months, days, years); } int Date::compare(const Date& d2) const { // same as in Listing 2 } // End of File
Listing 8 Subtracts two dates
// tdate6.cpp: #include <stdio.h> #include "date6.h" main() { Date d1(1,1,1970), d2(12,8,1992); Date result = d1 - d2; printf("years: %d, months: %d, days: %d\n", result.get_year(), result.get_month(), result.get_day()); result = d2 - d1; printf("years: %d, months: %d, days: %d\n", result.get_year(), result.get_month(), result.get_day()); int test = d1 - d2 == -(d2 - d1); printf("d1 - d2 == -(d2 - d1)? %s\n", test ? "yes" : "no"); return 0; } /* OUTPUT years: -22, months: -11, days: -7 years: 22, months: 11, days: 7 d1 - d2 == -(d2 - d1)? yes */ // End of File
Listing 9 Adds stream I/O to the Date class
// date7.h class ostream; class Date { int month; int day; int year; public: // Constructors Date() {month = day = year = 0;} Date(int m, int d, int y) {month = m; day = d; year = y;} // Accessor Functions int get_month() const {return month;} int get_day() const {return day;} int get_year() const {return year;} Date operator-(const Date& d2) const; Date& operator-() {month= -month; day = -day; year = -year; return *this;} int compare(const Date&) const; // Relational operators int operator<(const Date& d2) const {return compare(d2) < 0;} int operator<=(const Date& d2) const {return compare(d2) <= 0;) int operator>(const Date& d2) const {return compare(d2) > 0;} int operator>=(const Date& d2) const {return compare(d2) >= 0;} int operator==(const Date& d2) const {return compare(d2) == 0;} int operator!=(const Date& d2) const {return compare(d2) != 0) // I/O operators friend ostream& operator<<(ostream&, const Date&); friend istream& operator>>(istream&, Date&); }; // End of File
Listing 10 Implements Date stream I/O functions
#include <iostream.h> #include "date7.h" ostream& operator<<(ostream& os, const Date& d) { os << d.month << '/' << d.day << '/' << d.year; return os; } istream& operator>>(istream& is, Date& d) { char slash; is >> d.month >> slash >> d.day >> slash >> d.year; return is; } // End of File
Listing 11 Illustrates stream I/O of Date objects
// tdate7.cpp: #include <iostream.h> #include "date7.h" main() { Date d1, d2; cout << "Enter a date: "; cin >> d1; cout << "Enter another date: "; cin >> d2; cout << "d1 - d2 = "<< d1 - d2 << endl; cout << "d2 - d1 = "<< d2 - d1 << endl; return 0; } /* OUTPUT Enter a date: 10/1/1951 Enter another date: 5/1/1954 d1 - d2 = -7/0/-2 d2 - d1 = 7/0/2 */ // End of File
Listing 12 Defines static members
// date8.h // Forward declarations class istream; class ostream; class Date { int month; int day; int year; static int dtab[2][13]; public: // Constructors Date(); // Get today's date (see .cpp file) Date(int m, int d, int y) {month = m; day = d; year = y;} // Accessor Functions int get_month() const {return month;} int get_day() const {return day;} int get_year() const {return year;} Date operator-(const Date& d2) const; Date& operator-() {month = -month; day = -day; year = -year; return *this;} int compare(const Date&) const; // Relational operators int operator<(const Date& d2) const {return compare{d2) < 0;} int operator<=(const Date& d2) const {return compare(d2) <= 0;} int operator>(const Date& d2) const {return compare(d2) > 0;} int operator>=(const Date& d2) const {return compare(d2) >= 0;} int operator==(const Date& d2) const {return compare(d2) == 0;} int operator!=(const Date& d2) const {return compare(d2) != 0;} // Stream I/O operators friend ostream& operator<<(ostream&, const Date&); friend istream& operator>>(istream&, Date&); static int isleap(int y) {return y%4 == 0 && y%100 != 0 || y%400 == 0;} }; // End of File
Listing 13 Final implementation of the Date class
// date8.cpp #include <iostream.h> #include <time.h> #include <assert.h> #include "date8.h" // Must initialize statics outside the class definition int Date::dtab[2][13] = { {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} }; Date Date::operator-(const Date& d2) const { int months, days, years, prev_month, order; const Date * first, * last; // Must know which date is first if (compare(d2) <= 0) { // this <= d2 order= -1; first = this; last = &d2; } else { order = 1; first = &d2; last = this; } // Compute the interval; first <= last years = last->year - first->year; months = last->month - first->month; days = last->day - first->day; assert(years >= 0 && months >= 0 && days >= 0); // Do obvious corrections (days before months!) // // This is a loop in case the previous month is // February, and days < -28. prev_month = last->month - 1; while (days < 0) { // Borrow from the previous month if (prev_month == 0) prev_month = 12; -months; days += dtab[isleap(last->year)][prev_month-]; } if (months < 0) { // Borrow from the previous year -years; months += 12; } // Return a date object with the interval if (order == 1) return Date(-months,-days,-years); else return Date(months,days,years); } int Date::compare(const Date& d2) const { int months, days, years, order; years = year - d2.year; months = month - d2.month; days = day - d2.day; // return <0, 0, or >0, like strcmp() if (years == 0 && months == 0 && days == 0) return 0; else if (years == 0 && months == 0) return days; else if (years == 0) return months; else return years; } ostream& operator<<(ostream& os, const Date& d) { os << d.month << '/' << d.day << '/' << d.year; return os; } istream& operator>>(istream& is, Date& d) { char slash; is >> d.month >> slash >> d.day >> slash >> d.year; return is; } Date::Date() ( // Get today's date time_t tval = time(0); struct tm *tmp= localtime(&tval); month = tmp->tm_mon+1; day = tmp->tm_mday; year = tmp->tm_year + 1900; } // End of File
Listing 14 Gets today's date
// tdate8.cpp: #include <iostream.h> #include "date8.h" main() { Date today, d2; cout << "Today's date is "<< today << endl; cout << "Enter another date: "; cin >> d2; cout << "today - d2 = "<< today - d2 << endl; cout << "d2 - today = "<< d2 - today << endl; return 0; } /* OUTPUT Today's date is 12/12/1992 Enter another date: 1/1/1970 today - d2 = 11/11/22 d2 - today = -11/-11/-22 */ // End of File