home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 15 / CDACTUAL15.iso / cdactual / program / c / WLIB.ZIP / WTIME.C < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-30  |  15.5 KB  |  755 lines

  1. #include <time.h>
  2. #include <ctype.h>
  3. #include <WTime.h>
  4. #include <WDOS.h>
  5. #include <WBits.h>
  6. #pragma hdrstop
  7.  
  8. // copyright (c) 1993 by Paul Wheaton
  9.  
  10. extern int DOM[12];//={31,28,31,30,31,30,31,31,30,31,30,31};
  11.  
  12. //.parse
  13.  
  14. /*
  15.  
  16. Converting Julian to Gregorian dates and back.  According to the Gregorian
  17. Calendar Principle:
  18.  
  19.           Each year has 365 days in it
  20.           EXCEPT years that are evenly divisible by 4    (366 days)
  21.           EXCEPT years that are evenly divisible by 100  (365 days)
  22.           EXCEPT years that are evenly divisible by 400  (366 days)
  23.  
  24. Most four year chunks (a quad) are 1461 days.
  25. Most 100 year chunks (a century) are 36,524 days.
  26. All 400 year chunks (quad century) are 116,877 days.
  27. In theory, the first year (Year 0000) was a leap year.
  28.  
  29. If you wanted to, you could assume that there are 365.2425 days in the
  30. average year.  If you do try this, remember that floating point math can
  31. throw you a little bit of round off error - add 0.0000000001 to everything.
  32.  
  33. I prefer to use integer math since I feel I have more control and more speed.
  34.  
  35. The way I calculate it, all Quads will have four years where the first year
  36. is 366 days and each one after that is 365 days.  EXCEPT for a Quad that is the
  37. first Quad in a Century
  38.  
  39. */
  40.  
  41. Bool LeapYear(int Year)
  42.   {
  43.     if ((Year%400)==0) return True;
  44.     if ((Year%100)==0) return False;
  45.     if ((Year%4)==0) return True;
  46.     return False;
  47.   }
  48.  
  49. static const long Q=1461L;    // number of days in four years (quad)
  50. static const long C=36524L;   // century
  51. static const long QC=146097L; // four centuries.
  52. int DOM[12]={31,28,31,30,31,30,31,31,30,31,30,31};
  53.   // days of the month
  54.  
  55. static void ConvertJulianToGregorian(long J, int& Y, int& M, int& D)
  56.   {
  57.     long NumQC=J/QC;
  58.     Y=int(NumQC)*400;
  59.     J-=(QC*NumQC);
  60.     long NumC=0;
  61.     if (J>(C+1))
  62.       {
  63.         J-=(C+1);
  64.         Y+=100;
  65.         NumC=J/C;
  66.         Y+=int(NumC)*100;
  67.         J-=NumC*C;
  68.         NumC++;
  69.       }
  70.     if ((NumC>0)&&(J>(Q-1)))
  71.       {
  72.         J-=(Q-1);
  73.         Y+=4;
  74.       }
  75.     long NumQ=J/Q;
  76.     Y+=int(NumQ)*4;
  77.     J-=NumQ*Q;
  78.     int Jul=int(J);  // no more need for long int math
  79.     if (LeapYear(Y))
  80.       {
  81.         if (Jul>=366)
  82.           {
  83.             Jul-=366;
  84.             Y++;
  85.           }
  86.         else if (Jul==59) // Jan 1, would have Jul = 0, Feb 29 would have Jul=59
  87.           {
  88.             M=2;
  89.             D=29;
  90.             return;
  91.           }
  92.         else if (Jul>59) Jul--;
  93.       }
  94.     while (Jul>=365)
  95.       {
  96.         Jul-=365;
  97.         Y++;
  98.       }
  99.     M=0;
  100.     while(DOM[M]<=Jul)
  101.       {
  102.         Jul-=DOM[M];
  103.         M++;
  104.       }
  105.     M++;
  106.     D=Jul+1;
  107.   }
  108.  
  109. static long ConvertGregorianToJulian(int Y, int M, int D)
  110.   {
  111.     Bool Leap=LeapYear(Y-(Y%4));
  112.     int NumQC=Y/400;
  113.     Y-=NumQC*400;
  114.     long J=NumQC*QC;
  115.     int NumC=Y/100;
  116.     if (NumC>0)
  117.       {
  118.         Y-=NumC*100;
  119.         J+=(NumC*C)+1;  // the first century has one more day
  120.       }
  121.     int NumQ=Y/4;
  122.     Y-=NumQ*4;
  123.     if ((NumC!=0)&&(NumQ>0))
  124.       {
  125.         // generally, the first Q doesn't have a leap year
  126.         J+=1460;
  127.         NumQ--;
  128.       }
  129.     J+=NumQ*Q;
  130.     if (Leap)
  131.       {
  132.         if (Y>0)
  133.           {
  134.             J+=366;
  135.             Y--;
  136.           }
  137.         else if (M>2) J++;
  138.       }
  139.     while (Y>0)
  140.       {
  141.         J+=365;
  142.         Y--;
  143.       }
  144.     int I;
  145.     For(I,M-1) J+=DOM[I];
  146.     J+=(D-1);
  147.     return J;
  148.   }
  149.  
  150. Date::Date(const JulianDate& J)
  151.   {
  152.     ConvertJulianToGregorian(J.J,Y,M,D);
  153.   }
  154.  
  155. void Date::operator=(const JulianDate& J)
  156.   {
  157.     ConvertJulianToGregorian(J.J,Y,M,D);
  158.   }
  159.  
  160. Bool Date::operator==(const JulianDate& X) const
  161.   {
  162.     long J=ConvertGregorianToJulian(Y,M,D);
  163.     return (J==X.J);
  164.   }
  165.  
  166. Bool Date::operator<=(const JulianDate& X) const
  167.   {
  168.     long J=ConvertGregorianToJulian(Y,M,D);
  169.     return (J<=X.J);
  170.   }
  171.  
  172. Bool Date::operator>=(const JulianDate& X) const
  173.   {
  174.     long J=ConvertGregorianToJulian(Y,M,D);
  175.     return (J>=X.J);
  176.   }
  177.  
  178. Bool Date::operator!=(const JulianDate& X) const
  179.   {
  180.     long J=ConvertGregorianToJulian(Y,M,D);
  181.     return (J!=X.J);
  182.   }
  183.  
  184. Bool Date::operator<(const JulianDate& X) const
  185.   {
  186.     long J=ConvertGregorianToJulian(Y,M,D);
  187.     return (J<=X.J);
  188.   }
  189.  
  190. Bool Date::operator>(const JulianDate& X) const
  191.   {
  192.     long J=ConvertGregorianToJulian(Y,M,D);
  193.     return (J>=X.J);
  194.   }
  195.  
  196. JulianDate Date::operator+(long Days) const
  197.   {
  198.     JulianDate J(ConvertGregorianToJulian(Y,M,D)+Days);
  199.     return J;
  200.   }
  201.  
  202. JulianDate Date::operator-(long Days) const
  203.   {
  204.     JulianDate J(ConvertGregorianToJulian(Y,M,D)-Days);
  205.     return J;
  206.   }
  207.  
  208. long Date::operator-(const JulianDate& X) const
  209.   {
  210.     long J=ConvertGregorianToJulian(Y,M,D);
  211.     J-=X.J;
  212.     return J;
  213.   }
  214.  
  215. JulianDate Date::operator++(int)
  216.   {
  217.     JulianDate J(*this);
  218.     ConvertJulianToGregorian(J.J+1,Y,M,D);
  219.     return J;  // return the original value since this is a post inc
  220.   }
  221.  
  222. JulianDate Date::operator--(int)
  223.   {
  224.     JulianDate J(*this);
  225.     ConvertJulianToGregorian(J.J-1,Y,M,D);
  226.     return J;  // return the original value since this is a post dec
  227.   }
  228.  
  229. JulianDate Date::operator++()
  230.   {
  231.     JulianDate J(*this);
  232.     J.J++;
  233.     ConvertJulianToGregorian(J.J,Y,M,D);
  234.     return J;  // return the original value since this is a post inc
  235.   }
  236.  
  237. JulianDate Date::operator--()
  238.   {
  239.     JulianDate J(*this);
  240.     J.J--;
  241.     ConvertJulianToGregorian(J.J,Y,M,D);
  242.     return J;  // return the original value since this is a post dec
  243.   }
  244.  
  245. void Date::operator+=(long Days)
  246.   {
  247.     JulianDate J(*this);
  248.     J+=Days;
  249.     ConvertJulianToGregorian(J.J,Y,M,D);
  250.   }
  251.  
  252. void Date::operator-=(long Days)
  253.   {
  254.     JulianDate J(*this);
  255.     J-=Days;
  256.     ConvertJulianToGregorian(J.J,Y,M,D);
  257.   }
  258.  
  259. ////////////////////    Julian stuff
  260.  
  261. JulianDate::JulianDate(int Year, int Month, int Day)
  262.   {
  263.     J=ConvertGregorianToJulian(Year,Month,Day);
  264.   }
  265.  
  266. JulianDate::JulianDate(const Date& D)
  267.   {
  268.     J=ConvertGregorianToJulian(D.Y,D.M,D.D);
  269.   }
  270.  
  271. int JulianDate::Year() const
  272.   {
  273.     int Y,M,D;
  274.     ConvertJulianToGregorian(J,Y,M,D);
  275.     return Y;
  276.   }
  277.  
  278. int JulianDate::Month() const
  279.   {
  280.     int Y,M,D;
  281.     ConvertJulianToGregorian(J,Y,M,D);
  282.     return M;
  283.   }
  284.  
  285. int JulianDate::Day() const
  286.   {
  287.     int Y,M,D;
  288.     ConvertJulianToGregorian(J,Y,M,D);
  289.     return D;
  290.   }
  291.  
  292. void JulianDate::SetYear(int Year)
  293.   {
  294.     int Y,M,D;
  295.     ConvertJulianToGregorian(J,Y,M,D);
  296.     Y=Year;
  297.     J=ConvertGregorianToJulian(Y,M,D);
  298.   }
  299.  
  300. void JulianDate::SetMonth(int Month)
  301.   {
  302.     int Y,M,D;
  303.     ConvertJulianToGregorian(J,Y,M,D);
  304.     M=Month;
  305.     J=ConvertGregorianToJulian(Y,M,D);
  306.   }
  307.  
  308. void JulianDate::SetDay(int Day)
  309.   {
  310.     int Y,M,D;
  311.     ConvertJulianToGregorian(J,Y,M,D);
  312.     D=Day;
  313.     J=ConvertGregorianToJulian(Y,M,D);
  314.   }
  315.  
  316. void JulianDate::operator=(const Date& D)
  317.   {
  318.     J=ConvertGregorianToJulian(D.Y,D.M,D.D);
  319.   }
  320.  
  321. //.parse
  322.  
  323. String40 Date::DayStr() const
  324.   {
  325.     char* X="00";
  326.     X[0]=D/10+'0';
  327.     X[1]=D%10+'0';
  328.     return String40(X);
  329.   }
  330.  
  331. //.parse
  332.  
  333. String40 Date::MonthStr2() const
  334.   {
  335.     char* X="00";
  336.     X[0]=M/10+'0';
  337.     X[1]=M%10+'0';
  338.     return String40(X);
  339.   }
  340.  
  341. //.parse
  342.  
  343. Date::Date(const char* Text)
  344.   {
  345.     String40 S=Text;
  346.     /*  possible cases:
  347.            to                 Today
  348.            y                  Yesterday
  349.            m tu w th f sa su  Mon, Tue, Wed, Thu, Fri, Sat, Sun
  350.  
  351.                 -30 (30 days ago)
  352.  
  353.                 01011993
  354.                 010193
  355.                 0101
  356.                 1-1-1993
  357.                 1-1-93
  358.                 1-1
  359.                 1/1/1993
  360.                 1/1/93
  361.                 1/1
  362.     */
  363.     S.Trim();
  364.     Y=0;
  365.     M=1;
  366.     D=1;
  367.     Date TD=Today();
  368.     JulianDate TDJ(TD);
  369.     int Pos;
  370.     while((Pos=S.Index('/'))!=NotFound) S[Pos]='-';
  371.     if (isdigit(S(0)))
  372.       {
  373.         if (S!="0")
  374.           {
  375.             if (!S.Find('-'))
  376.               {
  377.                 if ((S.Length()==8)||(S.Length()==6))
  378.                   {
  379.                     S.Insert('-',4);
  380.                     S.Insert('-',2);
  381.                   }
  382.                 else if (S.Length()==4) S.Insert('-',2);
  383.                 else S="";
  384.               }
  385.             if (S.Length()>2)
  386.               {
  387.                 int Pos=S.Index('-');
  388.                 M=atoi(S.Before(Pos));
  389.                 if (M<1) M=1;
  390.                 else if (M>12) M=12;
  391.                 S=S.After(Pos);
  392.                 Pos=S.Index('-');
  393.                 if (Pos==NotFound)
  394.                   {
  395.                     D=atoi(S);
  396.                     if (D<1) D=1;
  397.                     else if (D>31) D=31;
  398.                     Y=TD.Year();
  399.                     if ((*this)>TDJ) Y--;
  400.                   }
  401.                 else
  402.                   {
  403.                     D=atoi(S.Before(Pos));
  404.                     if (D<1) D=1;
  405.                     else if (D>31) D=31;
  406.                     Y=atoi(S.After(Pos));
  407.                     if (Y<100) Y+=1900;
  408.                   }
  409.                 if ((Y!=0)&&(D>28))
  410.                   {
  411.                     if (M==2)
  412.                       {
  413.                         if (LeapYear(Y)) D=29;
  414.                         else D=28;
  415.                       }
  416.                     else if (D>DOM[M-1]) D=DOM[M-1];
  417.                   }
  418.               }
  419.           }
  420.       }
  421.     else
  422.       {
  423.         if (S(0)=='-') (*this)=TDJ-(atoi(S.After(0)));
  424.         else
  425.           {
  426.             S.ToLower();
  427.             if (S.Before(2)=="to") (*this)=TDJ;
  428.             else if (S(0)=='y') (*this)=TDJ-1;
  429.             else
  430.               {
  431.                 int WD=7;
  432.                 if (S(0)=='m') WD=0;
  433.                 else if (S(0)=='w') WD=2;
  434.                 else if (S(0)=='f') WD=4;
  435.                 else if (S(0)=='t')
  436.                   {
  437.                     if (S(1)=='u') WD=1;
  438.                     else if (S(1)=='h') WD=3;
  439.                   }
  440.                 else if (S(0)=='s')
  441.                   {
  442.                     if (S(1)=='a') WD=5;
  443.                     else if (S(1)=='u') WD=6;
  444.                   }
  445.                 if (WD<7)
  446.                   {
  447.                     while(TDJ.DOW()!=WD) TDJ--;
  448.                     (*this)=TDJ;
  449.                   }
  450.               }
  451.           }
  452.       }
  453.   }
  454.  
  455. //.parse
  456.  
  457. const char* MonthName[13]=
  458.   {"","January","February","March","April","May","June","July","August",
  459.    "September","October","November","December"};
  460. const char* WeekdayName[7]=
  461.   {"Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"};
  462.  
  463. String40 Date::MonthStr() const
  464.   {
  465.     String40 MS=MonthName[M];
  466.     return MS;
  467.   }
  468.  
  469. String40 Date::DayName() const
  470.   {
  471.     String40 DN=WeekdayName[DOW()];
  472.     return DN;
  473.   }
  474.  
  475. String40 JulianDate::DayName() const
  476.   {
  477.     String40 DN=WeekdayName[DOW()];
  478.     return DN;
  479.   }
  480.  
  481. //.parse
  482.  
  483. int Date::DOW() const
  484.   {
  485.     return (JulianDate(*this).DOW());
  486.   }
  487.  
  488. //.parse
  489.  
  490. String40 Date::FullDesc() const
  491.   {
  492.     String40 S;
  493.     if (Y!=0) S=DayName()+", "+MonthStr()+' '+Str(D)+", "+Str(Y);
  494.     return S;
  495.   }
  496.  
  497. //.parse
  498.  
  499. String40 Date::ShortDesc() const
  500.   {
  501.     String40 S;
  502.     if (Y!=0) S=MonthStr2()+'-'+DayStr()+"-"+Str(Y);
  503.     return S;
  504.   }
  505.  
  506. //.parse
  507.  
  508. String40 Date::RelativePastStr() const
  509.   {
  510.     String40 S;
  511.     if (Y!=0)
  512.       {
  513.         JulianDate TJ(Today());
  514.         JulianDate J(*this);
  515.         if (J==TJ) S="Today";
  516.         else if (TJ-J==1) S="Yesterday";
  517.         else if (InRange(TJ-J,0L,6L)) S=J.DayName(); // "Monday", "Tuesday"...
  518.         else S=MonthStr()+' '+Str(D)+", "+Str(Y);
  519.       }
  520.     return S;
  521.   }
  522.  
  523. //.parse
  524.  
  525. String40 JulianDate::RelativePastStr(Bool Alpha) const
  526.   {
  527.     String40 S;
  528.     if (J!=0)
  529.       {
  530.         JulianDate TJ(Today());
  531.         if (TJ==J) S="Today";
  532.         else if (TJ-J==1) S="Yesterday";
  533.         else if (InRange((TJ-J).Val(),0L,6L)) S=DayName(); // "Monday", "Tuesday"...
  534.         else
  535.           {
  536.             Date D(*this);
  537.             if (Alpha) S=D.MonthStr()+' '+Str(D.Day())+", "+Str(D.Year());
  538.             else S=D.ShortDesc();
  539.           }
  540.       }
  541.     return S;
  542.   }
  543.  
  544. //.parse
  545.  
  546. static BitSet16 Month31;
  547. static Bool Month31Set=False;
  548.  
  549. Bool Date::Valid() const
  550.   {
  551.     if (!Month31Set) Month31=BitSet16(1,3,5,7,8,10,12);
  552.     if (Y>4000) return False;
  553.     if (Y<0) return False;
  554.     if (M<1) return False;
  555.     if (M>12) return False;
  556.     if (D<1) return False;
  557.     if (D>31) return False;
  558.     if (Month31(M)) return True;
  559.     if (D>30) return False;
  560.     if (M!=2) return True;
  561.     if (D<29) return True;
  562.     if (LeapYear(Y)) return True;
  563.     return False;
  564.   }
  565.  
  566. //.parse
  567.  
  568. JulianDate JulianDate::operator+(long Days) const
  569.   {
  570.     JulianDate JJ=*this;
  571.     JJ.J+=Days;
  572.     return JJ;
  573.   }
  574.  
  575. JulianDate JulianDate::operator-(long Days) const
  576.   {
  577.     JulianDate JJ=*this;
  578.     JJ.J-=Days;
  579.     return JJ;
  580.   }
  581.  
  582. JulianDate JulianDate::operator++(int) // postfix operator
  583.   {
  584.     JulianDate OJ(*this);
  585.     J++;
  586.     return OJ;
  587.   }
  588.  
  589. JulianDate JulianDate::operator--(int) // postfix operator
  590.   {
  591.     JulianDate OJ(*this);
  592.     J--;
  593.     return OJ;
  594.   }
  595.  
  596.  
  597. //.parse
  598.  
  599. Date Today()
  600.   {
  601.     Registers R;
  602.     R.AH()=0x2a;
  603.     CallBIOS(33,R);
  604.     Date D(R.CX(),R.DH(),R.DL());
  605.     return D;
  606.   }
  607.  
  608. /*
  609.  
  610.   Moment class.  Remember that there are 1440 minutes in a day.
  611.   No consideration is taken for GMT or daylight savings time.  If you
  612.   need that sort of stuff, you can inherit this class and do your own
  613.   tweaking.
  614.  
  615. */
  616.  
  617. //.parse
  618.  
  619. Moment::Moment(const JulianDate& J, int Hour, int Minute)
  620.   {
  621.     M=J.J*MinutesInADay+Hour*60+Minute;
  622.   }
  623.  
  624. //.parse
  625.  
  626. Time CurTime()
  627.   {
  628.     struct time t;
  629.     gettime(&t);
  630.     Time T(t.ti_hour,t.ti_min,t.ti_sec);
  631.     return T;
  632.   }
  633.  
  634. //.parse
  635.  
  636. int CurMinCount()
  637.   {
  638.     struct time t;
  639.     gettime(&t);
  640.     int X=t.ti_min+t.ti_hour*60;
  641.     return X;
  642.   }
  643.  
  644. //.parse
  645.  
  646. Moment CurMoment()
  647.   {
  648.     date d;
  649.     getdate(&d);
  650.     Moment M(JulianDate(d.da_year,d.da_mon,d.da_day));
  651.     M+=CurMinCount();
  652.     return M;
  653.   }
  654.  
  655. //.parse
  656.  
  657. String40 Time::ShortDesc()
  658.   {
  659.     String40 S;
  660.     if ((H==0)&&(M==0)) S="midnight";
  661.     else if ((H==12)&&(M==0)) S="noon";
  662.     else
  663.       {
  664.         int Hour=H;
  665.         Bool AM=(H<12);
  666.         if (!AM) Hour-=12;
  667.         if (Hour==0) Hour=12;
  668.         S+=Str(Hour)+':'+Form("@@",M)+(AM?"am":"pm");
  669.       }
  670.     return S;
  671.   }
  672.  
  673. //.parse
  674.  
  675. String40 Time::Desc()
  676.   {
  677.     String40 St;
  678.     if ((H==0)&&(M==0)) St="midnight";
  679.     else if ((H==12)&&(M==0)) St="noon";
  680.     else
  681.       {
  682.         int Hour=H;
  683.         Bool AM=(H<12);
  684.         if (!AM) Hour-=12;
  685.         if (Hour==0) Hour=12;
  686.         St+=Str(Hour)+':'+Form("@@",M)+':'+Form("@@",S)+(AM?"am":"pm");
  687.       }
  688.     return St;
  689.   }
  690.  
  691. //.parse
  692.  
  693. Time::Time(const Moment& MM)
  694.   {
  695.     int X=int(MM%MinutesInADay);
  696.     S=0;
  697.     M=X%60;
  698.     H=X/60;
  699.   }
  700.  
  701. //.parse
  702.  
  703. String40 Moment::RelativeDesc()
  704.   {
  705.     JulianDate J=*this;
  706.     Date D(J);
  707.     String40 S=D.RelativePastStr()+' ';
  708.     Time T(*this);
  709.     S+=T.ShortDesc();
  710.     return S;
  711.   }
  712.  
  713. //.parse
  714.  
  715. String40 Moment::FullDesc()
  716.   {
  717.     JulianDate J=*this;
  718.     Date D(J);
  719.     String40 S=D.FullDesc()+' ';
  720.     Time T(*this);
  721.     S+=T.ShortDesc();
  722.     return S;
  723.   }
  724.  
  725. //.parse
  726.  
  727. String40 Moment::ShortDesc()
  728.   {
  729.     JulianDate J=*this;
  730.     Date D(J);
  731.     String40 S=D.ShortDesc()+' ';
  732.     Time T(*this);
  733.     S+=T.ShortDesc();
  734.     return S;
  735.   }
  736.  
  737. //.parse
  738.  
  739. Moment Moment::operator-(long X)
  740.   {
  741.     Moment MM=M;
  742.     MM.M-=X;
  743.     return MM;
  744.   }
  745.  
  746. //.parse
  747.  
  748. Moment Moment::operator+(long X)
  749.   {
  750.     Moment MM=M;
  751.     MM.M+=X;
  752.     return MM;
  753.   }
  754.  
  755.