Output of file : WTIME.C contained in archive : WLIB.ZIP
#include "WLocal.h"
#pragma hdrstop

// copyright (c) 1993 by Paul Wheaton, Banana Programming
// 1916 Brooks #205, Missoula, MT 59801
//
// phone: (406)543-1928
// CompuServe: 72707,207
// Internet: [email protected]
// BBS: (406)543-8234 (The Montana Banana BBS)

extern int DOM[12];//={31,28,31,30,31,30,31,31,30,31,30,31};

//.parse

/*

Converting Julian to Gregorian dates and back. According to the Gregorian
Calendar Principle:

Each year has 365 days in it
EXCEPT years that are evenly divisible by 4 (366 days)
EXCEPT years that are evenly divisible by 100 (365 days)
EXCEPT years that are evenly divisible by 400 (366 days)

Most four year chunks (a quad) are 1461 days.
Most 100 year chunks (a century) are 36,524 days.
All 400 year chunks (quad century) are 116,877 days.
In theory, the first year (Year 0000) was a leap year.

If you wanted to, you could assume that there are 365.2425 days in the
average year. If you do try this, remember that floating point math can
throw you a little bit of round off error - add 0.0000000001 to everything.

I prefer to use integer math since I feel I have more control and more speed.

The way I calculate it, all Quads will have four years where the first year
is 366 days and each one after that is 365 days. EXCEPT for a Quad that is the

*/

Bool LeapYear(int Year)
{
if ((Year%400)==0) return True;
if ((Year%100)==0) return False;
if ((Year%4)==0) return True;
return False;
}

static const long Q=1461L; // number of days in four years (quad)
static const long C=36524L; // century
static const long QC=146097L; // four centuries.
int DOM[12]={31,28,31,30,31,30,31,31,30,31,30,31};
// days of the month

static void ConvertJulianToGregorian(long J, int& Y, int& M, int& D)
{
long NumQC=J/QC;
Y=int(NumQC)*400;
J-=(QC*NumQC);
long NumC=0;
if (J>(C+1))
{
J-=(C+1);
Y+=100;
NumC=J/C;
Y+=int(NumC)*100;
J-=NumC*C;
NumC++;
}
if ((NumC>0)&&(J>(Q-1)))
{
J-=(Q-1);
Y+=4;
}
long NumQ=J/Q;
Y+=int(NumQ)*4;
J-=NumQ*Q;
int Jul=int(J); // no more need for long int math
if (LeapYear(Y))
{
if (Jul>=366)
{
Jul-=366;
Y++;
}
else if (Jul==59) // Jan 1, would have Jul = 0, Feb 29 would have Jul=59
{
M=2;
D=29;
return;
}
else if (Jul>59) Jul--;
}
while (Jul>=365)
{
Jul-=365;
Y++;
}
M=0;
while(DOM[M]<=Jul)
{
Jul-=DOM[M];
M++;
}
M++;
D=Jul+1;
}

static long ConvertGregorianToJulian(int Y, int M, int D)
{
Bool Leap=LeapYear(Y-(Y%4));
int NumQC=Y/400;
Y-=NumQC*400;
long J=NumQC*QC;
int NumC=Y/100;
if (NumC>0)
{
Y-=NumC*100;
J+=(NumC*C)+1; // the first century has one more day
}
int NumQ=Y/4;
Y-=NumQ*4;
if ((NumC!=0)&&(NumQ>0))
{
// generally, the first Q doesn't have a leap year
J+=1460;
NumQ--;
}
J+=NumQ*Q;
if (Leap)
{
if (Y>0)
{
J+=366;
Y--;
}
else if (M>2) J++;
}
while (Y>0)
{
J+=365;
Y--;
}
int I;
For(I,M-1) J+=DOM[I];
J+=(D-1);
return J;
}

Date::Date(const JulianDate& J)
{
ConvertJulianToGregorian(J.J,Y,M,D);
}

void Date::operator=(const JulianDate& J)
{
ConvertJulianToGregorian(J.J,Y,M,D);
}

Bool Date::operator==(const JulianDate& X) const
{
long J=ConvertGregorianToJulian(Y,M,D);
return (J==X.J);
}

