Date Class: solution
You were asked to write a class that represents a date and give it specific functionality.
Observations:
  A Date class should represent a date only, not a time. Dates can be entered 
  and viewed in different formats, but the internal method used to represent them 
  should be independent of the particular format.
We could use three components to represent day, month and year internally, but this may make some calculations difficult.
A look at the UNIX system call ctime(3) and the definition of 
  struct tm, the basic date/time representation on my (BSD based) 
  UNIX system only handles years from 1900. This might be reasonable for a structure 
  to store the current date and time, but if we are dealing with a date in general 
  we might want to store dates before 1900 (think of a database of historical 
  documents from the first fleet, or artifacts from ancient Egypt, for example).
A common date system used by astronomers is known as a Julian Date. A Julian day begins at noon of the calendar date. Julian day 0 was 1 January, 4713 B.C.! (4713B.C. = -4712)
There is no year 0 as a calendar date — the year after 1 B.C. was 1 A.D. 
  The Gregorian calendar was adopted on 15 October 1582. There is a gap of ten 
  days between 4 Oct 1582 and 15 Oct 1582, meaning that the 15th of October was 
  directly following the 4th of October (Pope Gregor forced this in order to achieve 
  better agreement between the civil and the astronomical calendar). If we use 
  a long to represent the Julian day internally, we can represent 
  dates from 1/1/4713 B.C. up to 31/12/31766 A.D.
For further information on Julian days and some code fragments to deal with 
  conversion, see:
  Press, W.H. et. al. (1988) Numerical Recipes in C (2nd Ed.), Cambridge 
  U.P., p. 11. (Copies available from the library and bookshop). You may also 
  find this 
  web site helpful. These references details on how to convert from Julian 
  Dates to Calendar Dates and back.
The question asked for the Date class to be capable of a number of functions. So let's look at the basic class declaration:
 
  class Date {
    public:
    // types for year, month and day
    typedef short year_t;
    typedef unsigned short month_t;
    typedef unsigned short day_t;  
    typedef unsigned short week_t;
   // constructors
   Date();  // default constructor
   Date(year_t year, month_t month, day_t day); // e.g. Date(2005,3,28);
   Date( const Date& theDate );
      
    // Assignment.
    Date& operator=( Date& theDate );
      
    // Date component accessors.
    year_t year() const;
    month_t month() const;
    day_t day() const;
    week_t weekOfTheYear() const;
    day_t dayOfTheYear() const;
    day_t dayOfTheWeek() const;
    long julianDay() const;
    // setter methods
    bool setDate(year_t year, month_t month, day_t day);  // to change the date returns false for illegal dates
    static Date today();  // change the date to today
    // Testing.
    bool isLeapYear() const;
   
    // printing to a stream
    void print(ostream& stream ) const;
    string toString() const;
 private:
    long myDate; // stores the date a a Julian date
};
 
There are several points to consider. First, what about errors? It's possible 
  to initialise a Date with numbers that don't represent proper dates, 
  e.g. Date d(2001,2,31). Constructors can't return values so what 
  should we do?
The best thing to do would be to throw an exception - a topic covered 
  in a latter lecture. 
  For the time being it would be satisfactory to print an error message to cerr. 
  Clearly we also will need support methods to check valid numbers for day, month 
  and year — since these might need to be used without creating a Date object 
  it would be best to define them as static to the class, e.g.:
  class Date {
   public:
	.
	.
	.
    static bool isYear( year_t year );
    static bool isMonth( month_t month );
    static bool isDayInMonth( year_t year, month_t month, day_t day);
	static bool isLeapYear( year_t year );
	.
	.
	.
};	
  
Static methods are global to all objects of a given class; they cannot access individual objects directly, but they can be called before object initialisation. They can also be accessed without the need to create an object of that class, e.g.:
  Date::year_t aYear;
  cout << "Enter your year of birth" << endl;
  cin >> aYear;
  if (! Date::isYear(aYear) ) {
  	cout << "That's not a proper year!" << endl;
	exit(-1);
  } else {
   Date d(aYear,1,1);
  }
  
Implementation:
  Not all the implementation will be covered here, but let's look at 
  a few things — first constructors. What Date should the default constructor 
  initialise to? We could define a default date, but what should it be? Some UNIX 
  systems use 1 January 1970 at their default. Another option might be to make 
  the default today, but this involves extra work and many default constructed 
  Date objects may be initialised shortly after construction to a new value. So 
  for efficiency we should make the default date a constant:
  	// default Julian Day is 1 January, 1970
	static const long defaultJulianDay = 2440588L;
	
	// Constructor defaults to the value of 'defaultJulianDay'
	Date::Date() : myDate( defaultJulianDay ) {
 	}
The other constructors can be handled using the setDate methods 
  defined in the class.
Here's the assignment operator:
// Assign myself from the supplied date
Date&
Date::operator=( const Date& date )
{
	myDate = date.myDate;
	return *this;
}
Check for leap years:
/* static */ bool
Date::isLeapYear( year_t year )     
{
  // Invalid years can not be leap years.
  if ( !isYear( year ) ) 
    return false;
  // Adjust for BC
  if (year < 0)
    ++year;
  // Leap years are divisible by 4, years ending in 00, which
  // are normal unless divisible by 400.
  return (year % 100) ? (year % 4 == 0) : (year % 400 == 0);
}
If we have a method julianDay() that returns the Julian day representation then we can work out the day of the year:
day_t
Date::dayOfTheYear() const
{
  return (day_t)(julianDay() - Date( year(), 1, 1 ).julianDay() );
}
Formatting:
  As an option, you were asked to provide formatted output. Some C system 
  calls let you do this to an extent, but we are still faced with the problem 
  of dates before 1900. Also, what if we change languages? A better solution might 
  be to create a separateDateFormat class that will return strings 
  and formats for output. DateFormat could also be an abstract base 
  class, allowing for multiple language support. e.g.
  DateFormat * ausfmt = new AustralianDateFormat;
  DateFormat * usfmt = new USDateFormat;
  ausfmt->useLongFormat();
  ausfmt->showDayOfTheWeek();
  usfmt->setSeperator(":");
  Date d(7,8,2005);
  d.print(cout, fmt); // prints "Wednesday, 7 August 2005"
  d.print(cout, usfmt); // prints "8:7:2005"
  
Summary:
  We could add many extra classes to represent a time period (microseconds to 
  years) so we could add time periods to dates and get a new date:
Date now, in50years
  TimePeriod p;
  now.today(); // set now to today's date
  p.setYears(50); // a time period of 50 years
  in50years = now + p;
  cout << "In 50 years from today it will be " << in50years << endl; 
The Date class would be better with more overloaded operators, 
  including increment, decrement and comparison.
We could also add other classes to represent day in a year or things like "the first Tuesday in November", which might be useful for calendar and reminder programs.
What looked like a simple task (represent a date) can actually turn out to be pretty complex! The more you want to do the task well, the more classes and support is needed (error handling for example). Suddenly your simple "kit bag" of basic classes is looking quite complex...
At some point, these simple "support" classes become a whole framework for building applications. Many commercial and public domain frameworks are available for a variety of purposes, most commonly for building whole applications.