home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR36 / KDC46.ZIP / DATECL.CPP next >
C/C++ Source or Header  |  1993-08-04  |  16KB  |  685 lines

  1. /*
  2.  *┌──────────────────────────────────────────────────────────────────────
  3.  *│ File.........: DATECL.CPP
  4.  *│ Date.........: August 4, 1993
  5.  *│ Author.......: Ly Minh Trí (CIS 70641,3127)
  6.  *│ Copyright....: None! Use freely.
  7.  *│ Version......: 4.6  Compile w/MSC++ 7.0 or Borland C++ 3.1
  8.  *│ Usage........: General purpose date conversion, arithmetic,
  9.  *│              : comparison, and formatting class
  10.  *│
  11.  *│ See DATECLS4.H for acknowledgements and compile/link notes.
  12.  *└──────────────────────────────────────────────────────────────────────
  13.  */
  14.  
  15. #include "datecl.h"
  16. #include "ctype.h"
  17.  
  18. int Date::DisplayFormat=Date::MDY;
  19. char Date::cbuf[Date::BUF_SIZE];
  20.  
  21. unsigned char Date::DisplayOptions='\0';
  22.  
  23. const char *dayname[] = {"Sunday","Monday","Tuesday","Wednesday",
  24.        "Thursday","Friday","Saturday"} ;
  25.  
  26. const char *mname[] = {"January","February","March","April","May",
  27.        "June","July","August","September","October","November","December"};
  28.  
  29. static int GauDays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
  30.  
  31. ////////////////////////////////////////////////////////////
  32. // Constructors
  33. ////////////////////////////////////////////////////////////
  34.  
  35. Date::Date()
  36. {
  37.     month = day = day_of_week = 0;
  38.     year = 0;
  39.     julian = 0;
  40. }
  41.  
  42. Date::Date (long j) : julian(j)
  43. {
  44.     julian_to_mdy ();
  45. }
  46.  
  47. Date::Date (int m, int d, int y) : month((unsigned char)m), day((unsigned char)d), year(y)
  48. {
  49.     mdy_to_julian ();
  50. }
  51.  
  52. Date::Date (const char *dat)
  53. {
  54.     #ifdef _MSC                         // Differentiate between Microsoft's
  55.     if (!_stricmp(dat, "TODAY"))        // and Borland's compiler!
  56.     #else
  57.     if (!stricmp(dat, "TODAY"))
  58.     #endif
  59.     {
  60.         struct DOSDATE_T temp_date;
  61.         _dos_getdate(&temp_date);
  62.         month = temp_date.month;
  63.         day   = temp_date.day;
  64.         year  = temp_date.year;
  65.     }
  66.     else
  67.     {
  68.         char *tmp, *tmp2;
  69.         int  nlen=strlen(dat), i, datetype;
  70.  
  71.         tmp = new char[nlen+1];
  72.  
  73.         //
  74.         //  TML - We need to make a copy of 'dat' because strtok() modifies
  75.         //  the content of its first parameter!!!
  76.         //
  77.         strcpy(tmp, dat);
  78.  
  79.         //
  80.         //  Possible date string formats are those that are generated by the
  81.         //  Date class itself!  The corresponding possible string lengths are
  82.         //  also listed (with ranges from shortest to longest string for that
  83.         //  format).
  84.         //
  85.         //  MDY:        03/23/1993                      => 6-10,13-17
  86.         //  EUROPEAN:   23 March 1993                   => 13, 20
  87.         //  FULL,ABBR.: Tue, Mar 23, 1993               => 16-17, 23-24
  88.         //  FULL:       Tuesday, March 23, 1993         => 22-23, 29-30
  89.         //
  90.         //  These dates may also have B.C.E. appended at the end, thus we have
  91.         //  the second set of string lengths with 7 more characters!
  92.         //
  93.  
  94.         if (isalpha(tmp[0]))
  95.             datetype = Date::FULL;
  96.         else if (nlen == 20)
  97.             datetype = Date::EUROPEAN;
  98.         else if (nlen == 13)
  99.             datetype = (isalpha(tmp[5]) ? Date::EUROPEAN : Date::MDY);
  100.         else
  101.             datetype = Date::MDY;
  102.  
  103.         switch(datetype)
  104.         {
  105.             case Date::EUROPEAN:
  106.                 day   = (unsigned char)atoi(strtok(tmp," "));
  107.  
  108.                 tmp2 = strtok(NULL," ");
  109.                 i = 0;
  110.                 while (i < 12)
  111.                 {
  112.                     #ifdef _MSC
  113.                     if (_stricmp(tmp2, mname[i++]) == 0)
  114.                     #else
  115.                     if (stricmp(tmp2, mname[i++]) == 0)
  116.                     #endif
  117.                         break;
  118.                 }
  119.  
  120.                 month = (i <= 12) ? i : 0;
  121.                 year  = atoi(strtok(NULL," "));
  122.                 break;
  123.  
  124.             case Date::FULL:
  125.                 strtok(tmp," ");                // Skip the day info
  126.                 tmp2 = strtok(NULL," ");        // Get the month string
  127.  
  128.                 i = -1;
  129.                 while (++i < 12)
  130.                 {
  131.                     if (toupper(tmp2[0]) == toupper(*(mname[i]))    &&
  132.                         toupper(tmp2[1]) == toupper(*(mname[i]+1))  &&
  133.                         toupper(tmp2[2]) == toupper(*(mname[i]+2)))
  134.                         break;
  135.                 }
  136.  
  137.                 month = (i <= 12) ? ++i : 0;
  138.                 day   = atoi(strtok(NULL,","));
  139.                 year  = atoi(strtok(NULL," "));
  140.                 break;
  141.  
  142.             default:
  143.                 month = (unsigned char)atoi(strtok(tmp,"/-"));
  144.                 day   = (unsigned char)atoi(strtok(NULL,"/-"));
  145.                 year  = atoi(strtok(NULL," "));
  146.                 break;
  147.         }
  148.  
  149.         //
  150.         //  Convert B.C.E. year to proper value!
  151.         //
  152.         if (strtok(NULL, ".") != NULL)
  153.             year *= -1;
  154.  
  155.         //
  156.         //  Verify values!
  157.         //
  158.         if ((month < 1) || (month > 12) || (day < 1) || (day > (unsigned char) DaysInMonth()))
  159.         {
  160.             month = day = 0;
  161.             year = 0;
  162.         }
  163.  
  164.         delete [] tmp;
  165.     }
  166.  
  167.     mdy_to_julian ();
  168. }
  169.  
  170. Date::Date (const DOSDATE_T &ds)
  171. {
  172.     month = ds.month;
  173.     day   = ds.day;
  174.     year  = ds.year;
  175.     mdy_to_julian ();
  176. }
  177.  
  178. Date::Date (const Date &dt)
  179. {
  180.     month = dt.month;
  181.     day   = dt.day;
  182.     year  = dt.year;
  183.     mdy_to_julian ();
  184. }
  185.  
  186. //////////////////////////////////////////////////////////////
  187. // Conversion operations
  188. //////////////////////////////////////////////////////////////
  189. Date::operator char *( void )
  190. {
  191.     formatDate();
  192.     return cbuf;
  193. }
  194.  
  195. //////////////////////////////////////////////////////////////
  196. // Date Arithmetic
  197. //////////////////////////////////////////////////////////////
  198. Date Date::operator + (long i)
  199. {
  200.     return Date(julian + i);
  201. }
  202.  
  203. Date Date::operator + (int i)
  204. {
  205.     return Date(julian + (long)i);
  206. }
  207.  
  208. Date Date::operator - (long i)
  209. {
  210.     return Date(julian - i);
  211. }
  212.  
  213. Date Date::operator - (int i)
  214. {
  215.     return Date(julian - (long)i);
  216. }
  217.  
  218. long Date::operator - (const Date &dt)
  219. {
  220.     return ( julian - dt.julian );
  221. }
  222.  
  223. const Date &Date::operator += (long i)
  224. {
  225.     julian += i;
  226.     julian_to_mdy();
  227.     return *this;
  228. }
  229.  
  230. const Date &Date::operator -= (long i)
  231. {
  232.     julian -= i;
  233.     julian_to_mdy();
  234.     return *this;
  235. }
  236.  
  237. Date Date::operator ++()
  238. {
  239.     Date temp=*this;                    // TML - Necessary to save current
  240.                                         // value of (*this) in order to
  241.     julian++;                           // simulate prefix operation!
  242.     julian_to_mdy();
  243.     return temp;
  244. }
  245.  
  246. Date Date::operator ++(int)
  247. {
  248.     julian++;
  249.     julian_to_mdy();
  250.     return *this;
  251. }
  252.  
  253. Date Date::operator --()
  254. {
  255.     Date temp=*this;                    // TML - Necessary to save current
  256.                                         // value of (*this) in order to
  257.     julian--;                           // simulate prefix operation!
  258.     julian_to_mdy();
  259.     return temp;
  260. }
  261.  
  262. Date Date::operator --(int)
  263. {
  264.     julian--;
  265.     julian_to_mdy();
  266.     return *this;
  267. }
  268.  
  269. //////////////////////////////////////////////////////////////
  270. // Date comparison
  271. //////////////////////////////////////////////////////////////
  272. int Date::operator <  (const Date &dt)
  273. {
  274.     return ( julian < dt.julian );
  275. }
  276.  
  277. int Date::operator <= (const Date &dt)
  278. {
  279.     return ( (julian == dt.julian) || (julian < dt.julian) );
  280. }
  281.  
  282. int Date::operator >  (const Date &dt)
  283. {
  284.     return ( julian > dt.julian );
  285. }
  286.  
  287. int Date::operator >= (const Date &dt)
  288. {
  289.     return ( (julian == dt.julian) || (julian > dt.julian) );
  290. }
  291.  
  292. int Date::operator == (const Date &dt)
  293. {
  294.     return ( julian == dt.julian );
  295. }
  296.  
  297. int Date::operator != (const Date &dt)
  298. {
  299.     return ( julian != dt.julian );
  300. }
  301.  
  302. ////////////////////////////////////////////////////////////////
  303. // Ostream operations
  304. ////////////////////////////////////////////////////////////////
  305.  
  306. ostream &operator << (ostream &os, const Date &dt)
  307. {
  308.     return os << dt.formatDate();
  309. }
  310.  
  311. ostream &operator << (ostream &os, const DOSDATE_T &dt)
  312. {
  313.     return os << (int)dt.month << "/" << (int)dt.day << "/" << dt.year;
  314. }
  315.  
  316. //////////////////////////////////////////////////////////////
  317. // Conversion routines
  318. //////////////////////////////////////////////////////////////
  319.  
  320. void Date::julian_to_wday (void)
  321. {
  322.     day_of_week = (unsigned char) ((julian + 2) % 7 + 1);
  323. }
  324.  
  325. void Date::julian_to_mdy ()
  326. {
  327.     long a,b,c,d,e,z,alpha;
  328.     z = julian+1;
  329.  
  330.     // dealing with Gregorian calendar reform
  331.  
  332.     if (z < 2299161L)
  333.         a = z;
  334.     else
  335.     {
  336.         alpha = (long) ((z-1867216.25) / 36524.25);
  337.         a = z + 1 + alpha - alpha/4;
  338.     }
  339.  
  340.     b = ( a > 1721423 ? a + 1524 : a + 1158 );
  341.     c = (long) ((b - 122.1) / 365.25);
  342.     d = (long) (365.25 * c);
  343.     e = (long) ((b - d) / 30.6001);
  344.  
  345.     day = (unsigned char)(b - d - (long)(30.6001 * e));
  346.     month = (unsigned char)((e < 13.5) ? e - 1 : e - 13);
  347.     year = (int)((month > 2.5 ) ? (c - 4716) : c - 4715);
  348.     julian_to_wday ();
  349. }
  350.  
  351. void Date::mdy_to_julian (void)
  352. {
  353.     int a,b=0;
  354.     int work_month=month, work_day=day, work_year=year;
  355.  
  356.     // correct for negative year
  357.  
  358.     if (work_year < 0)
  359.         work_year++;
  360.  
  361.     if (work_month <= 2)
  362.     {
  363.         work_year--;
  364.         work_month +=12;
  365.     }
  366.  
  367.     // deal with Gregorian calendar
  368.  
  369.     if (work_year*10000. + work_month*100. + work_day >= 15821015.)
  370.     {
  371.         a = (int)(work_year/100.);
  372.         b = 2 - a + a/4;
  373.     }
  374.  
  375.     julian = (long) (365.25*work_year) +
  376.              (long) (30.6001 * (work_month+1))  +  work_day + 1720994L + b;
  377.     julian_to_wday ();
  378. }
  379.  
  380. ////////////////////////////////////////////////////////////////
  381. // Format routine
  382. ////////////////////////////////////////////////////////////////
  383. const char *Date::formatDate (int type) const
  384. {
  385.     memset( cbuf, '\0', sizeof(cbuf) );
  386.  
  387.     switch ( type )
  388.     {
  389.         case Date::DAY:
  390.  
  391.             if ( (day_of_week < 1) || (day_of_week > 7) )
  392.                 strcpy(cbuf,"invalid day");
  393.             else
  394.                 strncpy( cbuf, dayname[day_of_week-1],
  395.                     (DisplayOptions & Date::DATE_ABBR) ? ABBR_LENGTH : 9);
  396.             break;
  397.  
  398.         case Date::MONTH:
  399.  
  400.             if ( (month < 1) || (month > 12) )
  401.                 strcpy(cbuf,"invalid month");
  402.             else
  403.                 strncpy( cbuf, mname[month-1],
  404.                     (DisplayOptions & Date::DATE_ABBR) ? ABBR_LENGTH : 9);
  405.             break;
  406.  
  407.         case Date::FULL:
  408.  
  409.             if ( (month < 1) || (month > 12) || (day_of_week < 1) ||
  410.                  (day_of_week > 7) || (day < 1) )
  411.             {
  412.                 strcpy(cbuf,"invalid date");
  413.                 break;
  414.             }
  415.  
  416.             strncpy( cbuf, dayname[day_of_week-1],
  417.                 (DisplayOptions & Date::DATE_ABBR) ? ABBR_LENGTH : 9);
  418.             strcat( cbuf, ", ");
  419.             strncat( cbuf, mname[month-1],
  420.                 (DisplayOptions & Date::DATE_ABBR) ? ABBR_LENGTH : 9);
  421.             sprintf( cbuf+strlen(cbuf), " %d, %d", day, abs(year) );
  422.  
  423.             if (year < 0)
  424.                 strcat(cbuf," B.C.E.");
  425.             break;
  426.  
  427.         case Date::EUROPEAN:
  428.  
  429.             if ( (month < 1) || (month > 12) || (day_of_week < 1) ||
  430.                  (day_of_week > 7) || (day < 1)  )
  431.             {
  432.                 strcpy(cbuf,"invalid date");
  433.                 break;
  434.             }
  435.  
  436.             sprintf(cbuf,"%d ",  day);
  437.             strncat(cbuf, mname[month-1],
  438.                 (DisplayOptions & Date::DATE_ABBR) ? ABBR_LENGTH : 9);
  439.             sprintf( cbuf+strlen(cbuf), " %d", abs(year) );
  440.  
  441.             if (year < 0)
  442.                 strcat(cbuf," B.C.E.");
  443.             break;
  444.  
  445.         case Date::MDY:
  446.  
  447.         default:
  448.             if ( (month < 1) || (month > 12) || (day_of_week < 1) ||
  449.                  (day_of_week > 7) || (day < 1) )
  450.             {
  451.                 strcpy(cbuf,"invalid date");
  452.                 break;
  453.             }
  454.             else
  455.                 sprintf( cbuf+strlen(cbuf), "%1d/%1d/%02d", month, day,
  456.                     (DisplayOptions & Date::NO_CENTURY) && (abs(year) > 1899)
  457.                     ? (abs(year) - (abs(year) / 100 * 100))
  458.                     : (abs(year))  );
  459.             break;
  460.     }
  461.  
  462.     return cbuf;
  463. }
  464.  
  465. void Date::setFormat( int format )
  466. {
  467.     DisplayFormat = format;
  468. }
  469.  
  470. int Date::setOption( int option, int action )
  471. {
  472.     //
  473.     // TML - Convert from switch statement to if statement
  474.     //
  475.     if (option & (Date::NO_CENTURY | Date::DATE_ABBR))
  476.     {
  477.         if ( action )
  478.             DisplayOptions |= option;
  479.         else
  480.             DisplayOptions &= ~option;
  481.  
  482.         return 1;
  483.     }
  484.     else
  485.         return 0;
  486. }
  487.  
  488. ///////////////////////////////////////////////////////////////
  489. //  Miscellaneous Routines
  490. ///////////////////////////////////////////////////////////////
  491.  
  492. long Date::julDate( void ) const
  493. {
  494.     return julian;
  495. }
  496.  
  497. int Date::DOY( void ) const
  498. {
  499.     Date temp( 1, 1, year );
  500.  
  501.     return (int) (julian - temp.julian + 1);
  502. }
  503.  
  504.  
  505. int Date::isLeapYear( void ) const
  506. {
  507.     return  ( (year >= 1582) ?
  508.           (year % 4 == 0  &&  year % 100 != 0  ||  year % 400 == 0 ):
  509.           (year % 4 == 0) );
  510. }
  511.  
  512. DOSDATE_T Date::eom( void ) const
  513. {
  514.     static DOSDATE_T eom_temp;
  515.     Date tempdate( (month % 12) + 1, 1, year);
  516.  
  517.     if (month == 12)
  518.         tempdate.year++;
  519.  
  520.     tempdate--;
  521.  
  522.     eom_temp.year  = tempdate.year;
  523.     eom_temp.month = tempdate.month;
  524.     eom_temp.day   = tempdate.day;
  525.  
  526.     return eom_temp;
  527. }
  528.  
  529. DOSDATE_T Date::getDate( void ) const
  530. {
  531.     static DOSDATE_T getDate_temp;
  532.  
  533.     getDate_temp.year  = year;
  534.     getDate_temp.month = month;
  535.     getDate_temp.day   = day;
  536.  
  537.     return getDate_temp;
  538. }
  539.  
  540.  
  541. //─────────────────────────────────────────────────
  542. // Version 4.0 Extension to Public Interface - CDP
  543. //─────────────────────────────────────────────────
  544.  
  545. PUBLIC const Date & Date::Set()
  546. {
  547.     struct DOSDATE_T sDate;
  548.     _dos_getdate(&sDate);
  549.  
  550.     month = sDate.month;
  551.     day   = sDate.day;
  552.     year  = sDate.year;
  553.  
  554.     mdy_to_julian();
  555.     return *this;
  556. }
  557.  
  558. PUBLIC const Date & Date::Set(int nMonth, int nDay, int nYear)
  559. {
  560.     month = (unsigned char)nMonth;
  561.     year  = nYear < 0 ? 9999 : nYear;
  562.     year  = nYear > 9999 ? 0 : nYear;
  563.     day   = (unsigned char)(nDay < DaysInMonth() ? nDay : DaysInMonth());
  564.  
  565.     mdy_to_julian();
  566.     return *this;
  567. }
  568.  
  569. PUBLIC const Date & Date::Set(long j)
  570. {
  571.     julian = j;
  572.  
  573.     julian_to_mdy();
  574.     return *this;
  575. }
  576.  
  577. PUBLIC int Date::DaysInMonth()
  578. {
  579.     return GauDays[month-1] + (month==2 && isLeapYear());
  580. }
  581.  
  582. PUBLIC int Date::FirstDOM() const
  583. {
  584.     return Date(month, 1, year).NDOW();
  585. }
  586.  
  587. PUBLIC int Date::Day() const
  588. {
  589.     return day;
  590. }
  591.  
  592. PUBLIC int Date::NDOW() const
  593. {
  594.     return day_of_week;
  595. }
  596.  
  597. PUBLIC int Date::NYear4() const
  598. {
  599.     return year;
  600. }
  601.  
  602. PUBLIC int Date::NMonth() const
  603. {
  604.     return month;
  605. }
  606.  
  607. PUBLIC const Date & Date::AddWeeks(int nCount)
  608. {
  609.     Set(julian + (long)nCount*7);
  610.     return *this;
  611. }
  612.  
  613.  
  614. PUBLIC const Date & Date::AddMonths(int nCount)
  615. {
  616.     nCount += month;                    // Since month is of type unsigned char
  617.                                         // I choose to use nCount as the main
  618.     while (nCount < 1)                  // counter - TML
  619.     {
  620.         nCount += 12;
  621.         year--;
  622.     }
  623.  
  624.     while (nCount > 12)
  625.     {
  626.         nCount -= 12;
  627.         year++;
  628.     }
  629.  
  630.     month = (unsigned char) nCount;
  631.     mdy_to_julian();
  632.     return *this;
  633. }
  634.  
  635. PUBLIC const Date & Date::AddYears(int nCount)
  636. {
  637.     year += nCount;
  638.     mdy_to_julian();
  639.     return *this;
  640. }
  641.  
  642. PUBLIC int Date::WOM()
  643. {
  644.     // Abs day includes the days from previous month that fills up
  645.     // the begin. of the week.
  646.     int nAbsDay = day + FirstDOM()-1;
  647.     return (nAbsDay-NDOW())/7 + 1;
  648. }
  649.  
  650. PUBLIC int Date::WOY()
  651. {
  652.     Date   doTemp(1, 1, year);
  653.     return (int)(((julian - doTemp.julian+1)/7) + 1);
  654. }
  655.  
  656. PUBLIC Date Date::BOM()
  657. {
  658.     return(Date(month, 1, year));
  659. }
  660.  
  661. PUBLIC Date Date::EOM()
  662. {
  663.     return(Date(month+1, 1, year)-1L);
  664. }
  665.  
  666. PUBLIC Date Date::BOY()
  667. {
  668.     return(Date(1, 1, year));
  669. }
  670.  
  671. PUBLIC Date Date::EOY()
  672. {
  673.     return(Date(1, 1, year+1)-1L);
  674. }
  675.  
  676. PUBLIC const char * Date::CMonth()
  677. {
  678.     return(formatDate(MONTH));
  679. }
  680.  
  681. PUBLIC const char * Date::CDOW()
  682. {
  683.     return(formatDate(DAY));
  684. }
  685.