home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / oclsrc15.zip / OCL / Source / ODate.cpp < prev    next >
C/C++ Source or Header  |  1996-08-12  |  13KB  |  614 lines

  1. // OCL - OS/2 Class Library
  2. // (c) Cubus 1995
  3. // All Rights Reserved
  4. // ODate.hpp
  5.  
  6.  
  7. /*
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Neither the name Cubus nor the name Team OCL may be used to
  14.  *    endorse or promote products derived from this software
  15.  *    without specific prior written permission.
  16.  * 3. See OCL.INF for a detailed copyright notice.
  17.  *
  18.  *              THIS SOFTWARE IS PROVIDED ``AS IS'' AND
  19.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  20.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  21.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  22.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  23.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  24.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  25.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  26.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  27.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  28.  * SUCH DAMAGE.
  29.  */
  30.  
  31.  
  32. // $Header: W:/Projects/OCL/Source/rcs/ODate.cpp 1.50 1996/08/11 23:49:13 B.STEIN Release $
  33.  
  34.  
  35. #define __OCL_SOURCE__
  36.  
  37. #define OINCL_OSTRING
  38. #define OINCL_BASE
  39.  
  40. #include <ocl.hpp>
  41. #include <ODate.hpp>
  42. #include <OMessage.hpp>
  43. #include <time.h>
  44.  
  45. // module constants 
  46.  
  47. static const INT
  48.   daysToMonth [2][13] =
  49.     {
  50.     { 0,  31,  59,  90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
  51.     { 0,  31,  60,  91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
  52.     };
  53.  
  54. static const ODate::MDY
  55.   reformMDY = 
  56.     {
  57.      ODate::September, 2, 1752
  58.     };
  59.  
  60. static const LONG
  61.   reformJulianDayNumber = 2361221;
  62.  
  63. static const INT
  64.   reformDays = 11;
  65.  
  66.  
  67. // member functions
  68.  
  69.  
  70. ODate::ODate()
  71. {
  72. #if (defined (__IBMCPP__) || defined (__HIGHC__))
  73.   _tzset();
  74. #endif
  75. #if (defined (__EMX__) || defined (__WATCOM_CPLUSPLUS__))
  76.   tzset();
  77. #endif
  78.  
  79.  _now_time_t = time(0);
  80.  _now_tm     = *localtime(&_now_time_t);
  81.  julian      = today().julian;
  82.  
  83.  calculate();
  84. }
  85.  
  86.  
  87.  
  88. ODate::ODate(INT aYear, INT aDay)
  89. {
  90.  ODate::MDY mdy = DYToMDY(aDay, aYear);
  91.  
  92.  init(mdy.month, mdy.day, mdy.year);
  93. }
  94.  
  95.  
  96.  
  97. ODate::ODate(const _CDATE &cDate)
  98. {
  99.  init((ODate::Month)cDate.month, cDate.day, cDate.year);
  100. }
  101.  
  102.  
  103.  
  104. ODate::ODate(INT aDay, Month aMonth, INT aYear)
  105. {
  106.  init(aMonth, aDay, aYear);
  107. }
  108.  
  109.  
  110.  
  111. ODate::ODate(Month aMonth, INT aDay, INT aYear)
  112. {
  113.  init(aMonth, aDay, aYear);
  114. }
  115.  
  116.  
  117.  
  118. ODate::ODate(const ODate& aDate)
  119.   : julian(aDate.julian)
  120.   {}
  121.  
  122.  
  123.  
  124. ODate::ODate(ULONG julianDayNumber)
  125.   : julian(julianDayNumber)
  126.   {}
  127.  
  128.  
  129. ODate::~ODate()
  130.   {}
  131.  
  132.  
  133. PSZ ODate::isOfType() const
  134. {
  135.  return("ODate");
  136. }
  137.  
  138.  
  139. ostream& operator << (ostream &aStream, const ODate &aDate)
  140. {
  141.  return(aStream << (PSZ) aDate.asString());
  142. }
  143.  
  144.  
  145. OString ODate::asString(DateFormat dateFmt) const
  146. {
  147.  OString  temp(CCHMAXPATH);
  148.  
  149.  switch(dateFmt)
  150.   {
  151.    case sd_pi:          // [-31] 7837
  152.      sprintf(temp,"[%ld] %04ld", prefix, integer);
  153.      break;
  154.    case sd_pif1:        // [-31] 7837.5
  155.      sprintf(temp,"[%ld] %04ld.%01ld", prefix, integer, fraction/1000);
  156.      break;
  157.    case sd_pif2:        // [-31] 7837.53
  158.      sprintf(temp,"[%ld] %04ld.%02ld", prefix, integer, fraction/100);
  159.      break;
  160.    case sd_pif3:        // [-31] 7837.532
  161.      sprintf(temp,"[%ld] %04ld.%03ld", prefix, integer, fraction/10);
  162.      break;
  163.    case sd_pif4:        // [-31] 7837.5321
  164.      sprintf(temp,"[%ld] %04ld.%04ld", prefix, integer, fraction);
  165.      break;
  166.    case sd_if:          // 7837
  167.      sprintf(temp,"%04ld", integer);
  168.      break;
  169.    case sd_if1:         // 7837.5
  170.      sprintf(temp,"%04ld.%01ld", integer, fraction/1000);
  171.      break;
  172.    case sd_if2:         // 7837.53 
  173.      sprintf(temp,"%04ld.%02ld", integer, fraction/100);
  174.      break;
  175.    case sd_if3:         // 7837.532
  176.      sprintf(temp,"%04ld.%03ld", integer, fraction/10);
  177.      break;
  178.    case sd_if4:         // 7837.5321
  179.      sprintf(temp,"%04ld.%04ld", integer, fraction);
  180.      break;
  181.    default: {
  182.      COUNTRYCODE ctryCode = { 0, 0 };
  183.      COUNTRYINFO ctryInfo;
  184.      ULONG       bytes;
  185.      PSZ         fmts[] = {
  186.                            "%m-%d-%y",
  187.                            "%d-%m-%y",
  188.                            "%y-%m-%d",
  189.                            "%m-%d-%Y",
  190.                            "%d-%m-%Y",
  191.                            "%Y-%m-%d"
  192.                           };
  193.  
  194.      DosQueryCtryInfo(sizeof(ctryInfo), &ctryCode, &ctryInfo, &bytes );
  195.  
  196.      ULONG x = ctryInfo.fsDateFmt;
  197.  
  198.      if (x > yy_mm_dd)
  199.          x = mm_dd_yy;
  200.  
  201.      OString fmt(fmts[x]);
  202.      fmt.getText()[3] = fmt.getText()[6] = ctryInfo.szDateSeparator[0];
  203.      return(asString(fmt));  } 
  204.   }
  205.  
  206.  return(OString(temp));
  207. };
  208.  
  209.  
  210. OString ODate::asString(PCSZ fmt) const
  211. {
  212.  OString   result(((fmt != NULL) ? strlen(fmt) : 0) + 3);
  213.  OString   tempFmt(fmt);
  214.  tm        dummy = { 0 };
  215.  
  216.  dummy.tm_mon    = (INT)(monthOfYear()) - (INT)January;
  217.  dummy.tm_mday   = dayOfMonth();
  218.  
  219.  if ((strchr(tempFmt, 'y')) && (year() < 1900))
  220.     dummy.tm_year = year();
  221.  else
  222.     dummy.tm_year = year() - 1900;
  223.  
  224.  mktime(&dummy);
  225.  
  226.  strftime((PSZ)result, result.length(), fmt, &dummy);
  227.  
  228.  return(OString(result));
  229. }
  230.  
  231.  
  232. _CDATE ODate::asCDATE() const
  233. {
  234.  CDATE result = {
  235.                  (UCHAR) dayOfMonth(),
  236.                  (UCHAR) monthOfYear(),
  237.                  (UCHAR) year()
  238.                 };
  239.  return(result);
  240. }
  241.  
  242.  
  243. OString ODate::dayName() const
  244. {
  245.  return(ODate::dayName(dayOfWeek()));
  246. }
  247.  
  248.  
  249. OString ODate::monthName() const
  250. {
  251.  return(ODate::monthName(monthOfYear()));
  252. }
  253.  
  254.  
  255. INT ODate::dayOfMonth() const
  256. {
  257.  ODate::MDY mdy = ODate::julianToMDY(julian);
  258.  
  259.  return(mdy.day);
  260. }
  261.  
  262.  
  263. INT ODate::dayOfYear() const
  264. {
  265.  ODate::MDY mdy = ODate::julianToMDY(julian);
  266.  
  267.  return(daysToMonth[ODate::isLeapYear(mdy.year)][mdy.month - 1] + mdy.day);
  268. }
  269.  
  270.  
  271.  
  272. ODate::Month ODate::monthOfYear() const
  273. {
  274.  return(ODate::julianToMDY(julian).month);
  275. }
  276.  
  277.  
  278. INT ODate::year() const
  279. {
  280.  return(ODate::julianToMDY(julian).year);
  281. }
  282.  
  283.  
  284. OString ODate::dayName(ODate::DayOfWeek aDay)
  285. {
  286.  return(OString(OMessage(OCL_ODATE_MON + (ULONG) aDay, OCL::MSGFILE)));
  287. };
  288.  
  289.  
  290. OString ODate::monthName(ODate::Month aMonth)
  291. {
  292.  return(OString(OMessage(OCL_ODATE_JAN + (ULONG) aMonth, OCL::MSGFILE)));
  293. }
  294.  
  295.  
  296. INT ODate::daysInMonth(ODate::Month aMonth, INT aYear)
  297. {
  298.  BOOL leap   = (ODate::isLeapYear(aYear) != FALSE);
  299.  INT  result = daysToMonth[leap][aMonth]
  300.                -
  301.                daysToMonth[leap][aMonth - 1];
  302.  
  303.  if ((aYear == reformMDY.year) &&
  304.      (aMonth == reformMDY.month))
  305.    result -= reformDays;
  306.  return(result);
  307. }
  308.  
  309.  
  310. INT ODate::daysInYear(INT aYear)
  311. {
  312.  INT result = 365 + ODate::isLeapYear(aYear);
  313.  
  314.  if (aYear == reformMDY.year)
  315.    result -= reformDays;
  316.  
  317.  return(result);
  318. }
  319.  
  320.  
  321.  
  322. BOOL ODate::isLeapYear(INT aYear)
  323. {
  324.  INT  y      = aYear + (aYear < 0);
  325.  
  326.  return((y % 4 == 0) && ((aYear < reformMDY.year) || (y % 100 != 0) || (y % 400 == 0)));
  327. }
  328.  
  329.  
  330. BOOL ODate::isValid(ODate::Month aMonth, INT aDay, INT aYear)
  331. {
  332.  INT  days   = reformMDY.day + reformDays;
  333.  
  334.  if (aMonth >= January  &&
  335.      aMonth <= December &&
  336.      aDay > 0           &&
  337.      aYear != 0)
  338.   { 
  339.    if ((aYear == reformMDY.year) && (aMonth == reformMDY.month))
  340.      return (aDay <= (ODate::daysInMonth(aMonth, aYear) + reformDays) &&
  341.             (aDay <= reformMDY.day || aDay > days));
  342.    else
  343.      return (aDay <= ODate::daysInMonth(aMonth, aYear));
  344.   }
  345.  
  346.  return(FALSE);
  347. }
  348.  
  349.  
  350.  
  351. ODate& ODate::init(ODate::Month aMonth, INT aDay, INT aYear)
  352. {
  353.  if (ODate::isValid(aMonth, aDay, aYear))
  354.   {
  355.    ODate::MDY mdy = { aMonth, aDay, aYear };
  356.    julian         = ODate::MDYToJulian(mdy);
  357.   }
  358.  else
  359.    julian = 0;
  360.  
  361.  return(*this);
  362. }
  363.  
  364.  
  365. ODate::MDY ODate::julianToMDY(ULONG julianDayNumber)
  366. {
  367.  ODate::MDY result;
  368.  INT        century,
  369.             days,
  370.             j;
  371.  BOOL       leap = FALSE;
  372.  
  373.  if (julianDayNumber > reformJulianDayNumber)
  374.   {
  375.    century          = (julianDayNumber - 1684595) / 36524.25;
  376.    julianDayNumber += (century * 3L / 4L) - 2;
  377.   }
  378.  
  379.  LONG fours = julianDayNumber / 1461,
  380.       years = fours * 4;
  381.  
  382.  days = julianDayNumber % 1461;
  383.  
  384.  for (j = 1; j < 5; ++j)
  385.    if (365 * j >= days) break;
  386.  
  387.  --j;
  388.  
  389.  if (j == 0)
  390.   {
  391.    if ( years <= 4712 + reformMDY.year )
  392.      {
  393.       leap = TRUE;
  394.       ++days;
  395.      }
  396.    else
  397.      {
  398.       if ( ( years - 4712 ) % 100 != 0 || ( years - 4712 ) % 400 == 0 )
  399.         {
  400.          leap = TRUE;
  401.          ++days;
  402.         }
  403.      }
  404.   }
  405.  else
  406.   {
  407.    days -= 365 * j;
  408.    years += j;
  409.   }
  410.  
  411.  for (j = 1; j < 12; ++j)
  412.    if (days <= daysToMonth[leap][j]) break;
  413.  
  414.  result.month = (ODate::Month) j;
  415.  result.day   = days - daysToMonth[leap][j - 1];
  416.  result.year  = years - 4712;
  417.  
  418.  if (result.year <= 0)
  419.    result.year--;
  420.  
  421.  return result;
  422. }
  423.  
  424. ODate::MDY ODate::DYToMDY(INT aDay, INT aYear)
  425. {
  426.  ODate::MDY   result;
  427.  
  428.  result.month = ODate::January,
  429.  result.day   = aDay,
  430.  result.year  = aYear;
  431.  
  432.  if (ODate::isValid(aYear, aDay))
  433.    while(TRUE)
  434.     {
  435.      INT maxDay = ODate::daysInMonth(result.month, result.year);
  436.      if ( result.day > maxDay )
  437.           result.month = (ODate::Month) ( result.month + 1 ),
  438.           result.day -= maxDay;
  439.      else
  440.         break;
  441.     }
  442.  
  443.  if (result.year == reformMDY.year &&
  444.      result.month == reformMDY.month &&
  445.      result.day > reformMDY.day )
  446.    result.day += reformDays;
  447.  
  448.  return result;
  449. }
  450.  
  451.  
  452. ULONG ODate::MDYToJulian(MDY aDate)
  453. {
  454.  aDate.year   += (aDate.year < 0);
  455.  
  456.  INT    years = aDate.year + 4712,
  457.         month_days,
  458.         century;
  459.  BOOL   leap  = FALSE;
  460.  
  461.  LONG   year_days = 365L * (LONG) years + (LONG)( years >> 2 ),
  462.         julian_date;
  463.  
  464.  if ((years & 3) == 0)
  465.    {
  466.     leap = TRUE,
  467.     year_days--;
  468.    }
  469.  
  470.  month_days  = daysToMonth[leap][aDate.month - 1];
  471.  julian_date = year_days + (LONG)( month_days + aDate.day);
  472.  
  473.  if (julian_date > reformJulianDayNumber)
  474.    {
  475.     years = aDate.year - 300;
  476.     if ( aDate.month <= 2)
  477.        years--;
  478.     century = years / 100;
  479.     julian_date -= ( ( century * 3 ) / 4 + 1 );
  480.    }
  481.  
  482.  return(julian_date);
  483. }
  484.  
  485.  
  486. ODate ODate::today()
  487. {
  488. #if (defined (__IBMCPP__) || defined (__HIGHC__))
  489.   _tzset();
  490. #endif
  491. #if (defined (__EMX__) || defined (__WATCOM_CPLUSPLUS__))
  492.   tzset();
  493. #endif
  494.  
  495.  time_t _now_time_t = time(0);
  496.  tm     _now_tm     = *localtime(&_now_time_t);
  497.  
  498.  return(ODate(_now_tm.tm_year + 1900, _now_tm.tm_yday + 1));
  499. }
  500.  
  501.  
  502. ODate ODate::now()
  503. {
  504.  return ODate();
  505. }
  506.  
  507.  
  508. ODate::DayOfWeek ODate::dayOfWeek() const
  509. {
  510.  return((ODate::DayOfWeek)(julian % 7));
  511. }
  512.  
  513.  
  514. ULONG ODate::julianDate() const
  515. {
  516.  return(julian);
  517. }
  518.  
  519.  
  520. BOOL ODate::operator == (const ODate &aDate) const
  521. {
  522.  return(julian == aDate.julian);
  523. }
  524.  
  525.  
  526. BOOL ODate::operator != (const ODate &aDate) const
  527. {
  528.  return(julian != aDate.julian);
  529. }
  530.  
  531.  
  532. BOOL ODate::operator <  (const ODate &aDate) const
  533. {
  534.  return(julian <  aDate.julian);
  535. }
  536.  
  537.  
  538. BOOL ODate::operator <= (const ODate &aDate) const
  539. {
  540.  return(julian <= aDate.julian);
  541. }
  542.  
  543.  
  544. BOOL ODate::operator >  (const ODate &aDate) const
  545. {
  546.  return(julian >  aDate.julian);
  547. }
  548.  
  549.  
  550. BOOL ODate::operator >= (const ODate &aDate) const
  551. {
  552.  return(julian >= aDate.julian);
  553. }
  554.  
  555.  
  556. ODate ODate::operator + (INT numDays) const
  557. {
  558.  return(ODate(julian + numDays));
  559. }
  560.  
  561.  
  562. ODate ODate::operator - (INT numDays) const
  563. {
  564.  return(ODate(julian - numDays));
  565. }
  566.  
  567.  
  568. ODate& ODate::operator += (INT numDays)
  569. {
  570.  julian += numDays;
  571.  return(*this);
  572. }
  573.  
  574.  
  575. ODate& ODate::operator -= (INT numDays)
  576. {
  577.  julian -= numDays;
  578.  return(*this);
  579. }
  580.  
  581.  
  582. LONG ODate::operator - (const ODate &aDate) const
  583. {
  584.  return(julian - aDate.julian);
  585. }
  586.  
  587.  
  588. BOOL ODate::isValid(INT aDay, ODate::Month aMonth, INT aYear)
  589. {
  590.  return(ODate::isValid(aMonth, aDay, aYear));
  591. }
  592.  
  593.  
  594. BOOL ODate::isValid(INT aYear, INT aDay)
  595. {
  596.  return(aYear != 0 && aDay <= ODate::daysInYear(aYear));
  597. }
  598.  
  599.  
  600. ODate& ODate::calculate()
  601. {
  602.  _now_time_t = mktime(&_now_tm);
  603.  fraction    = ((_now_time_t%17280) * 3125) / 5400;
  604.  integer     = _now_time_t/17280 + 9350;
  605.  prefix      = (integer/10000) - 36;
  606.  integer    %= 10000;
  607.  
  608.  return(*this);
  609. }
  610.  
  611.  
  612. // end of source
  613.  
  614.