home *** CD-ROM | disk | FTP | other *** search
/ PC Media 23 / PC MEDIA CD23.iso / share / prog / date50 / datecl.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1994-12-10  |  25.2 KB  |  1,057 lines

  1. /*
  2. *+----------------------------------------------------------------------
  3. *| File.........: DATECLS.CPP
  4. *| Date.........: Sat  09-25-1993
  5. *| Author.......: James M. Curran, et al
  6. *| Version......: 5.0   Compile w/MSVC++ 1.0  / or Borland C++ 3.1
  7. *| Usage........: General purpose date conversion, arithmetic,
  8. *|              :    comparison, and formatting class
  9. *|
  10. *| See DATE.H for acknowledgements and compile/link notes.
  11. *+----------------------------------------------------------------------
  12. */
  13. #include "datecl.h"
  14.  
  15. #include <assert.h>
  16. #include <ctype.h>
  17.  
  18. //--------------------- Class Varaibles ------------------------------------------------
  19.  
  20. int                Date::DisplayFormat        = Date::MDY;
  21. unsigned int    Date::DisplayOptions    = 0;
  22. unsigned short    Date::DefaultCentury    = 1900;
  23. unsigned int       Date::startDST=((Date::APRIL<<8) + 1);
  24. unsigned int       Date::startSTD=((Date::OCTOBER<<8) + 31);
  25.  
  26.  
  27. //---------------------- Compatibility Section -----------------------------------------
  28. //
  29. // Here we attempt to smooth out all the variations between different compiliers, by 
  30. // #define-ing several symbols to include or remove, or to use a common name.
  31. //
  32. // The #defines used are :
  33. //
  34.  
  35. #if defined(_MSC_VER) || defined(_WIN32)
  36.  
  37.         #define    strnset        _strnset    // MS uses ANSI-friendly names for the
  38.         #define    stricmp        _stricmp    // common (but non-standard) string 
  39.         #define    strnicmp    _strnicmp    // functions
  40.  
  41. #elif defined (__ZTC__)  && __ZTC__ < 0x0600
  42.  
  43.         #define    stricmp(a,b)    memicmp(a,b, strlen(a))
  44.         #define    strnicmp        memicmp
  45.  
  46.         // A quick check indicated that Zortech doesn't have a
  47.         // stricmp function--- This may have to be changed. - JMC
  48.  
  49.         // This has been tested on the striped-down version of
  50.         // ZTC that was provided with Tom Swan's 1991 book "Learning C++"
  51.         
  52.         // Of course, Zortech is now owned by Symantec, so they might
  53.         // have their own predefined macro to identify themselves.
  54.         // If anyone knows, please alert me... - JMC
  55. #endif            
  56.     
  57.  
  58. #if !defined(_INC_WINDOWS)    // if this is NOT a windows program
  59.  
  60.                   
  61. // See last of these blocks for English names & comments
  62.                    
  63. #if defined(_DEUTSCHEN)    //--------------------------------------------------------------------
  64.  
  65.         static const char *dayname[] = {"Sonntag","Montag","Dienstag",
  66.                     "Mittwoch","Donnerstag","Freitag","Samstag"} ;
  67.  
  68.         static const char *mname[] = {"Januar","Februar","Marz","April","Mai",
  69.                        "Juni","Juli","August","September","Oktober","November",
  70.                     "Dezember"};
  71.  
  72.         static const char    szInvalidDay[]         = "Invalide Tag";
  73.         static const char    szInvalidDate[]     = "Invalide Datum";
  74.         static const char    szInvalidMonth[]    = "Invalide Monat";
  75.         static const char    szBCE[]                = " B.C.E.";
  76.         static const char    szYears[]            = "Jahre";
  77.         static const char    szMonths[]            = "Monate";
  78.         static const char    szDays[]            = "Daten";
  79.  
  80. #elif defined(_ESPANOL)  //------------------------------------------------------------------
  81.  
  82.  
  83.         static const *char dayname[]= {"Domingo","Lunes","Martes",
  84.                     "Miercoles","Jueves","Viernes","Sabado"} ;
  85.  
  86.         static const char *mname[] = {"Enero","Febrero","Marzo","Abril",
  87.                     "Mayo","Junio","Julio","Agosto","Septiembre","Octubre",
  88.                     "Noviembre","Diciembre"};
  89.  
  90.         static const char    szInvalidDay[]         = "Invalido dia";
  91.         static const char    szInvalidDate[]     = "Invalido data";
  92.         static const char    szInvalidMonth[]    = "Invalido mes";
  93.         static const char    szBCE[]                = " B.C.E.";
  94.         static const char    szYears[]            = "anos";
  95.         static const char    szMonths[]            = "mes";
  96.         static const char    szDays[]            = "dia";
  97.  
  98. #elif defined (_FRANCAIS)
  99.         static const char *dayname[]= {"Dimanche","Lundi","Mardi",
  100.                     "Mercredi", "Jeudi","Vendredi","Samedi"} ;
  101.  
  102.         static const char *mname[] = {"Janvier","Fevrier","Mars","Avril",
  103.                     "Mai","Juin","Juillet","Aout","Septembre","Octobre",
  104.                     "Novembre","Decembre"};
  105.  
  106.         static const char    szInvalidDay[]         = "invalide jour";
  107.         static const char    szInvalidDate[]     = "invalide date";
  108.         static const char    szInvalidMonth[]    = "invalide mois";
  109.         static const char    szBCE[]                = " B.C.E.";
  110.         static const char    szYears[]            = "annee";
  111.         static const char    szMonths[]            = "mois";
  112.         static const char    szDays[]            = "journee";
  113.  
  114.  
  115. #else   // ENGLISH
  116.  
  117.                         // ---------------------------------------------------------------------
  118.  
  119.         
  120.         static const char *dayname[]= {"Sunday","Monday","Tuesday",
  121.                     "Wednesday", "Thursday","Friday","Saturday"} ;
  122.  
  123.         static const char *mname[] = {"January","February","March","April",
  124.                     "May","June","July","August","September","October",
  125.                     "November","December"};
  126.  
  127.         static const char    szInvalidDay[]         = "invalid day";
  128.         static const char    szInvalidDate[]     = "invalid date";
  129.         static const char    szInvalidMonth[]    = "invalid month";
  130.         static const char    szBCE[]                = " B.C.E.";
  131.         static const char    szYears[]            = "years";
  132.         static const char    szMonths[]            = "months";
  133.         static const char    szDays[]            = "days";
  134.  
  135. #endif
  136.                             // -----------------------------------------------------------------
  137.  
  138.     #define    GetString(x)            (x)
  139.     #define GetStringArray(x,y)        (x##[y-1])
  140.  
  141.     #define    INVALID_DAY            szInvalidDay
  142.     #define    INVALID_DATE        szInvalidDate
  143.     #define    INVALID_MONTH        szInvalidMonth
  144.     #define    MONTHS                mname
  145.     #define    DAYNAME                dayname
  146.  
  147. /*
  148.  * OK, the deal here is to use fake access functions to the strings
  149.  * we've just defined above, but only if this is NOT a Windows program.
  150.  * "Why?" you may be asking... Glad you asked.  If this were a Windows
  151.  * EXE, or better yet, a DLL, we'd want to put those strings in a
  152.  * STRINGTABLE, which means we'll need an access function to get them.
  153.  * And unless we want to have a DOS version and a separate Windows 
  154.  * version, we'll need access functions for the DOS version too.
  155.  * But it's ineffecient to have REAL access funcs, when we can just
  156.  * fake it using a couple of #defines.  Here a "call" to 
  157.  * "GetString(INVALID_DATE)" would be exactly the same as using 
  158.  * "szInvalidDate" in the code.  Similarly, "GetStringArray(MONTHS,month)"
  159.  * is the same as "mname[month-1];".
  160.  * BUT -- When  it comes time to write the Windows version, all we
  161.  * need do is write simple functions for GetString & GetStringArray, 
  162.  * and replace the #defines above with numeric constants. Viola!
  163.  *
  164.  * In fact here's a start for the Windows functions:
  165.  *        #define    GetStringArray(x,y)    GetString(x+y)
  166.  * -JMC
  167.  */
  168.  
  169.  
  170. #endif   // (_INC_WINDOWS)
  171.  
  172.  
  173. static char GauDays[]    = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
  174.  
  175. static int    DaysSoFar[][13] =
  176.             {
  177.             {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
  178.             {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}
  179.             };
  180.  
  181.  
  182.  
  183. ////////////////////////////////////////////////////////////
  184. // Constructors
  185. ////////////////////////////////////////////////////////////
  186.  
  187. Date::Date()
  188. {
  189.     month     = NON_MONTH;
  190.     day     = 0;
  191.     year     = 0;
  192.     julian     = 0L;
  193.  
  194.     day_of_week = NON_DAY;
  195. }
  196.  
  197. //////////////////////////////////////////////////////////////
  198.  
  199. Date::Date (long j) : julian(j)
  200. {
  201.     julian_to_mdy ();
  202. }
  203.  
  204. //////////////////////////////////////////////////////////////
  205.  
  206. Date::Date (short m, short d, short y) : month(m), day(d), year(y)
  207. {
  208.     assert(month > 0);
  209.     assert(month < 13);
  210.  
  211.     assert(day   > 0);
  212.     assert(day   < 32);
  213.  
  214.     mdy_to_julian ();
  215. }
  216.  
  217. //////////////////////////////////////////////////////////////
  218.  
  219. Date::Date (const tm    &TM)
  220. {
  221.         month    = (short) (TM.tm_mon + 1);
  222.         day        = (short)  TM.tm_mday;
  223.         year    = (short) (TM.tm_year + 1900);
  224.  
  225.         mdy_to_julian();
  226. }
  227.  
  228.  
  229. //////////////////////////////////////////////////////////////
  230.  
  231. #if defined(MSDOS) || defined(_WIN32)
  232. Date::Date (const DOSDATE_T &ds)
  233. {
  234.         month    = ds.month;
  235.         day        = ds.day;
  236.         year    = (short) ds.year;
  237.  
  238.         mdy_to_julian ();
  239. }
  240. #endif
  241.  
  242.  
  243. //////////////////////////////////////////////////////////////
  244.  
  245. Date::Date (const Date &dt)
  246. {
  247.         month = dt.month;
  248.         day   = dt.day;
  249.         year  = dt.year;
  250.  
  251.         mdy_to_julian ();
  252. }
  253.  
  254.  
  255. //////////////////////////////////////////////////////////////
  256.  
  257. Date::Date (int weeknum, int dow, short m, short y) : month(m), day(1), year(y)
  258. {
  259.         int    d;
  260.  
  261.         assert(weeknum > -1);        // weeknum = 0 mean "the last" 
  262.         assert(weeknum < 6);
  263.         assert(dow >  NON_DAY);
  264.         assert(dow <= SATURDAY);
  265.         assert(m   >  NON_MONTH);
  266.         assert(m   <= DECEMBER);
  267.         
  268.         mdy_to_julian ();
  269.  
  270.         if (weeknum ==0)
  271.         {
  272.                 AddMonths(1);
  273.         }
  274.  
  275.         d = (dow - day_of_week);
  276.         julian = julian + d;
  277.  
  278.         if (d > -1) 
  279.             weeknum--;
  280.             
  281.         AddWeeks(weeknum);
  282.         
  283. }
  284. //////////////////////////////////////////////////////////////
  285.  
  286. Date::Date (const char *dat)
  287. {
  288.     tm            *local_time;
  289.     time_t         timer;
  290.     const char    *pDat;
  291.  
  292.     timer       = time(NULL);
  293.     local_time = localtime(&timer);
  294.  
  295.     if ( (*dat == '.') || (stricmp(dat, "TODAY") == 0) )
  296.     {
  297.         month = (short)(local_time->tm_mon + 1);
  298.         day   = (short) local_time->tm_mday;
  299.         year  = (short)(local_time->tm_year + 1900);
  300.     }
  301.     else
  302.     {
  303.             int      nlen=strlen(dat);
  304.             int        i;
  305.             int        datetype;
  306.             int        mon;
  307.  
  308.         //
  309.         //  Possible date string formats are those that are generated by the
  310.         //  Date class itself!  The corresponding possible string lengths are
  311.         //  also listed (with ranges from shortest to longest string for that
  312.         //  format).
  313.         //
  314.         //    MDY:        03/23/1993                => 6-10,  13-17
  315.         //    COLLATE:    19930323                => 8
  316.         //    EUROPEAN:    23 March 1993            => 13,      20
  317.         //    FULL,ABBR.: Tue, Mar 23, 1993        => 16-17, 23-24
  318.         //    FULL:        Tuesday, March 23, 1993    => 22-23, 29-30
  319.         //
  320.         //  These dates may also have B.C.E. appended at the end, thus we have
  321.         //  the second set of string lengths with 7 more characters!
  322.         //
  323.  
  324.         if (isalpha(dat[0]))
  325.                 datetype = Date::FULL;
  326.  
  327.         else if (nlen == 20)
  328.                 datetype = Date::EUROPEAN;
  329.  
  330.         else if (nlen == 13)
  331.                 datetype = (isalpha(dat[5]) ? Date::EUROPEAN : Date::MDY);
  332.  
  333.         else
  334.                 datetype = Date::MDY;        // or COLLATE - both done at default:
  335.  
  336.         switch(datetype)
  337.         {
  338.             case Date::EUROPEAN:
  339.                 day   = (short) atoi(dat);
  340.  
  341.                 pDat  = strchr(dat, ' ')+1;
  342.                 i         = 12;
  343.  
  344.                 while (i > 0)
  345.                 {
  346.                     if (strnicmp(pDat, GetStringArray(MONTHS,i), 3) == 0)
  347.                             break;
  348.  
  349.                     i--;
  350.                 }
  351.  
  352.                 mon   =  i;
  353.                 pDat  = strchr(pDat, ' ')+1;
  354.                 year  = (short) atoi(pDat);
  355.                 break;
  356.  
  357.             case Date::FULL:
  358.                 pDat = strchr(dat, ' ')+1;        // Skip the day info
  359.  
  360.                 i         = 12;
  361.  
  362.                 while (i > 0)
  363.                 {
  364.                         if (strnicmp(pDat, GetStringArray(MONTHS,i), 3) == 0)
  365.                                 break;
  366.  
  367.                         i--;
  368.                 }
  369.  
  370.                 mon      = i;
  371.  
  372.                 pDat  = strchr(pDat, ' ')+1;
  373.                 day   = (short) atoi(pDat);
  374.  
  375.                 pDat  = strchr(pDat, ' ')+1;
  376.                 year  = (short) atoi(pDat);
  377.                 break;
  378.  
  379.  
  380.             default:
  381.                 i = strspn(dat,"0123456789");
  382.  
  383.                 if (i == nlen)        // It's entirely number --> COLLATE
  384.                 {
  385.                         year  = (short) ((dat[0]-'0')*1000 + (dat[1]-'0') *100  +
  386.                                          (dat[2]-'0')*10   + (dat[3]-'0'));
  387.                         // The above line sometimes produces a warning because the compiler
  388.                         // assumes that "(dat[0]-'0')*1000" can go beyond the range of a
  389.                         // short.  But the lines above it make sure it won't get higher
  390.                         // than 9000, so every thing cool.
  391.  
  392.                         mon   = (short) (dat[4]-'0')*10   + (dat[5]-'0');
  393.                         day   = (short)((dat[6]-'0')*10   + (dat[7]-'0'));
  394.                 }
  395.                 else
  396.                 {
  397.                         pDat  = &dat[i];
  398.                         mon   = atoi(dat);        // Month is number before that
  399.                         day   = (short) atoi(pDat+1);    // day is number after that.
  400.  
  401.                         pDat  = strchr(pDat+1, *pDat); // Find next occurence of the first delimiter
  402.  
  403.                         if (pDat == NULL)                // If no 2nd delim, assume current year.
  404.                                 year = (short) (local_time->tm_year + 1900);
  405.                         else
  406.                                 year = (short) atoi(pDat+1);
  407.                 }
  408.                 break;
  409.         }
  410.  
  411.       //
  412.       //  Convert B.C.E. year to proper value!
  413.       //
  414.  
  415.         if (strchr(dat, '.') != NULL)
  416.                 year = -year;
  417.  
  418.     
  419.         month = (enum Months) mon;
  420.         
  421.         //
  422.         //  Verify values!
  423.         //
  424.         if ((month <= 0) || (day <= 0))
  425.         {
  426.                 month      = NON_MONTH;
  427.                 day     = 0;
  428.                 year     = 0;
  429.         }
  430.         
  431.         if ( (year > 0) && (year < 100) )
  432.                 year = year + DefaultCentury;
  433.  
  434.     }
  435.  
  436.     mdy_to_julian ();
  437. }
  438.  
  439.  
  440. //////////////////////////////////////////////////////////////
  441. // Conversion operations
  442. //////////////////////////////////////////////////////////////
  443.  
  444. Date::operator const char *( void ) const
  445. {
  446.  
  447.         return (formatDate());
  448. }
  449.  
  450. //////////////////////////////////////////////////////////////
  451. // Date Arithmetic
  452. //////////////////////////////////////////////////////////////
  453.  
  454.  
  455. Date &Date::operator+= (long i)
  456. {
  457.         julian += i;
  458.  
  459.         julian_to_mdy();
  460.  
  461.         return *this;
  462. }
  463.  
  464. //////////////////////////////////////////////////////////////
  465.  
  466. Date &Date::operator -= (long i)
  467. {
  468.         julian -= i;
  469.         julian_to_mdy();
  470.  
  471.         return *this;
  472. }
  473.  
  474. //////////////////////////////////////////////////////////////
  475.  
  476. Date Date::operator ++()
  477. {
  478.         julian++;
  479.  
  480.         julian_to_mdy();
  481.  
  482.         return *this;
  483. }
  484.  
  485. //////////////////////////////////////////////////////////////
  486.  
  487. Date Date::operator --()
  488. {
  489.         julian--;
  490.  
  491.         julian_to_mdy();
  492.  
  493.         return *this;
  494. }
  495.  
  496. //////////////////////////////////////////////////////////////
  497. #if !defined(NOPOSTFIX)
  498. Date Date::operator ++(int)
  499. {
  500.         Date temp=*this;                // TML - Necessary to save current
  501.                                         // value of (*this) in order to
  502.         julian++;                        // simulate postfix operation!
  503.         julian_to_mdy();
  504.  
  505.         return temp;
  506. }
  507.  
  508. //////////////////////////////////////////////////////////////
  509.  
  510. Date Date::operator --(int)
  511. {
  512.         Date temp=*this;                // TML - Necessary to save current
  513.                                         // value of (*this) in order to
  514.         julian--;                        // simulate postfix operation!
  515.  
  516.         julian_to_mdy();
  517.  
  518.         return temp;
  519. }
  520. #endif
  521.  
  522.  
  523. ////////////////////////////////////////////////////////////////
  524. // Ostream operations
  525. ////////////////////////////////////////////////////////////////
  526.  
  527. ostream &operator << (ostream &os, const Date &dt)
  528. {
  529.     return os << dt.formatDate();
  530. }
  531.  
  532. //////////////////////////////////////////////////////////////
  533.  
  534. ostream &operator << (ostream &os, const DOSDATE_T &dt)
  535. {
  536.     return os << (int)dt.month << '/' << (int)dt.day << '/' << dt.year;
  537. }
  538.  
  539. //////////////////////////////////////////////////////////////
  540. // Conversion routines
  541. //////////////////////////////////////////////////////////////
  542.  
  543. void Date::julian_to_wday (void)
  544. {
  545.     day_of_week = (enum Wday) ((julian + 2) % 7 + 1);
  546. }
  547.  
  548. //////////////////////////////////////////////////////////////
  549.  
  550.  
  551. #define OCT5_1582        (2299160L)        // "really" 15-Oct-1582
  552. #define OCT14_1582        (2299169L)        // "really"  4-Oct-1582
  553. #define JAN1_1            (1721423L)
  554.  
  555. #define YEAR            (365)
  556. #define FOUR_YEARS        (1461)
  557. #define CENTURY         (36524L)
  558. #define FOUR_CENTURIES    (146097L)
  559.  
  560. void Date::julian_to_mdy ()
  561. {
  562.     long    z,y;
  563.     short     m,d;
  564.     int     lp;
  565.  
  566.     z = julian+1;
  567.     if (z >= OCT5_1582)
  568.     {
  569.         z -= JAN1_1;
  570.         z  = z + (z/CENTURY)  - (z/FOUR_CENTURIES) -2;
  571.         z += JAN1_1;
  572.  
  573.     }
  574.  
  575.     z = z - ((z-YEAR) / FOUR_YEARS);        // Remove leap years before current year
  576.     y = z / YEAR;
  577.  
  578.     d = (short) (z - (y * YEAR));
  579.  
  580.     y = y - 4712;                // our base year in 4713BC
  581.     if (y < 1)
  582.         y--;
  583.  
  584.     lp = !(y & 3);                // lp = 1 if this is a leap year.
  585.  
  586.     if (d==0)
  587.     {
  588.             y--;
  589.             d = (short) (YEAR + lp);
  590.     }
  591.  
  592.     m  = (short) (d/30);        // guess at month
  593.  
  594.     while (DaysSoFar[lp][m] >=d)
  595.         m--;                    // Correct guess.
  596.  
  597.     d = (short) (d - DaysSoFar[lp][m]);
  598.  
  599.     day = d;
  600.  
  601.     month = (short) (m+1);
  602.  
  603.     year = (short) y;
  604.  
  605.     julian_to_wday ();
  606. }
  607.  
  608. //////////////////////////////////////////////////////////////
  609.  
  610.  
  611. // The original here was far more complicated then it needed to be.
  612. // What we need to keep in mind is the simple rule:
  613. //      Before 10/4/1585, a leap year occured every 4 years.
  614. //      After  10/15/1585, leap years were skipped on centuries
  615. //        not divisible by 400. Plus 10 days were skipped to adjust
  616. //        for the past error.
  617.  
  618. void Date::mdy_to_julian (void)
  619. {
  620.     int        a;
  621.     int        work_year=year;
  622.     long    j;
  623.     int     lp;
  624.  
  625.     // correct for negative year  (-1 = 1BC = year 0)
  626.  
  627.     if (work_year < 0)
  628.             work_year++;
  629.  
  630.     lp = !(work_year & 3);            // lp = 1 if this is a leap year.
  631.  
  632.     j =
  633.         ((work_year-1) / 4)        +        // Plus ALL leap years
  634.         DaysSoFar[lp][month-1]    +
  635.         day                    +
  636.         (work_year * 365L)    +        // Days in years
  637.          JAN1_1             +
  638.          -366;                        // adjustments
  639.  
  640.     // deal with Gregorian calendar
  641.     if (j >= OCT14_1582)
  642.     {
  643.  
  644.         a = (int)(work_year/100);
  645.         j = j+ 2 - a + a/4;            // Skip days which didn't exist.
  646.     }
  647.  
  648.     julian = j;
  649.  
  650.     julian_to_wday ();
  651. }
  652.  
  653.  
  654. ////////////////////////////////////////////////////////////////
  655. // Format routine
  656. ////////////////////////////////////////////////////////////////
  657.  
  658. char *Date::formatDate (int type) const
  659. {
  660.     static char buf[40];
  661.  
  662.     strnset( buf, '\0', sizeof(buf) );
  663.  
  664.     switch ( type )
  665.     {
  666.         case Date::DAY:
  667.             if ( (day_of_week < 1) || (day_of_week > 7) )
  668.                 strcpy(buf,GetString(INVALID_DAY));
  669.             else
  670.                 strncpy( buf, GetStringArray(DAYNAME,day_of_week),
  671.                     (DisplayOptions & DATE_ABBR) ? ABBR_LENGTH : 9);
  672.             break;
  673.  
  674.         case Date::MONTH:
  675.             if ( (month < 1) || (month > 12) )
  676.                 strcpy(buf,GetString(INVALID_MONTH));
  677.             else
  678.                 strncpy( buf, GetStringArray(MONTHS,month),
  679.                     (DisplayOptions & DATE_ABBR) ? ABBR_LENGTH : 9);
  680.             break;
  681.  
  682.         case Date::FULL:
  683.             if ( (month < 1) || (month > 12) || (day_of_week < 0) ||
  684.                  (day_of_week > 7) )
  685.             {
  686.                 strcpy(buf,GetString(INVALID_DATE));
  687.             }
  688.             else
  689.             {
  690.                 int    y = abs(year);
  691.                 if ((DisplayOptions & NO_CENTURY)  && (y > 1899) )
  692.                         y = y % 100;
  693.                         
  694.                     strncpy( buf, GetStringArray(DAYNAME,day_of_week),
  695.                         (DisplayOptions & DATE_ABBR) ? ABBR_LENGTH : 9);
  696.  
  697.                     strcat( buf, ", ");
  698.                     strncat( buf, GetStringArray(MONTHS,month),
  699.                         (DisplayOptions & DATE_ABBR) ? ABBR_LENGTH : 9);
  700.  
  701.                     strcat( buf, " ");
  702.                     sprintf( buf+strlen(buf), "%d, %02d", day, y );
  703.                     if (year < 0)
  704.                         strcat(buf,szBCE);
  705.             }
  706.             break;
  707.  
  708.         case Date::EUROPEAN:
  709.             if ( (month < 1) || (month > 12) || (day_of_week < 0) ||
  710.                  (day_of_week > 7) )
  711.             {
  712.                 strcpy(buf,GetString(INVALID_DATE));
  713.             }
  714.             else
  715.             {
  716.                    int    y = year;
  717.                 if ((DisplayOptions & NO_CENTURY)  && (y > 1899) )
  718.                         y = y % 100;
  719.                         
  720.  
  721.                     sprintf(buf,"%d ",    day);
  722.  
  723.                     strncat(buf, GetStringArray(MONTHS,month),
  724.                             (DisplayOptions & DATE_ABBR) ? ABBR_LENGTH : 9);
  725.  
  726.                     sprintf( buf+strlen(buf), " %02d", y );
  727.  
  728.                     if (year < 0)
  729.                             strcat(buf,szBCE);
  730.             }
  731.             break;
  732.  
  733.         case Date::COLLATE:
  734.             if (day==0 || month==0 || year<=0)            // Can't generate COLLATE form for BCE dates.
  735.                 strcpy(buf,GetString(INVALID_DATE));
  736.             else
  737.                 sprintf( buf, "%04d%02d%02d", year, month, day);
  738.             break;
  739.  
  740.         case Date::MDY:
  741.         default:
  742.             if (day==0 || month==0 || year==0)
  743.                 strcpy(buf,GetString(INVALID_DATE));
  744.             else
  745.             {
  746.                 int    y = year;
  747.                 if ((DisplayOptions & NO_CENTURY)  && (y > 1899) )
  748.                         y = y % 100;
  749.                         
  750.                 sprintf( buf+strlen(buf), "%1d/%1d/%02d", month, day, y);
  751.             }
  752.             break;
  753.     }
  754.  
  755.     return (buf);
  756. }
  757.  
  758. //////////////////////////////////////////////////////////////
  759.  
  760.  
  761. int Date::setCentury(short century)
  762. {
  763.     int        oldcent = DefaultCentury;
  764.                   
  765.     if ( (century > 0) && (century < 100) )
  766.             century = century * 100;
  767.                       
  768.     DefaultCentury = century;
  769.     
  770.     return(oldcent);
  771. }    
  772.  
  773. //////////////////////////////////////////////////////////////
  774.  
  775. bool Date::setOption( int option, int action )
  776. {
  777.         bool        retv = true;
  778.  
  779.         switch ( option )
  780.         {
  781.             case NO_CENTURY:
  782.                 if ( action )
  783.                         DisplayOptions |= NO_CENTURY;
  784.                 else
  785.                         DisplayOptions &= (~NO_CENTURY);
  786.                 break;
  787.  
  788.             case DATE_ABBR:
  789.                 if ( action )
  790.                         DisplayOptions |= DATE_ABBR;
  791.                 else
  792.                         DisplayOptions &= (~DATE_ABBR);
  793.                 break;
  794.  
  795.             default:
  796.                 retv = false;
  797.                 break;
  798.         }
  799.  
  800.         return(retv);
  801. }
  802.  
  803. ///////////////////////////////////////////////////////////////
  804. //  Miscellaneous Routines
  805. ///////////////////////////////////////////////////////////////
  806.  
  807.  
  808. PUBLIC int Date::DOY( void ) const
  809. {
  810.     Date temp( 1, 1, year );
  811.  
  812.     return (int) (julian - temp.julian + 1);
  813. }
  814.  
  815.  
  816. //////////////////////////////////////////////////////////////
  817.  
  818. PUBLIC int Date::isLeapYear( void ) const
  819. {
  820.     return  ( (year >= 1582) ?
  821.               (year % 4 == 0  &&  year % 100 != 0  ||  year % 400 == 0 ):
  822.               (year % 4 == 0) );
  823. }
  824.  
  825. //////////////////////////////////////////////////////////////
  826. PUBLIC bool Date::isDST( void ) const
  827. {
  828.     // Initialize start of DST and STD
  829.     Date tempDST( (startDST >> 8), (startDST & 255), year ) ;
  830.     Date tempSTD( (startSTD >> 8), (startSTD & 255), year ) ;
  831.  
  832.     tempDST += -tempDST.NDOW() + 8 ;    // DST begins first Sunday in April
  833.     tempSTD -= (tempSTD.NDOW() - 1) ;   // STD begins last Sunday in October
  834.  
  835.     return( (bool) (julian >= tempDST.julian && julian < tempSTD.julian) ) ;
  836. }
  837. //////////////////////////////////////////////////////////////
  838.  
  839. PUBLIC bool Date::setDST(unsigned nMonth, unsigned nDay)
  840. {
  841.     if (nMonth < 13 && nDay < 32)
  842.     {
  843.         startDST = (nMonth << 8) + nDay;
  844.         return true;
  845.     }
  846.     else
  847.         return false;
  848. }
  849. //////////////////////////////////////////////////////////////
  850.  
  851. PUBLIC bool Date::setSTD(unsigned nMonth, unsigned nDay)
  852. {
  853.     if (nMonth < 13 && nDay < 32)
  854.     {
  855.         startSTD = (nMonth << 8) + nDay;
  856.         return true;
  857.     }
  858.     else
  859.         return false;
  860. }
  861.  
  862. //////////////////////////////////////////////////////////////
  863.  
  864. #if defined (MSDOS) || defined(_WIN32)
  865. PUBLIC DOSDATE_T Date::eom( void ) const
  866. {
  867.     static DOSDATE_T eom_temp;
  868.  
  869.     Date tempdate( (short) ((month % 12) + 1), 1, year);
  870.  
  871.     if (month == 12)
  872.         tempdate.year++;
  873.  
  874.     tempdate--;
  875.  
  876.     eom_temp.year  = (int)             tempdate.year;
  877.     eom_temp.month = (unsigned char) tempdate.month;
  878.     eom_temp.day   = (unsigned char) tempdate.day;
  879.  
  880.     return eom_temp;
  881. }
  882.  
  883.  
  884. PUBLIC DOSDATE_T Date::getDate( void ) const
  885. {
  886.     static DOSDATE_T getDate_temp;
  887.  
  888.     getDate_temp.year  =         year;
  889.     getDate_temp.month = (unsigned char) month;
  890.     getDate_temp.day   = (unsigned char) day;
  891.  
  892.     return getDate_temp;
  893. }
  894.  
  895. #endif
  896.  
  897. //////////////////////////////////////////////////////////////
  898.  
  899. //-------------------------------------------------
  900. // Version 4.0 Extension to Public Interface - CDP
  901. //-------------------------------------------------
  902.  
  903. PUBLIC Date &Date::Set(void)
  904. {
  905.     tm            *local_time;
  906.     time_t        timer;
  907.  
  908.     timer       = time(NULL);
  909.     local_time = localtime(&timer);
  910.  
  911.     month = (short) (local_time->tm_mon + 1);
  912.     day   = (short)  local_time->tm_mday;
  913.     year  = (short) (local_time->tm_year + 1900);
  914.  
  915.     mdy_to_julian();
  916.  
  917.     return *this;
  918. }
  919.  
  920. //////////////////////////////////////////////////////////////
  921.  
  922. PUBLIC Date &Date::Set(unsigned int    nMonth,unsigned int    nDay,unsigned int    nYear)
  923. {
  924.     month = (short) nMonth;
  925.     year  = (short) (nYear > 9999 ? 0 : nYear);
  926.  
  927.     day   = (short) ((nDay < DaysInMonth()) ? nDay : DaysInMonth());
  928.  
  929.     mdy_to_julian();
  930.  
  931.     return *this;
  932. }
  933.  
  934. //////////////////////////////////////////////////////////////
  935.  
  936. PUBLIC Date &Date::Set(long    j)
  937. {
  938.     julian = j;
  939.  
  940.     julian_to_mdy();
  941.  
  942.     return *this;
  943. }
  944.  
  945. //////////////////////////////////////////////////////////////
  946.  
  947. PUBLIC Date &Date::Set(int weeknum, int dow, short m, short y)
  948. {
  949.         int    d;
  950.  
  951.         assert(weeknum > -1);        // weeknum = 0 mean "the last" 
  952.         assert(weeknum < 6);
  953.         assert(dow >  NON_DAY);
  954.         assert(dow <= SATURDAY);
  955.         assert(m   >  NON_MONTH);
  956.         assert(m   <= DECEMBER);
  957.  
  958.         Set(m,1,y);
  959.  
  960.         mdy_to_julian ();
  961.  
  962.         if (weeknum ==0)    
  963.         {
  964.                 AddMonths(1);
  965.         }
  966.  
  967.         d = (dow - day_of_week);
  968.         julian = julian + d;
  969.  
  970.         if (d > 0)
  971.             weeknum--;
  972.             
  973.         AddWeeks(weeknum);            // Julian_to_mdy done in AddWeeks()
  974.  
  975.         return(*this);        
  976. }
  977.  
  978. //////////////////////////////////////////////////////////////
  979.  
  980. PUBLIC unsigned int Date::DaysInMonth() const
  981. {
  982.     return (unsigned int) (GauDays[month] + (month==2 && isLeapYear()));
  983. }
  984.  
  985. //////////////////////////////////////////////////////////////
  986.  
  987. PUBLIC Date &Date::AddMonths(int nCount)
  988. {
  989.     int nDays;
  990.  
  991.     month += (short) nCount;
  992.  
  993.     while (month < 1)
  994.     {
  995.         month += 12;
  996.         year--;
  997.     }
  998.  
  999.     while (month > 12)
  1000.     {
  1001.         month -= 12;
  1002.         year++;
  1003.     }
  1004.  
  1005.     nDays = (unsigned int) DaysInMonth();
  1006.  
  1007.     if (day > nDays)                    // Bump up the month by one if day is
  1008.     {                                   // greater than # of days in new month
  1009.         month++;                        // and assigned the difference as the
  1010.         day -= nDays;                   // day value for the new month! - TML
  1011.     }
  1012.  
  1013.     mdy_to_julian();
  1014.  
  1015.     return *this;
  1016. }
  1017.  
  1018. //////////////////////////////////////////////////////////////
  1019.  
  1020. PUBLIC Date & Date::AddWeeks(int nCount)
  1021. {
  1022.     Set(julian + (long)nCount*7);
  1023.     return *this;
  1024. }
  1025.  
  1026.  
  1027. //////////////////////////////////////////////////////////////
  1028.  
  1029. PUBLIC Date &Date::AddYears(int nCount)
  1030. {
  1031.     year += (short) nCount;
  1032.     mdy_to_julian();
  1033.  
  1034.     return *this;
  1035. }
  1036.  
  1037. //////////////////////////////////////////////////////////////
  1038.  
  1039. PUBLIC int Date::WOM(void) const 
  1040. {
  1041.     // Abs day includes the days from previous month that fills up
  1042.     // the begin. of the week.
  1043.  
  1044.     int nAbsDay = day + FirstDOM()-1;
  1045.     return (nAbsDay-NDOW())/7 + 1;
  1046. }
  1047. //////////////////////////////////////////////////////////////
  1048.  
  1049.  
  1050. PUBLIC int Date::WOY(void) const 
  1051. {
  1052.     Date   doTemp(1, 1, year);
  1053.     return (int)(((julian - doTemp.julian+1)/7) + 1);
  1054. }
  1055.  
  1056.  
  1057.