Bool Date::operator<=(const JulianDate& X) const
{
long J=ConvertGregorianToJulian(Y,M,D);
return (J<=X.J);
}

Bool Date::operator>=(const JulianDate& X) const
{
long J=ConvertGregorianToJulian(Y,M,D);
return (J>=X.J);
}

Bool Date::operator!=(const JulianDate& X) const
{
long J=ConvertGregorianToJulian(Y,M,D);
return (J!=X.J);
}

Bool Date::operator<(const JulianDate& X) const
{
long J=ConvertGregorianToJulian(Y,M,D);
return (J<=X.J);
}

Bool Date::operator>(const JulianDate& X) const
{
long J=ConvertGregorianToJulian(Y,M,D);
return (J>=X.J);
}

JulianDate Date::operator+(long Days) const
{
JulianDate J(ConvertGregorianToJulian(Y,M,D)+Days);
return J;
}

JulianDate Date::operator-(long Days) const
{
JulianDate J(ConvertGregorianToJulian(Y,M,D)-Days);
return J;
}

long Date::operator-(const JulianDate& X) const
{
long J=ConvertGregorianToJulian(Y,M,D);
J-=X.J;
return J;
}

JulianDate Date::operator++(int)
{
JulianDate J(*this);
ConvertJulianToGregorian(J.J+1,Y,M,D);
return J; // return the original value since this is a post inc
}

JulianDate Date::operator--(int)
{
JulianDate J(*this);
ConvertJulianToGregorian(J.J-1,Y,M,D);
return J; // return the original value since this is a post dec
}

JulianDate Date::operator++()
{
JulianDate J(*this);
J.J++;
ConvertJulianToGregorian(J.J,Y,M,D);
return J; // return the original value since this is a post inc
}

JulianDate Date::operator--()
{
JulianDate J(*this);
J.J--;
ConvertJulianToGregorian(J.J,Y,M,D);
return J; // return the original value since this is a post dec
}

void Date::operator+=(long Days)
{
JulianDate J(*this);
J+=Days;
ConvertJulianToGregorian(J.J,Y,M,D);
}

void Date::operator-=(long Days)
{
JulianDate J(*this);
J-=Days;
ConvertJulianToGregorian(J.J,Y,M,D);
}

//////////////////// Julian stuff

JulianDate::JulianDate(int Year, int Month, int Day)
{
J=ConvertGregorianToJulian(Year,Month,Day);
}

JulianDate::JulianDate(const Date& D)
{
J=ConvertGregorianToJulian(D.Y,D.M,D.D);
}

int JulianDate::Year() const
{
int Y,M,D;
ConvertJulianToGregorian(J,Y,M,D);
return Y;
}

int JulianDate::Month() const
{
int Y,M,D;
ConvertJulianToGregorian(J,Y,M,D);
return M;
}

int JulianDate::Day() const
{
int Y,M,D;
ConvertJulianToGregorian(J,Y,M,D);
return D;
}

void JulianDate::SetYear(int Year)
{
int Y,M,D;
ConvertJulianToGregorian(J,Y,M,D);
Y=Year;
J=ConvertGregorianToJulian(Y,M,D);
}

void JulianDate::SetMonth(int Month)
{
int Y,M,D;
ConvertJulianToGregorian(J,Y,M,D);
M=Month;
J=ConvertGregorianToJulian(Y,M,D);
}

void JulianDate::SetDay(int Day)
{
int Y,M,D;
ConvertJulianToGregorian(J,Y,M,D);
D=Day;
J=ConvertGregorianToJulian(Y,M,D);
}

void JulianDate::operator=(const Date& D)
{
J=ConvertGregorianToJulian(D.Y,D.M,D.D);
}

//.parse

String40 Date::DayStr() const
{
char* X="00";
X[0]=D/10+'0';
X[1]=D%10+'0';
return String40(X);
}

//.parse

String40 Date::MonthStr2() const
{
char* X="00";
X[0]=M/10+'0';
X[1]=M%10+'0';
return String40(X);
}

//.parse

