home *** CD-ROM | disk | FTP | other *** search
/ PC Media 7 / PC MEDIA CD07.iso / share / prog / cm / cmdate.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1994-09-06  |  8.8 KB  |  381 lines

  1. // CmDate.cpp
  2. // -----------------------------------------------------------------
  3. // Compendium - C++ Container Class Library
  4. // Copyright (C) 1992-1994, Glenn M. Poorman, All rights reserved
  5. // -----------------------------------------------------------------
  6. // Date class implementation.
  7. // -----------------------------------------------------------------
  8.  
  9. #include <time.h>
  10. #include <cm/include/cmstring.h>
  11. #include <cm/include/cmdate.h>
  12. #include <stdio.h>
  13.  
  14.  
  15. // Static array definitions.
  16.  
  17. static const unsigned char daysInMonth[12] =
  18.        {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
  19.  
  20. static const unsigned firstDayOfEachMonth[12] =
  21.        {1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335};
  22.  
  23. static const char* monthNames[12] =
  24.        {"January", "February", "March",     "April",   "May",      "June",
  25.         "July",    "August",   "September", "October", "November", "December"};
  26.  
  27. static const char* ucMonthNames[12] =
  28.        {"JANUARY", "FEBRUARY", "MARCH",     "APRIL",   "MAY",      "JUNE",
  29.         "JULY",    "AUGUST",   "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER"};
  30.  
  31. static const char* weekDayNames[7] =
  32.        {"Monday",   "Tuesday", "Wednesday", "Thursday", "Friday",
  33.         "Saturday", "Sunday"};
  34.  
  35. static const char* ucWeekDayNames[7] =
  36.        {"MONDAY",   "TUESDAY",  "WEDNESDAY", "THURSDAY", "FRIDAY",
  37.         "SATURDAY", "SUNDAY" };
  38.  
  39. // Initialize the date display style.
  40. int CmDate::_displayStyle = CmDate::NORMAL;
  41.  
  42.  
  43. // "CmDate" is the default date constructor.
  44. //
  45. CmDate::CmDate()
  46. {
  47.   time_t     clk = time(NULL);
  48.   struct tm *now = localtime(&clk);
  49.  
  50.   _julnum = julDay(now->tm_mon+1, now->tm_mday, now->tm_year + 1900);
  51. }
  52.  
  53.  
  54. // "CmDate" constructs a date from the specified day of the year and
  55. // year number.
  56. //
  57. CmDate::CmDate(unsigned day, unsigned year)
  58. {
  59.   if (year) _julnum = julDay(12, 13, year-1) + (unsigned long) day;
  60.   else      _julnum = ((unsigned long) 2415386L) + (unsigned long) day;
  61. }
  62.  
  63.  
  64. // "CmDate" constructs a date from the specified day number, month name,
  65. // and year number.
  66. //
  67. CmDate::CmDate(unsigned day, const char* monthName, unsigned year)
  68. {
  69.   _julnum = julDay(indexOfMonth(monthName), day, year);
  70. }
  71.  
  72. // "CmDate" constructs a date from the specified day number, month number,
  73. // and year number.
  74. //
  75. CmDate::CmDate(unsigned day, unsigned month, unsigned year)
  76. {
  77.   _julnum = julDay(month, day, year);
  78. }
  79.  
  80.  
  81. // "day" returns the day of year number.
  82. //
  83. unsigned CmDate::day() const
  84. {
  85.   return _julnum - julDay(12, 31, year()-1);
  86. }
  87.  
  88.  
  89. // "dayOfMonth" returns the day of month number.
  90. //
  91. unsigned CmDate::dayOfMonth() const
  92. {
  93.   unsigned m, d, y;
  94.   mdy(m, d, y);
  95.   return d;
  96. }
  97.  
  98.  
  99. // "firstDayOfMonth" returns the day of year number corresponding
  100. // to the first of this month.
  101. //
  102. unsigned CmDate::firstDayOfMonth() const
  103. {
  104.   return firstDayOfMonth(month());
  105. }
  106.  
  107.  
  108. // "firstDayOfMonth" returns the day of year number corresponding
  109. // to the first of the specified month.
  110. //
  111. unsigned CmDate::firstDayOfMonth(unsigned month) const
  112. {
  113.   if (month <= 0 || month > 12) return 0;
  114.   unsigned firstDay = firstDayOfEachMonth[month-1];
  115.   if (month > 2 && leap()) firstDay++;
  116.   return firstDay;
  117. }
  118.  
  119.  
  120. // "month" returns the month number.
  121. //
  122. unsigned CmDate::month() const
  123. {
  124.   unsigned m, d, y;
  125.   mdy(m, d, y);
  126.   return m;
  127. }
  128.  
  129.  
  130. // "nameOfDay" returns the name of the day for this date.
  131. //
  132. const char* CmDate::nameOfDay() const
  133. {
  134.   return dayName(weekDay());
  135. }
  136.  
  137.  
  138. // "nameOfMonth" returns the name of the month for this date.
  139. //
  140. const char* CmDate::nameOfMonth() const
  141. {
  142.   return monthName(month());
  143. }
  144.  
  145.  
  146. // "weekDay" returns the day of the week number.
  147. //
  148. unsigned CmDate::weekDay() const
  149. {
  150.   return _julnum % 7 + 1;
  151. }
  152.  
  153.  
  154. // "year" returns the year for this date.
  155. //
  156. unsigned CmDate::year() const
  157. {
  158.   unsigned m, d, y;
  159.   mdy(m, d, y);
  160.   return y;
  161. }
  162.  
  163.  
  164. // "leap" returns TRUE if this year is a leap year.
  165. //
  166. Bool CmDate::leap() const
  167. {
  168.   return leapYear(year());
  169. }
  170.  
  171.  
  172. // "previous" returns the date of the most recent day with the
  173. // specified name.
  174. //
  175. CmDate CmDate::previous(const char* dayName) const
  176. {
  177.   return previous(dayOfWeek(dayName));
  178. }
  179.  
  180.  
  181. // "previous" returns the date of the most recent day with the
  182. // specified number.
  183. //
  184. CmDate CmDate::previous(unsigned dayNum) const
  185. {
  186.   if (dayNum <= 0 || dayNum > 7) return CmDate();
  187.   unsigned delta = (weekDay() + 6 - dayNum) % 7 + 1;
  188.   return CmDate(_julnum - delta);
  189. }
  190.  
  191.  
  192. // "makeCurrent" makes this date the current date.
  193. //
  194. void CmDate::makeCurrent()
  195. {
  196.   time_t     clk = time(NULL);
  197.   struct tm *now = localtime(&clk);
  198.  
  199.   _julnum = julDay(now->tm_mon+1, now->tm_mday, now->tm_year + 1900);
  200. }
  201.  
  202.  
  203. // "isEqual" compares this date with the specified date.
  204. //
  205. Bool CmDate::isEqual(CmObject* pObj) const
  206. {
  207.   if (!pObj->isA("CmDate")) return CmObject::isEqual(pObj);
  208.   return (((CmDate*) pObj)->_julnum == _julnum);
  209. }
  210.  
  211.  
  212. // "compare" compares this date with the specified date.
  213. //
  214. int CmDate::compare(CmObject* pObj) const
  215. {
  216.   if (!pObj->isA("CmDate")) return CmObject::compare(pObj);
  217.   unsigned long jn = ((CmDate*) pObj)->_julnum;
  218.   return (_julnum == jn ? 0 : (_julnum > jn ? 1 : -1));
  219. }
  220.  
  221.  
  222. // "hash" hashes this date returning the hash value.
  223. //
  224. unsigned CmDate::hash(unsigned m) const
  225. {
  226.   return (unsigned) (_julnum % (unsigned long) m);
  227. }
  228.  
  229.  
  230. // "printOn" prints this date on the specified stream.
  231. //
  232. void CmDate::printOn(ostream& os) const
  233. {
  234.   switch (CmDate::_displayStyle)
  235.   {
  236.     case NORMAL:
  237.       os << nameOfMonth() << ' ' << dayOfMonth() << ", " << year();
  238.       break;
  239.  
  240.     case NUMBERS:
  241.       os << month() << '/' << dayOfMonth() << '/' << (year() % 100);
  242.       break;
  243.   }
  244. }
  245.  
  246.  
  247. // "write" writes the date to the specified reserve binary file.
  248. //
  249. Bool CmDate::write(CmReserveFile& file) const
  250. {
  251.   return file.write(_julnum);
  252. }
  253.  
  254.  
  255. // "read" reads the date from the specified reserve binary file.
  256. //
  257. Bool CmDate::read(CmReserveFile& file)
  258. {
  259.   return file.read(_julnum);
  260. }
  261.  
  262.  
  263. // "julDay" converts a Gregorian calendar date to the corresponding Julian
  264. // day number.  Algorithm 199 from Communications of the ACM, Volume 6,
  265. // No. 8, (August, 1963), p. 444.  Gregorian calendar started on September
  266. // 14, 1752.  This function is not valid before that.
  267. //
  268. unsigned long CmDate::julDay(unsigned m, unsigned d, unsigned y)
  269. {
  270.   unsigned long c, ya;
  271.   if(y <= 99) y += 1900;
  272.   if(!dayWithinMonth(m, d, y)) return (unsigned long) 0;
  273.  
  274.   if (m > 2)
  275.     m -= 3;
  276.   else
  277.   {
  278.     m += 9;
  279.     y--;
  280.   }
  281.   c  = y / 100;
  282.   ya = y - 100 * c;
  283.   return ((146097*c) >> 2) + ((1461*ya) >> 2) + (153*m + 2) / 5 + d + 1721119;
  284. }
  285.  
  286.  
  287. // "dayOfWeek" returns the day of week number for the specified day.
  288. //
  289. unsigned CmDate::dayOfWeek(const char* dayName)
  290. {
  291.   CmString str(dayName);
  292.   str.toUpper();
  293.   int ii = 7;
  294.   while (ii--)
  295.   {
  296.     if (str == ucWeekDayNames[ii]) break;
  297.   }
  298.   return (unsigned) ii + 1;
  299. }
  300.  
  301.  
  302. // "dayWithinMonth" returns the day of month number for the specified
  303. // date.
  304. //
  305. Bool CmDate::dayWithinMonth(unsigned month, unsigned day, unsigned year)
  306. {
  307.   if (day <= 0 || !(month >= 1 && month <= 12)) return FALSE;
  308.   unsigned d = daysInMonth[month - 1];
  309.   if (leapYear(year) && month == 2) d++;
  310.   return day <= d;
  311. }
  312.  
  313.  
  314. // "leapYear" returns TRUE if the specified year is a leap year.
  315. //
  316. Bool CmDate::leapYear(unsigned y)
  317. {
  318.   return ((y & 3) == 0 && y % 100 != 0 || y % 400 == 0);
  319. }
  320.  
  321.  
  322. // "indexOfMonth" finds the month number for the specified month.
  323. //
  324. unsigned CmDate::indexOfMonth(const char* nameOfMonth)
  325. {
  326.   CmString str(nameOfMonth);
  327.   str.toUpper();
  328.   int ii = 12;
  329.   while (ii--)
  330.   {
  331.     if (str == ucMonthNames[ii]) break;
  332.   }
  333.   return (unsigned) ii + 1;
  334. }
  335.  
  336.  
  337. // "dayName" returns the day name from the specified day of week
  338. // number.
  339. //
  340. const char* CmDate::dayName(unsigned wn)
  341. {
  342.   return (wn >= 1 && wn <= 7) ? weekDayNames[wn-1] : 0;
  343. }
  344.  
  345.  
  346. // "monthName" returns the month name from the specified month number.
  347. //
  348. const char* CmDate::monthName(unsigned mn)
  349. {
  350.   return (mn >= 1 && mn <= 12) ? monthNames[mn-1] : 0;
  351. }
  352.  
  353.  
  354. // "mdy" converts a Julian day number to it's corresponding Gregorian
  355. // calendar date.  Algorithm 199 from Communications of the ACM, Volume
  356. // 6, No. 8, (August, 1963), p. 444.  Gregorian calendar started on
  357. // September 14, 1752.  This function is not valid before that.
  358. //
  359. void CmDate::mdy(unsigned& m, unsigned& D, unsigned& y) const
  360. {
  361.   unsigned long d;
  362.   unsigned long j = _julnum - 1721119;
  363.   y = (unsigned) (((j << 2) - 1) / 146097);
  364.   j = (j << 2) - 1 - 146097 * y;
  365.   d = (j >> 2);
  366.   j = ((d << 2) + 3) / 1461;
  367.   d = (d << 2) + 3 - 1461 * j;
  368.   d = (d + 4) >> 2;
  369.   m = (unsigned)(5 * d - 3) / 153;
  370.   d = 5 * d - 3 - 153 * m;
  371.   D = (unsigned) ((d + 5) / 5);
  372.   y = (unsigned) (100 * y + j);
  373.   if (m < 10)
  374.     m += 3;
  375.   else
  376.   {
  377.     m -= 9;
  378.     y++;
  379.   }
  380. }
  381.