home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / yacl-012.zip / base / date.cxx < prev    next >
C/C++ Source or Header  |  1995-04-08  |  21KB  |  939 lines

  1.  
  2.  
  3.  
  4.  
  5. /*
  6.  *
  7.  *          Copyright (C) 1994, M. A. Sridhar
  8.  *  
  9.  *
  10.  *     This software is Copyright M. A. Sridhar, 1994. You are free
  11.  *     to copy, modify or distribute this software  as you see fit,
  12.  *     and to use  it  for  any  purpose, provided   this copyright
  13.  *     notice and the following   disclaimer are included  with all
  14.  *     copies.
  15.  *
  16.  *                        DISCLAIMER
  17.  *
  18.  *     The author makes no warranties, either expressed or implied,
  19.  *     with respect  to  this  software, its  quality, performance,
  20.  *     merchantability, or fitness for any particular purpose. This
  21.  *     software is distributed  AS IS.  The  user of this  software
  22.  *     assumes all risks  as to its quality  and performance. In no
  23.  *     event shall the author be liable for any direct, indirect or
  24.  *     consequential damages, even if the  author has been  advised
  25.  *     as to the possibility of such damages.
  26.  *
  27.  */
  28.  
  29.  
  30.  
  31. //
  32. // A class representing a particular date. Only dates on or after
  33. // Sep 14, 1752 are permitted.
  34. //
  35. // Author: M. A. Sridhar
  36. // Date:   November 9th, 1992
  37. // Modified Mar 3, 1995
  38.  
  39.  
  40. #ifdef __GNUC__
  41. #pragma implementation
  42. #endif
  43.  
  44.  
  45. #include "base/date.h"
  46. #include "base/error.h"
  47. #include "base/bytstrng.h"
  48. #include "base/stream.h"
  49.  
  50. #include <iostream.h>
  51. #include <ctype.h>
  52.  
  53. #include <time.h>
  54. #ifdef MSDOS
  55. #include <dos.h>
  56. #endif
  57.  
  58.  
  59. // A few static (local) helper functions: IntoDays and IntoYMD
  60. struct DateStruct {
  61.     short y,d;
  62.     CL_Date::MonthEnum m;
  63. };
  64.  
  65. static DateStruct IntoYMD (long num_days);
  66. static long       IntoDays (const DateStruct&);
  67.  
  68.  
  69.  
  70. CL_DEFINE_CLASS(CL_Date, _CL_Date_CLASSID);
  71.  
  72. //
  73. // ------------- Constructors and destructors ----------------------
  74. //
  75.  
  76. // Construct today's date
  77. CL_Date::CL_Date ()
  78. {
  79.     _days = 0;
  80. }
  81.  
  82.  
  83. /*---------------------------------------------------*/
  84.  
  85. // Construct the given date, assuming that:
  86. //        the year is given as 1992, not 92
  87. //        the month is indexed from 1 (e.g. January is month 1)
  88. CL_Date::CL_Date (short year, short month, short day)
  89. {
  90.     if (year < 1753) {
  91.         // CL_Error::Warning ("CL_Date constructor: invalid year %d", year);
  92.         _days = 0;
  93.         return;
  94.     }
  95.     if (!(month >= January && month <= December)) {
  96.         // CL_Error::Warning ("CL_Date constructor: invalid month %d", month);
  97.         _days = 0;
  98.         return;
  99.     }
  100.     if (day < 1 || day > DaysInMonth (month, year)) {
  101.         // CL_Error::Warning ("CL_Date constructor: invalid day %d", day);
  102.         _days = 0;
  103.         return;
  104.     }
  105.     
  106.     DateStruct dt;
  107.     dt.y = year;
  108.     dt.m = (MonthEnum) month;
  109.     dt.d = day;
  110.     _days = IntoDays (dt);
  111. }
  112.  
  113.  
  114. /*---------------------------------------------------*/
  115.  
  116.  
  117. // Construct the given date, assuming the month specified as a
  118. // string, e.g., "March". Assume case-sensitive comparison and
  119. // completely-specified month names (e.g. "Oct" is not allowed).
  120. CL_Date::CL_Date (short year, const char* month, short day)
  121. {
  122.     DateStruct dt;
  123.     dt.y = year;
  124.     dt.m = MonthNumber (month);
  125.     dt.d = day;
  126.     _days = IntoDays (dt);
  127. }
  128.  
  129.  
  130. /*---------------------------------------------------*/
  131.  
  132. // Construct a date from the given string containing the
  133. // representation in one of the allowed forms.
  134. CL_Date::CL_Date (const char* s)
  135. {
  136.     *this = CL_String(s);
  137. }
  138.  
  139. void CL_Date::operator= (const CL_String& s)
  140. {
  141.     if (!PrepareToChange())
  142.         return;
  143.     if (s.Size() == 0) {
  144.         _days = 0;
  145.         Notify ();
  146.         return;
  147.     }
  148.     long d = ParseAndConvert (s);
  149.     if (d < 0) {
  150.         _days = 0;
  151.         Notify ();
  152.         return;
  153.     }
  154.     _days = d;
  155.     Notify ();
  156. }
  157.  
  158.  
  159. long CL_Date::ParseAndConvert (const CL_String& s)
  160. {
  161.     CL_String fld[4];
  162.     DateStruct dt;
  163.  
  164.     if (s.Split (fld, 4, " ,") == 3) { // Date_American
  165.         fld[0].WordCapitalize ();
  166.         dt.m = MonthNumber (fld[0]);
  167.         short yr = (short) fld[2].AsLong();
  168.         dt.y = (yr >= 1900) ? yr : yr + 1900;
  169.         dt.d = (short) fld[1].AsLong();
  170.     }
  171.     else if (s.Split (fld, 4, "-") == 3) { // Date_Terse
  172.         fld[1].WordCapitalize ();
  173.         dt.m = MonthNumber (fld[1]);
  174.         short yr = (short) fld[2].AsLong();
  175.         dt.y = (yr >= 1900) ? yr : yr + 1900;
  176.         dt.d = (short) fld[0].AsLong();
  177.     }
  178.     else if (s.Split (fld, 4, "/") == 3) {// Date_Numbers
  179.         dt.m = (MonthEnum) fld[0].AsLong();
  180.         dt.d = (short) fld[1].AsLong();
  181.         short y = (short) fld[2].AsLong();
  182.         dt.y = y;
  183.         if (dt.y <= 99)
  184.             dt.y += 1900;
  185.     }
  186.     else {
  187.         // Assume that it's six digits, and try to parse it.
  188.         if (s.Size() != 6) {
  189.             return -1;
  190.         }
  191.         for (short i = 0; i < 6; i++) {
  192.             if (s[i] > '9' || s[i] < '0') {
  193.                 return -1;
  194.             }
  195.         }
  196.         short f1 = (s[0]-'0')*10 + s[1]-'0';
  197.         short f2 = (s[2]-'0')*10 + s[3]-'0';
  198.         short f3 = (s[4]-'0')*10 + s[5]-'0';
  199.         if (f1 >= 13) { // Assume yymmdd
  200.             dt.m = (MonthEnum) f2;
  201.             dt.y = f1 + 1900;
  202.             dt.d = f3;
  203.         }
  204.         else { // Assume mmddyy
  205.             dt.m = (MonthEnum) f1;
  206.             dt.y = f3 + 1900;
  207.             dt.d = f2;
  208.         }
  209.     }
  210.     if (dt.m <= 0 || dt.m >= 13) {
  211.         return -1;
  212.     }
  213.     if (dt.y <= 1899) {
  214.         return -1;
  215.     }
  216.     if (dt.d <= 0 || dt.d >= 32) {
  217.         return -1;
  218.     }
  219.     
  220.     return IntoDays (dt);
  221. }
  222.  
  223.     
  224. /*---------------------------------------------------*/
  225. // Copy constructor
  226. CL_Date::CL_Date (const CL_Date& d)
  227. {
  228.     _days = d._days;
  229. }
  230.  
  231.  
  232. /*---------------------------------------------------*/
  233.  
  234.  
  235. // Destructor
  236. CL_Date::~CL_Date ()
  237. {
  238. }
  239.  
  240.  
  241. /*---------------------------------------------------*/
  242.  
  243.  
  244. //
  245. // ---------------------- Access ----------------------------------
  246. //
  247.  
  248. // Return our year
  249. short CL_Date::Year() const
  250. {
  251.     return IntoYMD (_days).y;
  252. }
  253.  
  254.  
  255. /*---------------------------------------------------*/
  256.  
  257.  
  258.     
  259.  
  260. // Return our month
  261. CL_Date::MonthEnum CL_Date::Month () const
  262. {
  263.     return IntoYMD (_days).m;
  264. }
  265.  
  266. /*---------------------------------------------------*/
  267.  
  268.  
  269.  
  270. // Return our day of month
  271. short CL_Date::Day () const
  272. {
  273.     return IntoYMD (_days).d;
  274. }
  275.  
  276.  
  277. /*---------------------------------------------------*/
  278.  
  279.  
  280. // Return our day of week. Assume that 1 is for Sunday and 7 for
  281. // Saturday.
  282. CL_Date::WeekdayEnum CL_Date::DayOfWeek () const
  283. {
  284.     return (WeekdayEnum) (((1 + _days) % 7) + 1);
  285. }
  286.  
  287.  
  288.  
  289. /*---------------------------------------------------*/
  290.  
  291. short CL_Date::DaysInMonth () const
  292. {
  293.     DateStruct dt = IntoYMD (_days);
  294.     return DaysInMonth (dt.m, dt.y);
  295. }
  296.  
  297. /*---------------------------------------------------*/
  298.  
  299.  
  300. CL_String CL_Date::PrintString (DatePrintForm form) const
  301. {
  302.     if (_days == 0) // Invalid date
  303.         return "";
  304.     DateStruct dt = IntoYMD (_days);
  305.  
  306.     CL_String s, t;
  307.     switch (form) {
  308.  
  309.     case Date_American:
  310.         s =  MonthName (dt.m) + " "
  311.             + CL_String (dt.d) + ", "
  312.             + CL_String (dt.y);
  313.         return s;
  314.  
  315.     case Date_Terse:
  316.         t = CL_String ((long) dt.d, 2) + "-";
  317.         t = t + ShortMonthName (dt.m)  + "-";
  318.         t = t + CL_String ((long) dt.y);
  319.         return t;
  320.  
  321.     case Date_Numbers:
  322.         return CL_String ((long) dt.m, 2, '0') + "/"
  323.             + CL_String ((long) dt.d, 2, '0') + "/"
  324.             + CL_String ((long) dt.y - 1900L, 2);
  325.  
  326.     case Date_European:
  327.         return CL_String ((long) dt.d) + " "
  328.             + MonthName (dt.m) + " "
  329.             +  CL_String ((long) dt.y);
  330.  
  331.     case Date_EuroNumbers:
  332.         return CL_String ((long) dt.d, 2) + "/"
  333.             + CL_String ((long) dt.m, 2) + "/"
  334.             + CL_String ((long) dt.y - 1900L);
  335.  
  336.     default:
  337.         // CL_Error::Warning ("CL_Date::PrintString: Invalid form %d", form);
  338.         return "";
  339.     }
  340. }
  341.  
  342.  
  343.  
  344.  
  345.  
  346.  
  347. /*---------------------------------------------------*/
  348.  
  349.  
  350.  
  351. void CL_Date::FromStream (istream& s)
  352. {
  353.     CL_String rep;
  354.     char c;
  355.     long count = 0;
  356.     
  357.     char fill_char = s.fill ();
  358.     
  359.     while (s.get (c) && c == fill_char);
  360.     if (!s.good() || s.eof()) {
  361.         _days = 0;
  362.         return;
  363.     }
  364.     do {
  365.         if (isalnum (c) || c == '/' || c == '-') {
  366.             rep.Append (c);
  367.             count++;
  368.         }
  369.         else
  370.             break;
  371.     } while (s.get (c));
  372.  
  373.     long n = ParseAndConvert (rep);
  374.     if (n > 0) {
  375.         if (!s.eof ())
  376.             s.putback (c);
  377.         _days = n;
  378.     }
  379.     else {
  380.         s.seekg (s.tellg() - count, istream::cur);
  381.         _days = 0;
  382.     }
  383. }
  384.  
  385. /*---------------------------------------------------*/
  386.  
  387.  
  388.  
  389. // Tell if ours is a leap year
  390.  
  391. bool CL_Date::IsLeapYear () const
  392. {
  393.     return IsLeapYear (IntoYMD (_days).y);
  394. }
  395.  
  396.  
  397. /*---------------------------------------------------*/
  398.  
  399.  
  400. // Return the date of the next weekday given
  401.  
  402. CL_Date CL_Date::NextWeekday (const char* weekday_name) const
  403. {
  404.     short incr = DayNumber (weekday_name) - DayOfWeek();
  405.     return CL_Date (_days + ((incr >= 0) ? incr : incr + 7));
  406. }
  407.  
  408.  
  409. /*---------------------------------------------------*/
  410.  
  411.  
  412. // Return the date of the previous weekday given
  413.  
  414. CL_Date CL_Date::PreviousWeekday (const char* weekday_name) const
  415. {
  416.     short incr = DayNumber (weekday_name) - DayOfWeek();
  417.     return CL_Date (_days - ((incr > 0) ? 7 - incr : -incr));
  418. }
  419.  
  420.  
  421. CL_Date CL_Date::NextWeekday (WeekdayEnum weekday_num) const
  422. {
  423.     short incr = weekday_num - DayOfWeek();
  424.     return CL_Date (_days + ((incr >= 0) ? incr : incr + 7));
  425. }
  426.  
  427.  
  428. /*---------------------------------------------------*/
  429.  
  430.  
  431. // Return the date of the previous weekday given
  432.  
  433. CL_Date CL_Date::PreviousWeekday (WeekdayEnum weekday_num) const
  434. {
  435.     short incr = weekday_num - DayOfWeek();
  436.     return CL_Date (_days - ((incr > 0) ? 7 - incr : -incr));
  437. }
  438.  
  439.  
  440.  
  441. //
  442. // --------------------- Comparison ------------------------------
  443. //
  444.  
  445. bool CL_Date::operator<  (const CL_Date& d) const
  446. {
  447.     return _days < d._days;
  448. }
  449.  
  450.  
  451. /*---------------------------------------------------*/
  452.  
  453. bool CL_Date::operator<= (const CL_Date& d) const
  454. {
  455.     return _days <= d._days;
  456. }
  457.  
  458. /*---------------------------------------------------*/
  459.  
  460.  
  461. bool CL_Date::operator>  (const CL_Date& d) const
  462. {
  463.     return _days > d._days;
  464. }
  465.  
  466. /*---------------------------------------------------*/
  467.  
  468.  
  469. bool CL_Date::operator>= (const CL_Date& d) const
  470. {
  471.     return _days >= d._days;
  472. }
  473.  
  474.  
  475. /*---------------------------------------------------*/
  476.  
  477. bool CL_Date::operator== (const CL_Date& d) const
  478. {
  479.     return _days == d._days;
  480. }
  481.  
  482.  
  483. /*---------------------------------------------------*/
  484.  
  485. bool CL_Date::operator!= (const CL_Date& d) const
  486. {
  487.     return _days != d._days;
  488. }
  489.  
  490.  
  491. /*---------------------------------------------------*/
  492.  
  493.  
  494.  
  495. //
  496. // -------------------------- Modification ----------------------
  497. //
  498.  
  499. // Assignment
  500.  
  501. void CL_Date::operator= (const CL_Date& d)
  502. {
  503.     if (this == &d)
  504.         return;
  505.     if (!PrepareToChange())
  506.         return;
  507.     _days = d._days;
  508.     Notify ();   // Notify all our clients
  509. }
  510.  
  511.  
  512.  
  513.  
  514. //
  515. // -------------------------- Date arithmetic -------------------
  516. //
  517.  
  518.  
  519. // add or subtract the given number of days
  520.  
  521. CL_Date  CL_Date::operator+  (short num_days) const
  522. {
  523.     return CL_Date (_days + num_days);
  524. }
  525.  
  526.  
  527. /*---------------------------------------------------*/
  528.  
  529. CL_Date& CL_Date::operator+= (short num_days) 
  530. {
  531.     if (!PrepareToChange())
  532.         return *this;
  533.     _days += num_days;
  534.     Notify();
  535.     return *this;
  536. }
  537.  
  538.  
  539. /*---------------------------------------------------*/
  540.  
  541. CL_Date  CL_Date::operator-  (short num_days) const
  542. {
  543.     return CL_Date (_days - num_days);
  544. }
  545.  
  546.  
  547. /*---------------------------------------------------*/
  548.  
  549. CL_Date& CL_Date::operator-= (short num_days)
  550. {
  551.     if (!PrepareToChange())
  552.         return *this;
  553.     _days -= num_days;
  554.     Notify();
  555.     return *this;
  556. }
  557.  
  558.  
  559.  
  560. /*---------------------------------------------------*/
  561.  
  562. // Return the number of days between us and the given date (which
  563. // may be positive or negative)
  564. long CL_Date::operator-   (const CL_Date& date) const
  565. {
  566.     return _days - date._days;
  567. }
  568.  
  569.  
  570. CL_Date CL_Date::AddMonths (short num_months) const
  571. {
  572.     DateStruct dt = IntoYMD (_days);
  573.     long new_months = dt.y * 12 + dt.m + num_months - 1;
  574.     short ny = new_months / 12;
  575.     if (ny < 1901) {
  576.         CL_Error::Warning ("CL_Date::AddMonths: parameter %d too large",
  577.                            num_months);
  578.         return *this;
  579.     }
  580.     MonthEnum nm = (MonthEnum) (new_months % 12 + 1);
  581.     return CL_Date (ny, nm, minl (dt.d, CL_Date::DaysInMonth (nm, ny)));
  582. }
  583.  
  584.  
  585.         
  586. CL_Date CL_Date::AddYears (short num_years) const
  587. {
  588.     DateStruct dt = IntoYMD (_days);
  589.     return CL_Date (dt.y + num_years, dt.m, dt.d);
  590. }
  591.  
  592.  
  593.  
  594.  
  595.  
  596. //
  597. // --------------------- Static methods ---------------------------
  598. //
  599.  
  600. #if defined (__GNUC__)
  601. extern "C" time_t time (time_t*);
  602. #endif
  603.  
  604. CL_Date CL_Date::Today ()
  605. {
  606.     time_t timer;
  607.     struct tm *tblock;
  608.     DateStruct dt;
  609.  
  610.     timer = time ((time_t*) NULL);
  611.     tblock = localtime (&timer);
  612.     dt.y = tblock->tm_year + 1900; 
  613.     dt.m = (MonthEnum) (tblock->tm_mon + 1); // Correct for 0-11
  614.     dt.d = tblock->tm_mday;
  615.     return CL_Date (IntoDays (dt));
  616. }
  617.  
  618.  
  619.  
  620. static char* week_day [7] = {
  621.     "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
  622.     "Saturday"
  623.     };
  624. // Return name of given weekday (1 = "Sunday", ..., 7 = "Saturday")
  625. CL_String CL_Date::DayName (WeekdayEnum weekday_num)
  626. {
  627.     if (Sunday <= weekday_num && weekday_num <= Saturday)
  628.         return CL_String (week_day [weekday_num - Sunday]);
  629.     else return "";
  630. }
  631.  
  632.  
  633. /*---------------------------------------------------*/
  634.  
  635.  
  636. // Do the opposite of the above:
  637. CL_Date::WeekdayEnum  CL_Date::DayNumber (const CL_String& weekday_name)
  638. {
  639.     for (short i = 0; i < 7; i++) {
  640.         if (weekday_name == week_day[i]) return (WeekdayEnum) (i+1);
  641.     }
  642. //     CL_Error::Warning ("CL_Date::DayNumber: Invalid weekday name '%s'",
  643. //                      (const char*) weekday_name);
  644.     return InvalidDay;
  645. }
  646.  
  647.  
  648.  
  649. /*---------------------------------------------------*/
  650.  
  651. // Return month name of given month (1 = "January", etc.)
  652. static char* months [12] = {
  653.     "January", "February", "March", "April", "May", "June", "July",
  654.     "August", "September", "October", "November", "December"
  655.     };
  656.  
  657. static char* short_months [12] = {
  658.     "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
  659.     "Aug", "Sep", "Oct", "Nov", "Dec"
  660.     };
  661.  
  662. CL_String CL_Date::MonthName (short month_num)
  663. {
  664.     return (month_num >= 1 && month_num <= 12) ?
  665.         months[month_num-1] : "";
  666. }
  667.  
  668.  
  669. /*---------------------------------------------------*/
  670. CL_String CL_Date::ShortMonthName (short month_num)
  671. {
  672.     return (month_num >= 1 && month_num <= 12) ? 
  673.         (short_months[month_num-1]) : ""; 
  674. }
  675.  
  676.  
  677. /*---------------------------------------------------*/
  678.  
  679. // And the opposite of the above:
  680. CL_Date::MonthEnum CL_Date::MonthNumber (const CL_String& month_name)
  681. {
  682.     for (short i = 0; i < 12; i++) {
  683.         if (month_name == months[i]) return (MonthEnum) (i+1);
  684.     }
  685.     for (i = 0; i < 12; i++) {
  686.         if (month_name == short_months[i]) return (MonthEnum) (i+1);
  687.     }
  688.     return InvalidMonth;
  689. }
  690.  
  691.  
  692. /*---------------------------------------------------*/
  693.  
  694. // Is the given year a leap year?
  695. bool CL_Date::IsLeapYear (short year)
  696. {
  697.     return (year % 4) == 0 && ((year % 100) != 0 || (year % 400) != 0);
  698. }
  699.  
  700.  
  701.  
  702. /*---------------------------------------------------*/
  703.  
  704.  
  705. long CL_Date::StorableFormWidth () const
  706. {
  707.     return sizeof (CL_ClassId) + sizeof (long);
  708. }
  709.  
  710.  
  711. bool CL_Date::ReadFrom (const CL_Stream& s)
  712. {
  713.     if (!PrepareToChange() || !ReadClassId (s) ||
  714.         !s.Read (_days))
  715.         return FALSE;
  716.     Notify();
  717.     return TRUE;
  718. }
  719.  
  720.  
  721.  
  722. bool CL_Date::WriteTo (CL_Stream& s) const
  723. {
  724.     return s.Write (ClassId())  && s.Write (_days);
  725. }
  726.  
  727.  
  728.  
  729.  
  730. bool CL_Date::operator<  (const CL_Object& obj) const
  731. {
  732.     if (!IsA (obj))
  733.         return FALSE;
  734.     return operator< ((const CL_Date&) obj);
  735. }
  736.  
  737.  
  738. bool CL_Date::operator<= (const CL_Object& obj) const
  739. {
  740.     if (!IsA (obj))
  741.         return FALSE;
  742.     return operator<= ((const CL_Date&) obj);
  743. }
  744.  
  745.  
  746. bool CL_Date::operator>  (const CL_Object& obj) const
  747. {
  748.     if (!IsA (obj))
  749.         return FALSE;
  750.     return operator> ((const CL_Date&) obj);
  751. }
  752.  
  753.  
  754. bool CL_Date::operator>= (const CL_Object& obj) const
  755. {
  756.     if (!IsA (obj))
  757.         return FALSE;
  758.     return operator>= ((const CL_Date&) obj);
  759. }
  760.  
  761.  
  762. bool CL_Date::operator== (const CL_Object& obj) const
  763. {
  764.     if (!IsA (obj))
  765.         return FALSE;
  766.     return operator== ((const CL_Date&) obj);
  767. }
  768.  
  769.  
  770. bool CL_Date::operator!= (const CL_Object& obj) const
  771. {
  772.     if (!IsA (obj))
  773.         return FALSE;
  774.     return operator!= ((const CL_Date&) obj);
  775. }
  776.  
  777.  
  778.  
  779. short CL_Date::Compare (const CL_Date& d) const
  780. {
  781.     return _days < d._days ? -1 : (_days == d._days ? 0 : 1);
  782. }
  783.  
  784.  
  785.  
  786. bool CL_Date::IsBetween  (const CL_Date& d1, const CL_Date& d2) const
  787. {
  788.     return _days >= minl (d1._days, d2._days) &&
  789.         _days <= maxl (d1._days, d2._days);
  790. }
  791.  
  792.  
  793.  
  794.  
  795. // Protected methods
  796.  
  797. CL_Date::CL_Date (long num_days)
  798. {
  799.     _days = num_days;
  800. }
  801.  
  802.  
  803.  
  804.  
  805. //
  806. // Helper functions
  807. //
  808.  
  809.  
  810. static short month_days[12] = {
  811.     31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  812.     };
  813.  
  814. short CL_Date::DaysInMonth (short month, short year)
  815. {
  816.     if (month != February || ! CL_Date::IsLeapYear (year))
  817.         return (month >= January && month <= December)
  818.             ? month_days[month-1] : -1;
  819.     else
  820.         return 29;
  821. }
  822.  
  823.  
  824. static DateStruct IntoYMD (long nDays)
  825. {
  826.     // This algorithm is based on Algorithm 199, CACM, Aug 1963. The
  827.     // algorithm is not valid for dates before Sep 14, 1752.
  828.     ulong d;
  829.     ulong j = nDays - 1721119L;
  830.     DateStruct retVal;
  831.     ulong mo, da, y;
  832.     y = (((j<<2) - 1) / 146097L);
  833.     j = (j<<2) - 1 - 146097L*y;
  834.     d = (j>>2);
  835.     j = ((d<<2) + 3) / 1461;
  836.     d = (d<<2) + 3 - 1461*j;
  837.     d = (d + 4)>>2;
  838.     mo = (5*d - 3)/153;
  839.     d  = 5*d - 3 - 153*mo;
  840.     da = ((d + 5)/5);
  841.     y  = (100*y + j);
  842.     if (mo < 10)
  843.         mo += 3;
  844.     else {
  845.         mo -= 9;
  846.         y ++;
  847.     }
  848.     retVal.y = y;
  849.     retVal.d = da;
  850.     retVal.m = (CL_Date::MonthEnum) mo;
  851.     return retVal;
  852. }
  853.  
  854. static long       IntoDays  (const DateStruct& s)
  855. {
  856.     // This algorithm is based on Algorithm 199, CACM, Aug 1963. The
  857.     // algorithm is not valid for dates before Sep 14, 1752.
  858.     DateStruct t = s;
  859.     if (t.y <= 99)
  860.         t.y += 1900;
  861.     if (s.d <= 0 || s.d > CL_Date::DaysInMonth (s.m, s.y))
  862.         return -1;
  863.         
  864.     if (t.m > 2)          
  865.         t.m = (CL_Date::MonthEnum) (t.m - 3);
  866.     else {
  867.         t.m = (CL_Date::MonthEnum) (t.m + 9);
  868.         t.y--;
  869.     } 
  870.     ulong c  = t.y / 100;
  871.     ulong yy = t.y - 100*c;
  872.     return ((146097L * c)>>2) + ((1461*yy)>>2) + (153*t.m + 2)/5 + t.d
  873.         + 1721119L;
  874. }
  875.  
  876.  
  877.  
  878. // Old code:
  879. // static DateStruct IntoYMD   (long num_days)
  880. // {
  881. //     DateStruct date;
  882. //     long temp_days;
  883. // 
  884. //     temp_days = num_days - (num_days / 1460)   
  885. //                          + (num_days / 36500L)
  886. //                          - (num_days / 146000L);
  887. // 
  888. //     date.y = (short) (temp_days / 365);
  889. //     num_days -= (date.y * 365L) + (date.y / 4) - date.y/100 + date.y /
  890. //         400;
  891. //     date.y += 1901;
  892. //     num_days++; // Correct for: Jan 1, 1901 has days = 0
  893. //     // Set number of days for February
  894. //     short i;
  895. //     for (i = 1; i <= 12; i++) {
  896. //         short ndays = CL_Date::DaysInMonth (i, date.y);
  897. //         if (num_days > ndays)
  898. //             num_days -= ndays;
  899. //         else {
  900. //             date.m = (CL_Date::MonthEnum) i;
  901. //             date.d = (short) num_days;
  902. //             break;
  903. //         }
  904. //     }
  905. //     return date;
  906. // }
  907. // static long       IntoDays  (const DateStruct& s)
  908. // {
  909. //     long n, p;
  910. //     short i;
  911. // 
  912. //     if (s.m < CL_Date::January || s.m > CL_Date::December)
  913. //         return 0;
  914. //     if (s.y < 1901 || s.y > 10000) // Wonder if this library will be around
  915. //                                    // after 10,000 AD? <grin>
  916. //         return 0;
  917. //     if (s.d <= 0 || s.d > CL_Date::DaysInMonth (s.m, s.y))
  918. //         return 0;
  919. //     for (i = 1, p = 0; i <= ((short) s.m) - 1; ((short&) i)++)
  920. //         p += CL_Date::DaysInMonth (i, s.y);
  921. //     n =  (s.y - 1901L) * 365 + p + s.d - 1;
  922. //         // Jan 1, 1901 gives 0 days
  923. //     n += (s.y - 1901L) / 4 + 3 * (s.y - 1901L) / 400;
  924. //         // Add number of leap years between 1901 and s.y
  925. //     return n;
  926. // }
  927.  
  928.  
  929.  
  930. #if defined(__GNUC__) && __GNUC_MINOR__ >= 6
  931. #include "base/cmparatr.h"
  932. #include "base/basicops.h"
  933. #include "base/binding.h"
  934.  
  935. template class CL_Binding<CL_Date>;
  936. template class CL_Comparator<CL_Date>;
  937. template class CL_Basics<CL_Date>;
  938. #endif
  939.