Date::Date(const char* Text)
{
String40 S=Text;
/* possible cases:
to Today
tom Tomorrow
y Yesterday
m tu w th f sa su (last) Mon, Tue, Wed, Thu, Fri, Sat, Sun

-30 (30 days ago)
+30 (30 days from now)

01011993
010193
0101
1-1-1993
1-1-93
1-1
1/1/1993
1/1/93
1/1
*/
S.Trim();
Y=0;
M=1;
D=1;
Date TD=Today();
JulianDate TDJ(TD);
int Pos;
while((Pos=S.Index('/'))!=NotFound) S[Pos]='-';
if (isdigit(S(0)))
{
if (S!="0")
{
if (!S.Find('-'))
{
if ((S.Length()==8)||(S.Length()==6))
{
S.Insert('-',4);
S.Insert('-',2);
}
else if (S.Length()==4) S.Insert('-',2);
else S="";
}
if (S.Length()>2)
{
int Pos=S.Index('-');
M=atoi(S.Before(Pos));
if (M<1) M=1;
else if (M>12) M=12;
S=S.After(Pos);
Pos=S.Index('-');
if (Pos==NotFound)
{
D=atoi(S);
if (D<1) D=1;
else if (D>31) D=31;
Y=TD.Year();
if ((*this)>TDJ) Y--;
}
else
{
D=atoi(S.Before(Pos));

if (D<1) D=1;
else if (D>31) D=31;
Y=atoi(S.After(Pos));
if (Y<100) Y+=1900;
}
if ((Y!=0)&&(D>28))
{
if (M==2)
{
if (LeapYear(Y)) D=29;
else D=28;
}
else if (D>DOM[M-1]) D=DOM[M-1];
}
}
}
}
else
{
if (S(0)=='-') (*this)=TDJ-(atoi(S.After(0)));
else if (S(0)=='+') (*this)=TDJ+(atoi(S.After(0)));
else
{
S.ToLower();
if (S.Before(3)=="tom") (*this)=TDJ+1;
else if (S.Before(2)=="to") (*this)=TDJ;
else if (S(0)=='y') (*this)=TDJ-1;
else
{
int WD=7;
if (S(0)=='m') WD=0;
else if (S(0)=='w') WD=2;
else if (S(0)=='f') WD=4;
else if (S(0)=='t')
{
if (S(1)=='u') WD=1;
else if (S(1)=='h') WD=3;
}
else if (S(0)=='s')
{
if (S(1)=='a') WD=5;
else if (S(1)=='u') WD=6;
}
if (WD<7)
{
while(TDJ.DOW()!=WD) TDJ--;
(*this)=TDJ;
}
}
}
}
}

//.parse

const char* MonthName[13]=
{"","January","February","March","April","May","June","July","August",
"September","October","November","December"};
const char* WeekdayName[7]=
{"Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"};

String40 Date::MonthStr() const
{
String40 MS=MonthName[M];
return MS;
}

String40 Date::DayName() const
{
String40 DN=WeekdayName[DOW()];
return DN;
}

String40 JulianDate::DayName() const
{
String40 DN=WeekdayName[DOW()];
return DN;
}

//.parse

int Date::DOW() const
{
return (JulianDate(*this).DOW());
}

//.parse

String40 Date::FullDesc() const
{
String40 S;
if (Y!=0) S=DayName()+", "+MonthStr()+' '+Str(D)+", "+Str(Y);
return S;
}

//.parse

String40 JulianDate::FullDesc() const
{
Date D=*this;
return D.FullDesc();
}

//.parse

String40 Date::ShortDesc() const
{
String40 S;
if (Y!=0) S=MonthStr2()+'-'+DayStr()+"-"+Str(Y);
return S;
}

//.parse

String40 Date::RelativePastStr() const
{
String40 S;
if (Y!=0)
{
JulianDate TJ(Today());
JulianDate J(*this);
if (J==TJ) S="Today";
else if (TJ-J==1) S="Yesterday";
else if (InRange(TJ-J,0L,6L)) S=J.DayName(); // "Monday", "Tuesday"...
else S=MonthStr()+' '+Str(D)+", "+Str(Y);
}
return S;
}

//.parse

String40 JulianDate::RelativePastStr(Bool Alpha) const
{
String40 S;
if (J!=0)
{
JulianDate TJ(Today());
if (TJ==J) S="Today";
else if (TJ-J==1) S="Yesterday";
else if (InRange((TJ-J).Val(),0L,6L)) S=DayName(); // "Monday", "Tuesday"...
else
{
Date D(*this);
if (Alpha) S=D.MonthStr()+' '+Str(D.Day())+", "+Str(D.Year());
else S=D.ShortDesc();
}
}
return S;
}

