home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1994 #1 / monster.zip / monster / PROG_C / DATECL.ZIP / DATECL.CPP next >
C/C++ Source or Header  |  1994-01-26  |  17KB  |  729 lines

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