home *** CD-ROM | disk | FTP | other *** search
- // CmDate.cpp
- // -----------------------------------------------------------------
- // Compendium - C++ Container Class Library
- // Copyright (C) 1992-1994, Glenn M. Poorman, All rights reserved
- // -----------------------------------------------------------------
- // Date class implementation.
- // -----------------------------------------------------------------
-
- #include <time.h>
- #include <cm/include/cmstring.h>
- #include <cm/include/cmdate.h>
- #include <stdio.h>
-
-
- // Static array definitions.
-
- static const unsigned char daysInMonth[12] =
- {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
-
- static const unsigned firstDayOfEachMonth[12] =
- {1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335};
-
- static const char* monthNames[12] =
- {"January", "February", "March", "April", "May", "June",
- "July", "August", "September", "October", "November", "December"};
-
- static const char* ucMonthNames[12] =
- {"JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE",
- "JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER"};
-
- static const char* weekDayNames[7] =
- {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
- "Saturday", "Sunday"};
-
- static const char* ucWeekDayNames[7] =
- {"MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY",
- "SATURDAY", "SUNDAY" };
-
- // Initialize the date display style.
- int CmDate::_displayStyle = CmDate::NORMAL;
-
-
- // "CmDate" is the default date constructor.
- //
- CmDate::CmDate()
- {
- time_t clk = time(NULL);
- struct tm *now = localtime(&clk);
-
- _julnum = julDay(now->tm_mon+1, now->tm_mday, now->tm_year + 1900);
- }
-
-
- // "CmDate" constructs a date from the specified day of the year and
- // year number.
- //
- CmDate::CmDate(unsigned day, unsigned year)
- {
- if (year) _julnum = julDay(12, 13, year-1) + (unsigned long) day;
- else _julnum = ((unsigned long) 2415386L) + (unsigned long) day;
- }
-
-
- // "CmDate" constructs a date from the specified day number, month name,
- // and year number.
- //
- CmDate::CmDate(unsigned day, const char* monthName, unsigned year)
- {
- _julnum = julDay(indexOfMonth(monthName), day, year);
- }
-
- // "CmDate" constructs a date from the specified day number, month number,
- // and year number.
- //
- CmDate::CmDate(unsigned day, unsigned month, unsigned year)
- {
- _julnum = julDay(month, day, year);
- }
-
-
- // "day" returns the day of year number.
- //
- unsigned CmDate::day() const
- {
- return _julnum - julDay(12, 31, year()-1);
- }
-
-
- // "dayOfMonth" returns the day of month number.
- //
- unsigned CmDate::dayOfMonth() const
- {
- unsigned m, d, y;
- mdy(m, d, y);
- return d;
- }
-
-
- // "firstDayOfMonth" returns the day of year number corresponding
- // to the first of this month.
- //
- unsigned CmDate::firstDayOfMonth() const
- {
- return firstDayOfMonth(month());
- }
-
-
- // "firstDayOfMonth" returns the day of year number corresponding
- // to the first of the specified month.
- //
- unsigned CmDate::firstDayOfMonth(unsigned month) const
- {
- if (month <= 0 || month > 12) return 0;
- unsigned firstDay = firstDayOfEachMonth[month-1];
- if (month > 2 && leap()) firstDay++;
- return firstDay;
- }
-
-
- // "month" returns the month number.
- //
- unsigned CmDate::month() const
- {
- unsigned m, d, y;
- mdy(m, d, y);
- return m;
- }
-
-
- // "nameOfDay" returns the name of the day for this date.
- //
- const char* CmDate::nameOfDay() const
- {
- return dayName(weekDay());
- }
-
-
- // "nameOfMonth" returns the name of the month for this date.
- //
- const char* CmDate::nameOfMonth() const
- {
- return monthName(month());
- }
-
-
- // "weekDay" returns the day of the week number.
- //
- unsigned CmDate::weekDay() const
- {
- return _julnum % 7 + 1;
- }
-
-
- // "year" returns the year for this date.
- //
- unsigned CmDate::year() const
- {
- unsigned m, d, y;
- mdy(m, d, y);
- return y;
- }
-
-
- // "leap" returns TRUE if this year is a leap year.
- //
- Bool CmDate::leap() const
- {
- return leapYear(year());
- }
-
-
- // "previous" returns the date of the most recent day with the
- // specified name.
- //
- CmDate CmDate::previous(const char* dayName) const
- {
- return previous(dayOfWeek(dayName));
- }
-
-
- // "previous" returns the date of the most recent day with the
- // specified number.
- //
- CmDate CmDate::previous(unsigned dayNum) const
- {
- if (dayNum <= 0 || dayNum > 7) return CmDate();
- unsigned delta = (weekDay() + 6 - dayNum) % 7 + 1;
- return CmDate(_julnum - delta);
- }
-
-
- // "makeCurrent" makes this date the current date.
- //
- void CmDate::makeCurrent()
- {
- time_t clk = time(NULL);
- struct tm *now = localtime(&clk);
-
- _julnum = julDay(now->tm_mon+1, now->tm_mday, now->tm_year + 1900);
- }
-
-
- // "isEqual" compares this date with the specified date.
- //
- Bool CmDate::isEqual(CmObject* pObj) const
- {
- if (!pObj->isA("CmDate")) return CmObject::isEqual(pObj);
- return (((CmDate*) pObj)->_julnum == _julnum);
- }
-
-
- // "compare" compares this date with the specified date.
- //
- int CmDate::compare(CmObject* pObj) const
- {
- if (!pObj->isA("CmDate")) return CmObject::compare(pObj);
- unsigned long jn = ((CmDate*) pObj)->_julnum;
- return (_julnum == jn ? 0 : (_julnum > jn ? 1 : -1));
- }
-
-
- // "hash" hashes this date returning the hash value.
- //
- unsigned CmDate::hash(unsigned m) const
- {
- return (unsigned) (_julnum % (unsigned long) m);
- }
-
-
- // "printOn" prints this date on the specified stream.
- //
- void CmDate::printOn(ostream& os) const
- {
- switch (CmDate::_displayStyle)
- {
- case NORMAL:
- os << nameOfMonth() << ' ' << dayOfMonth() << ", " << year();
- break;
-
- case NUMBERS:
- os << month() << '/' << dayOfMonth() << '/' << (year() % 100);
- break;
- }
- }
-
-
- // "write" writes the date to the specified reserve binary file.
- //
- Bool CmDate::write(CmReserveFile& file) const
- {
- return file.write(_julnum);
- }
-
-
- // "read" reads the date from the specified reserve binary file.
- //
- Bool CmDate::read(CmReserveFile& file)
- {
- return file.read(_julnum);
- }
-
-
- // "julDay" converts a Gregorian calendar date to the corresponding Julian
- // day number. Algorithm 199 from Communications of the ACM, Volume 6,
- // No. 8, (August, 1963), p. 444. Gregorian calendar started on September
- // 14, 1752. This function is not valid before that.
- //
- unsigned long CmDate::julDay(unsigned m, unsigned d, unsigned y)
- {
- unsigned long c, ya;
- if(y <= 99) y += 1900;
- if(!dayWithinMonth(m, d, y)) return (unsigned long) 0;
-
- if (m > 2)
- m -= 3;
- else
- {
- m += 9;
- y--;
- }
- c = y / 100;
- ya = y - 100 * c;
- return ((146097*c) >> 2) + ((1461*ya) >> 2) + (153*m + 2) / 5 + d + 1721119;
- }
-
-
- // "dayOfWeek" returns the day of week number for the specified day.
- //
- unsigned CmDate::dayOfWeek(const char* dayName)
- {
- CmString str(dayName);
- str.toUpper();
- int ii = 7;
- while (ii--)
- {
- if (str == ucWeekDayNames[ii]) break;
- }
- return (unsigned) ii + 1;
- }
-
-
- // "dayWithinMonth" returns the day of month number for the specified
- // date.
- //
- Bool CmDate::dayWithinMonth(unsigned month, unsigned day, unsigned year)
- {
- if (day <= 0 || !(month >= 1 && month <= 12)) return FALSE;
- unsigned d = daysInMonth[month - 1];
- if (leapYear(year) && month == 2) d++;
- return day <= d;
- }
-
-
- // "leapYear" returns TRUE if the specified year is a leap year.
- //
- Bool CmDate::leapYear(unsigned y)
- {
- return ((y & 3) == 0 && y % 100 != 0 || y % 400 == 0);
- }
-
-
- // "indexOfMonth" finds the month number for the specified month.
- //
- unsigned CmDate::indexOfMonth(const char* nameOfMonth)
- {
- CmString str(nameOfMonth);
- str.toUpper();
- int ii = 12;
- while (ii--)
- {
- if (str == ucMonthNames[ii]) break;
- }
- return (unsigned) ii + 1;
- }
-
-
- // "dayName" returns the day name from the specified day of week
- // number.
- //
- const char* CmDate::dayName(unsigned wn)
- {
- return (wn >= 1 && wn <= 7) ? weekDayNames[wn-1] : 0;
- }
-
-
- // "monthName" returns the month name from the specified month number.
- //
- const char* CmDate::monthName(unsigned mn)
- {
- return (mn >= 1 && mn <= 12) ? monthNames[mn-1] : 0;
- }
-
-
- // "mdy" converts a Julian day number to it's corresponding Gregorian
- // calendar date. Algorithm 199 from Communications of the ACM, Volume
- // 6, No. 8, (August, 1963), p. 444. Gregorian calendar started on
- // September 14, 1752. This function is not valid before that.
- //
- void CmDate::mdy(unsigned& m, unsigned& D, unsigned& y) const
- {
- unsigned long d;
- unsigned long j = _julnum - 1721119;
- y = (unsigned) (((j << 2) - 1) / 146097);
- j = (j << 2) - 1 - 146097 * y;
- d = (j >> 2);
- j = ((d << 2) + 3) / 1461;
- d = (d << 2) + 3 - 1461 * j;
- d = (d + 4) >> 2;
- m = (unsigned)(5 * d - 3) / 153;
- d = 5 * d - 3 - 153 * m;
- D = (unsigned) ((d + 5) / 5);
- y = (unsigned) (100 * y + j);
- if (m < 10)
- m += 3;
- else
- {
- m -= 9;
- y++;
- }
- }
-