//.parse

static BitSet16 Month31;
static Bool Month31Set=False;

Bool Date::Valid() const
{
if (!Month31Set) Month31=BitSet16(1,3,5,7,8,10,12);
if (Y>4000) return False;
if (Y<0) return False;
if (M<1) return False;
if (M>12) return False;
if (D<1) return False;
if (D>31) return False;
if (Month31(M)) return True;
if (D>30) return False;
if (M!=2) return True;
if (D<29) return True;
if (LeapYear(Y)) return True;
return False;
}

//.parse

JulianDate JulianDate::operator+(long Days) const
{
JulianDate JJ=*this;
JJ.J+=Days;
return JJ;
}

JulianDate JulianDate::operator-(long Days) const
{
JulianDate JJ=*this;
JJ.J-=Days;
return JJ;
}

JulianDate JulianDate::operator++(int) // postfix operator
{
JulianDate OJ(*this);
J++;
return OJ;
}

JulianDate JulianDate::operator--(int) // postfix operator
{
JulianDate OJ(*this);
J--;
return OJ;
}

//.parse

Date Today()
{
Registers R;
R.AH()=0x2a;
CallBIOS(33,R);
Date D(R.CX(),R.DH(),R.DL());
return D;
}

/*

Moment class. Remember that there are 1440 minutes in a day.
No consideration is taken for GMT or daylight savings time. If you
need that sort of stuff, you can inherit this class and do your own
tweaking.

*/

//.parse

Moment::Moment(const JulianDate& J, int Hour, int Minute)
{
}

//.parse

Time CurTime()
{
struct time t;
gettime(&t);
Time T(t.ti_hour,t.ti_min,t.ti_sec);
return T;
}

//.parse

int CurMinCount()
{
struct time t;
gettime(&t);
int X=t.ti_min+t.ti_hour*60;
return X;
}

//.parse

Moment CurMoment()
{
date d;
getdate(&d);
Moment M(JulianDate(d.da_year,d.da_mon,d.da_day));
M+=CurMinCount();
return M;
}

//.parse

String40 Time::ShortDesc()
{
String40 S;
if ((H==0)&&(M==0)) S="midnight";
else if ((H==12)&&(M==0)) S="noon";
else
{
int Hour=H;
Bool AM=(H<12);
if (!AM) Hour-=12;
if (Hour==0) Hour=12;
S+=Str(Hour)+':'+Form("@@",M)+(AM?"am":"pm");
}
return S;
}

//.parse

String40 Time::Desc()
{
String40 St;
if ((H==0)&&(M==0)) St="midnight";
else if ((H==12)&&(M==0)) St="noon";
else
{
int Hour=H;
Bool AM=(H<12);
if (!AM) Hour-=12;
if (Hour==0) Hour=12;
St+=Str(Hour)+':'+Form("@@",M)+':'+Form("@@",S)+(AM?"am":"pm");
}
return St;
}

//.parse

Time::Time(const Moment& MM)
{
S=0;
M=X%60;
H=X/60;
}

//.parse

String40 Moment::RelativeDesc()
{
JulianDate J=*this;
Date D(J);
String40 S=D.RelativePastStr()+' ';
Time T(*this);
S+=T.ShortDesc();
return S;
}

//.parse

String40 Moment::FullDesc()
{
JulianDate J=*this;
Date D(J);
String40 S=D.FullDesc()+' ';
Time T(*this);
S+=T.ShortDesc();
return S;
}

//.parse

String40 Moment::ShortDesc()
{
JulianDate J=*this;
Date D(J);
String40 S=D.ShortDesc()+' ';
Time T(*this);
S+=T.ShortDesc();
return S;
}

//.parse

Moment Moment::operator-(long X)
{
Moment MM=M;
MM.M-=X;
return MM;
}

//.parse

Moment Moment::operator+(long X)
{
Moment MM=M;
MM.M+=X;
return MM;
}



### 3 Responses to “Category : C++ Source CodeArchive   : WLIB.ZIPFilename : WTIME.C”

1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/