home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / ocl150a.zip / OCL / Source / ODate.cpp < prev    next >
C/C++ Source or Header  |  1997-01-10  |  13KB  |  615 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()[2] = fmt.getText()[5] = 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.  INT       iLength = ((fmt != NULL) ? strlen(fmt) : 0) + 3;
  213.  OString   result(iLength);
  214.  OString   tempFmt(fmt);
  215.  tm        dummy = { 0 };
  216.  
  217.  dummy.tm_mon    = (INT)(monthOfYear()) - (INT)January;
  218.  dummy.tm_mday   = dayOfMonth();
  219.  
  220.  if ((strchr(tempFmt, 'y')) && (year() < 1900))
  221.     dummy.tm_year = year();
  222.  else
  223.     dummy.tm_year = year() - 1900;
  224.  
  225.  mktime(&dummy);
  226.  
  227.  strftime((PSZ)result, iLength, fmt, &dummy);
  228.  
  229.  return(OString(result));
  230. }
  231.  
  232.  
  233. _CDATE ODate::asCDATE() const
  234. {
  235.  CDATE result = {
  236.                  (UCHAR) dayOfMonth(),
  237.                  (UCHAR) monthOfYear(),
  238.                  (UCHAR) year()
  239.                 };
  240.  return(result);
  241. }
  242.  
  243.  
  244. OString ODate::dayName() const
  245. {
  246.  return(ODate::dayName(dayOfWeek()));
  247. }
  248.  
  249.  
  250. OString ODate::monthName() const
  251. {
  252.  return(ODate::monthName(monthOfYear()));
  253. }
  254.  
  255.  
  256. INT ODate::dayOfMonth() const
  257. {
  258.  ODate::MDY mdy = ODate::julianToMDY(julian);
  259.  
  260.  return(mdy.day);
  261. }
  262.  
  263.  
  264. INT ODate::dayOfYear() const
  265. {
  266.  ODate::MDY mdy = ODate::julianToMDY(julian);
  267.  
  268.  return(daysToMonth[ODate::isLeapYear(mdy.year)][mdy.month - 1] + mdy.day);
  269. }
  270.  
  271.  
  272.  
  273. ODate::Month ODate::monthOfYear() const
  274. {
  275.  return(ODate::julianToMDY(julian).month);
  276. }
  277.  
  278.  
  279. INT ODate::year() const
  280. {
  281.  return(ODate::julianToMDY(julian).year);
  282. }
  283.  
  284.  
  285. OString ODate::dayName(ODate::DayOfWeek aDay)
  286. {
  287.  return(OString(OMessage(OCL_ODATE_MON + (ULONG) aDay, OCL::MSGFILE)));
  288. };
  289.  
  290.  
  291. OString ODate::monthName(ODate::Month aMonth)
  292. {
  293.  return(OString(OMessage(OCL_ODATE_JAN + (ULONG) aMonth, OCL::MSGFILE)));
  294. }
  295.  
  296.  
  297. INT ODate::daysInMonth(ODate::Month aMonth, INT aYear)
  298. {
  299.  BOOL leap   = (ODate::isLeapYear(aYear) != FALSE);
  300.  INT  result = daysToMonth[leap][aMonth]
  301.                -
  302.                daysToMonth[leap][aMonth - 1];
  303.  
  304.  if ((aYear == reformMDY.year) &&
  305.      (aMonth == reformMDY.month))
  306.    result -= reformDays;
  307.  return(result);
  308. }
  309.  
  310.  
  311. INT ODate::daysInYear(INT aYear)
  312. {
  313.  INT result = 365 + ODate::isLeapYear(aYear);
  314.  
  315.  if (aYear == reformMDY.year)
  316.    result -= reformDays;
  317.  
  318.  return(result);
  319. }
  320.  
  321.  
  322.  
  323. BOOL ODate::isLeapYear(INT aYear)
  324. {
  325.  INT  y      = aYear + (aYear < 0);
  326.  
  327.  return((y % 4 == 0) && ((aYear < reformMDY.year) || (y % 100 != 0) || (y % 400 == 0)));
  328. }
  329.  
  330.  
  331. BOOL ODate::isValid(ODate::Month aMonth, INT aDay, INT aYear)
  332. {
  333.  INT  days   = reformMDY.day + reformDays;
  334.  
  335.  if (aMonth >= January  &&
  336.      aMonth <= December &&
  337.      aDay > 0           &&
  338.      aYear != 0)
  339.   { 
  340.    if ((aYear == reformMDY.year) && (aMonth == reformMDY.month))
  341.      return (aDay <= (ODate::daysInMonth(aMonth, aYear) + reformDays) &&
  342.             (aDay <= reformMDY.day || aDay > days));
  343.    else
  344.      return (aDay <= ODate::daysInMonth(aMonth, aYear));
  345.   }
  346.  
  347.  return(FALSE);
  348. }
  349.  
  350.  
  351.  
  352. ODate& ODate::init(ODate::Month aMonth, INT aDay, INT aYear)
  353. {
  354.  if (ODate::isValid(aMonth, aDay, aYear))
  355.   {
  356.    ODate::MDY mdy = { aMonth, aDay, aYear };
  357.    julian         = ODate::MDYToJulian(mdy);
  358.   }
  359.  else
  360.    julian = 0;
  361.  
  362.  return(*this);
  363. }
  364.  
  365.  
  366. ODate::MDY ODate::julianToMDY(ULONG julianDayNumber)
  367. {
  368.  ODate::MDY result;
  369.  INT        century,
  370.             days,
  371.             j;
  372.  BOOL       leap = FALSE;
  373.  
  374.  if (julianDayNumber > reformJulianDayNumber)
  375.   {
  376.    century          = (INT) ((julianDayNumber - 1684595) / 36524.25);
  377.    julianDayNumber += (century * 3L / 4L) - 2;
  378.   }
  379.  
  380.  LONG fours = julianDayNumber / 1461,
  381.       years = fours * 4;
  382.  
  383.  days = julianDayNumber % 1461;
  384.  
  385.  for (j = 1; j < 5; ++j)
  386.    if (365 * j >= days) break;
  387.  
  388.  --j;
  389.  
  390.  if (j == 0)
  391.   {
  392.    if ( years <= 4712 + reformMDY.year )
  393.      {
  394.       leap = TRUE;
  395.       ++days;
  396.      }
  397.    else
  398.      {
  399.       if ( ( years - 4712 ) % 100 != 0 || ( years - 4712 ) % 400 == 0 )
  400.         {
  401.          leap = TRUE;
  402.          ++days;
  403.         }
  404.      }
  405.   }
  406.  else
  407.   {
  408.    days -= 365 * j;
  409.    years += j;
  410.   }
  411.  
  412.  for (j = 1; j < 12; ++j)
  413.    if (days <= daysToMonth[leap][j]) break;
  414.  
  415.  result.month = (ODate::Month) j;
  416.  result.day   = days - daysToMonth[leap][j - 1];
  417.  result.year  = years - 4712;
  418.  
  419.  if (result.year <= 0)
  420.    result.year--;
  421.  
  422.  return result;
  423. }
  424.  
  425. ODate::MDY ODate::DYToMDY(INT aDay, INT aYear)
  426. {
  427.  ODate::MDY   result;
  428.  
  429.  result.month = ODate::January,
  430.  result.day   = aDay,
  431.  result.year  = aYear;
  432.  
  433.  if (ODate::isValid(aYear, aDay))
  434.    while(TRUE)
  435.     {
  436.      INT maxDay = ODate::daysInMonth(result.month, result.year);
  437.      if ( result.day > maxDay )
  438.           result.month = (ODate::Month) ( result.month + 1 ),
  439.           result.day -= maxDay;
  440.      else
  441.         break;
  442.     }
  443.  
  444.  if (result.year == reformMDY.year &&
  445.      result.month == reformMDY.month &&
  446.      result.day > reformMDY.day )
  447.    result.day += reformDays;
  448.  
  449.  return result;
  450. }
  451.  
  452.  
  453. ULONG ODate::MDYToJulian(MDY aDate)
  454. {
  455.  aDate.year   += (aDate.year < 0);
  456.  
  457.  INT    years = aDate.year + 4712,
  458.         month_days,
  459.         century;
  460.  BOOL   leap  = FALSE;
  461.  
  462.  LONG   year_days = 365L * (LONG) years + (LONG)( years >> 2 ),
  463.         julian_date;
  464.  
  465.  if ((years & 3) == 0)
  466.    {
  467.     leap = TRUE,
  468.     year_days--;
  469.    }
  470.  
  471.  month_days  = daysToMonth[leap][aDate.month - 1];
  472.  julian_date = year_days + (LONG)( month_days + aDate.day);
  473.  
  474.  if (julian_date > reformJulianDayNumber)
  475.    {
  476.     years = aDate.year - 300;
  477.     if ( aDate.month <= 2)
  478.        years--;
  479.     century = years / 100;
  480.     julian_date -= ( ( century * 3 ) / 4 + 1 );
  481.    }
  482.  
  483.  return(julian_date);
  484. }
  485.  
  486.  
  487. ODate ODate::today()
  488. {
  489. #if (defined (__IBMCPP__) || defined (__HIGHC__))
  490.   _tzset();
  491. #endif
  492. #if (defined (__EMX__) || defined (__WATCOM_CPLUSPLUS__))
  493.   tzset();
  494. #endif
  495.  
  496.  time_t _now_time_t = time(0);
  497.  tm     _now_tm     = *localtime(&_now_time_t);
  498.  
  499.  return(ODate(_now_tm.tm_year + 1900, _now_tm.tm_yday + 1));
  500. }
  501.  
  502.  
  503. ODate ODate::now()
  504. {
  505.  return ODate();
  506. }
  507.  
  508.  
  509. ODate::DayOfWeek ODate::dayOfWeek() const
  510. {
  511.  return((ODate::DayOfWeek)(julian % 7));
  512. }
  513.  
  514.  
  515. ULONG ODate::julianDate() const
  516. {
  517.  return(julian);
  518. }
  519.  
  520.  
  521. BOOL ODate::operator == (const ODate &aDate) const
  522. {
  523.  return(julian == aDate.julian);
  524. }
  525.  
  526.  
  527. BOOL ODate::operator != (const ODate &aDate) const
  528. {
  529.  return(julian != aDate.julian);
  530. }
  531.  
  532.  
  533. BOOL ODate::operator <  (const ODate &aDate) const
  534. {
  535.  return(julian <  aDate.julian);
  536. }
  537.  
  538.  
  539. BOOL ODate::operator <= (const ODate &aDate) const
  540. {
  541.  return(julian <= aDate.julian);
  542. }
  543.  
  544.  
  545. BOOL ODate::operator >  (const ODate &aDate) const
  546. {
  547.  return(julian >  aDate.julian);
  548. }
  549.  
  550.  
  551. BOOL ODate::operator >= (const ODate &aDate) const
  552. {
  553.  return(julian >= aDate.julian);
  554. }
  555.  
  556.  
  557. ODate ODate::operator + (INT numDays) const
  558. {
  559.  return(ODate(julian + numDays));
  560. }
  561.  
  562.  
  563. ODate ODate::operator - (INT numDays) const
  564. {
  565.  return(ODate(julian - numDays));
  566. }
  567.  
  568.  
  569. ODate& ODate::operator += (INT numDays)
  570. {
  571.  julian += numDays;
  572.  return(*this);
  573. }
  574.  
  575.  
  576. ODate& ODate::operator -= (INT numDays)
  577. {
  578.  julian -= numDays;
  579.  return(*this);
  580. }
  581.  
  582.  
  583. LONG ODate::operator - (const ODate &aDate) const
  584. {
  585.  return(julian - aDate.julian);
  586. }
  587.  
  588.  
  589. BOOL ODate::isValid(INT aDay, ODate::Month aMonth, INT aYear)
  590. {
  591.  return(ODate::isValid(aMonth, aDay, aYear));
  592. }
  593.  
  594.  
  595. BOOL ODate::isValid(INT aYear, INT aDay)
  596. {
  597.  return(aYear != 0 && aDay <= ODate::daysInYear(aYear));
  598. }
  599.  
  600.  
  601. ODate& ODate::calculate()
  602. {
  603.  _now_time_t = mktime(&_now_tm);
  604.  fraction    = ((_now_time_t%17280) * 3125) / 5400;
  605.  integer     = _now_time_t/17280 + 9350;
  606.  prefix      = (integer/10000) - 36;
  607.  integer    %= 10000;
  608.  
  609.  return(*this);
  610. }
  611.  
  612.  
  613. // end of source
  614.  
  615.