home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Monster Media 1994 #1
/
monster.zip
/
monster
/
PROG_C
/
DATECL.ZIP
/
DATECL49.DOC
< prev
next >
Wrap
Text File
|
1994-01-26
|
26KB
|
591 lines
=======================================================
Documentation for "The Killer Date Class!" Version 4.00
=======================================================
History
=======
In the beginning Steve Marcus (CIS 72007,1233) posted a basic date
manipulation/arithmetic class produced with Borland C++ 2.0 in the
BPROGB forum, with a request for suggestions and enhancements. This was
on 6/19/91.
A rather enterprising gentleman by the name of Eric Simon (CIS 70540,1522)
accepted the challenge, and produced a new and improved version in the
course of a project he was developing at work. He contributed the results
to the forum on 6/29/91, also inviting enhancements and comments.
About that time yet another enterprising gentleman named Christopher Hill
developed a need for a universal date conversion routine for use in a
business project he was developing as well. Browsing the same forum, he
encountered Eric's class, which provided much of the functionality he needed
- the basic julian-gregorian and day of week conversion algorithms -
relieving him of the task of researching or re-inventing them. Eric had also
added overloaded + and - operators for incrementing date objects by integer
days, as well as several print functions. Chris needed additional features
for his implementations, thus was born versions 3.0 and 3.1(Hill & Simon).
Well, almost a year later I sent out an SOS for a date class so _I_ didn't
have to re-invent the wheel and lo-and-behold Chris responded. Thus begins
the saga of version 4.0! I would like to take this opportunity to do a
little witnessing: I looked all over for a date class that would suit my
needs! I reviewed many implementations from strangers and friends alike
and I am here to tell ya' folks, "It don't 'git no bedder 'n dis!" This
class is _VERY_ cool! Now I'm not trying to say that there's no more
room for enhancements (I'd really be crazy then!), but I am saying that if
your looking for a _GOOD_ date class (I'd say commercial quality because
I have yet to see a commercial product that implemented a date class to
my satisfaction!) then this is it! So jump in and add to it, make it
better and we'll SAVE THE WORLD! (Ok, so I got a little carried away at
the end. Just a little...)
No, but really...
This is a truly pleasing example of co-operation among professionals, and
an "object" study in the code reusability of OOP, resulting in three releases
of one class within a single month by three different analysts who have never
met, and yet another upgrade almost a year later by a fourth analyst (myself)
and none of us have yet to meet! Chris thanks Steve and Eric for their
inspiration and generousity, and I thank all three as well and hereby
contribute my additions to the public domain.
I believe any of us would welcome further comments, suggestions and
enhancements as well.
Good luck! May the quest for the perfect date class continue!
v4.9 Ly Minh Trí - 73062,512 01/26/94
v4.8 Clyde Ford - 71426,72 11/18/93
v4.7 Ly Minh Trí - 73062,512 09/20/93
v4.6 Ly Minh Trí - 73062,512 08/04/93
v4.5 Ly Minh Trí - 73062,512 06/21/93
v4.4 Ly Minh Trí - 73062,512 06/03/93
v4.3 Ly Minh Trí - 73062,512 03/24/93
v4.2 Ly Minh Trí - 73062,512 03/13/93
v4.1 Kenneth A. Argo - 71241,3635 03/07/93
v4.0 Charles Price - 70541,3651 06/27/92
v3.1 Hill & Simon - 08/05/91
v3.0 Christopher Hill - 72030,2606 07/11/91
v2.0 Eric Simon - 70540,1522 06/29/91
v1.0 Steve Marcus - 72007,1233 06/16/91
===============================================================================
TML - 01/26/94
Version 4.9 fixes the Date::AddMonths() member function. The problem was it
did not adjust the day value after the new month's value have been calculated.
For example, if the current date is '08/31/1993' and 6 months is added to it
using Date::AddMonths(), then the result is: 02/31/1994. Date::AddMonths()
will now set the day value as appropriate for the new month. If the day value
is greater than the # of days in that month, then it will roll the month over
to the next month and set the day value to the difference between the day
value and the # of days in the that month. Thanks to Patrick Cunningham this
bug.
This version also expands the Date::isDST() functionality by adding two new
member functions: Date::setDST() and Date::setSTD(). Date::setDST() sets the
month and day on which DST date begins. Likewise, Date::setSTD() sets the
month and day on which STD date begins. Thanks to Marcelos Cantos for this
suggestion.
*********************** WARNING TO BORLAND C++ USERS *********************
A couple of people have kindly informed me that the class Date is a pre-defined
class in Borland C++. Thus, you will have to rename this class to another name
like xDate, or DateCL or whatever is appropriate for your implementation!!!
*******************************************************************************
===============================================================================
TML - 11/18/93
Version 4.8 adds a new member function Date::isDST() which was contributed by
Clyde Ford (CIS 71426,72). Date::isDST() determines if the current date object
is "within daylight savings time as defined in the United States". If so, then
it will return 1, otherwise a 0 is returned.
Please note that my CIS address has changed to 73062,512. If anyone have
added new functions to DateClass and feel others may benefit from it, feel
free to send me your code so I may incorporate it into future versions of
DateClass. Or if you prefer, just incorporate the code, document your
additions and upload it...
===============================================================================
TML - 09/20/93
Version 4.7 un-fixes the serious bug in the code for unary operators ++/--. In
other words, they were originally correct. I guess I got really confused when
I last talked to Jorge.
Thanks to James M. Curran for informing me of this change. Also, James has a
new version of DateClass (5.0) currently in the works. I think all of us will
be very impress and receptive of his version!!!
===============================================================================
TML - 08/04/93
Version 4.6 fixes the Date::AddMonths() member function. It does not add or
subtract the number of months correctly.
Thanks to Patrick Cunningham for finding this bug!
===============================================================================
TML - 06/21/93
Version 4.5 fixes a very serious bug in the code for unary operators ++/--. I
confused myself with the formats for prefix and postfix operations. (I got
them reversed.) Jorge Padron was kind enough to inform me of my mistake.
I also removed the 'const' keyword from parameter statements for functions which
require variables to be passed by values (as opposed to pass by reference.) For
example,
Date operator + (const long i);
is changed to:
Date operator + (long i);
I did it in the first place because I was trying to be consistent, but I realize
that this can be confusing (especially those that are just learning C++). Jorge
also pointed this out to me.
===============================================================================
TML - 06/03/93
Version 4.4 adds a little validation to the value of the day and month when an
object is created via a string argument. For example, month must be from
(1..12) and day must be from (1..n) where 'n' is the number of days for the
given month.
Thus, the following statements:
Date myDate("02/31/1993");
cout << myDate.formatDate() << "\n";
will result in an "invalid date" output!
===============================================================================
TML - 3/15/93
Well, I must say, this is quite an impressive Date class!!! And I must
agree with Mr. Kenneth...it's probably one of the BEST (if not the best) Date
class I've seen so far (but then again, I've not seen too many!).
However, I thought it really could take more advantage of some of the better
features of C++ (ie. encapsulation!!!). Thus, I decided to take on the
challenge set forth by the aforementioned 'Date'-crazed group.
My changes are listed below in the Version 4.2 section. Please let me know
of any updates/changes that will happen in the future!!!
And ofcourse, we all welcome any comments/suggestions/participations!!!
Ly Minh Trí :)
===============================================================================
Implementation Notes
====================
All versions prior to 4.0 were written specifically for a Borland C++
compiler. However, version 4.0 was written specifically for
Microsoft C++ 7.0. I too have attempted to optimize the code including
the specification of const where applicable, the passing of references
where advisable, and the use of constructor initializers where needed.
However, I have not made an exhaustive analysis of this subject either.
To get the best overview of the class capabilities run the demo program.
It may not look pretty, but with a printout of a sample run and the code
you should be able to get a really good feel for it. I have included a
samples run at the end of this file in case someone doesn't want to
take the time to compile the demo program.
This ZIP file contains:
MAKEFILE - make file to compile & link the files for MSC 7.0
DATEDEMO.PRJ - project file for compiling under Borland C++ 3.1
DATECL48.DOC - this file
DATECL.H - the header file
DATECL.CPP - the member functions
DATEDEMO.CPP - a test program (and a messy one at that!)
DATECL.LIB - a lib file so you can use it even if you
don't have MSC7.0, or you just don't feel
like fussin' with it! (Added in v4.0)
Future possibilities for enhancement include
============================================
1. Adding a derived Time class, for those applications which require
the ability to track more than just dates. This would allow the
manipulation of times for all dates (not just since 1980), and
arithmetic calculations as well.
===============================================================================
Additions/Changes to Version 4.5
================================
- Correct the implementation code for the unary operators ++ and --. These
were reversed in version 4.2 to 4.3 (i.e. prefix was coded as postfix, and
postfix was coded as prefix).
- Removed 'const' keyword from parameter statments that requires variables to
be passed by value.
===============================================================================
Additions/Changes to Version 4.4
================================
- Add a little validation to value of the day and month when an object is
created via a string argument.
===============================================================================
Additions/Changes to Version 4.3
================================
- Add more flexibility in the constructor to support the many string formats
that are used by the Date class.
- Fix Date::Date(char *) and make it accept the string as a 'const' argument.
Also, make a copy of the string ('dat') before passing it to strtok() since
this function modifies its argument!
- Remove the smaller buffer ('buf') and make use of only one buffer to save
memory.
- Re-code the type cast operator to call formatDate() so the current format
and options will be applied to the resulting string.
- Changed year to 'int' type to support B.C.E. dates.
===============================================================================
Additions/Changes to Version 4.2
================================
- Made it compatible to both Borland C++ (v 3.1) and Microsoft C++ (v 7.0)
via #define switches. Define _BCC for Borland and _MSC for Microsoft.
See the GO.BAT batch file!
- Fix memory problems in Version 4.1. There were three 'deadly' memory
threats introduced by Version 4.1:
(a) In the destructor function, it is erroneous to delete buf without
referring to it as a vector of characters. The proper method
would be:
delete [] buf; // Must have the brackets!
Please review the section "The Free Store and Class Arrays" on
page 95-99 of the _C++ Tutorial_ from Microsoft's C++ package!
(b) In the Date::operator char *() function, variable buf was allocated
space every time the function was called. This causes memory leaks
when the same Date instance calls this operator function more than
once during its lifetime.
(c) Also in the Date::operator char *() function, variable buf was
assigned the address of the constant string BadDate without prior
release of the memory for buf.
- Modified the following functions to return a Date object instead of a
reference to a Date object!
Date operator + (const long i);
Date operator + (const int i);
Date operator - (const long i);
Date operator - (const int i);
Date operator ++ ();
Date operator ++ (int);
Date operator -- ();
Date operator -- (int);
This is important because in Version 4.0 and before, the binary operators
(+ and -) were declared to return references to Date objects since these
functions dynamically creates a Date object when the function is called.
However, there were no provisions for deleting these objects once they
leave the scope of the function.
In Version 4.1, Mr. Kenneth got rid of this problem of allocation by
forcing the compiler to generate code to allocate stack space to return
the objects. However, Mr. Kenneth 'forget?' to remove the references
declaration. Why would this cause problem? Because when the calling
program is expecting a reference in return (as opposed to a copy of the
object), then that reference will be invalid since after the function
terminates, the temporary object (used to return the value to the calling
program) will also be terminated. Thus, the reference to the object is
rendered obsolete.
To test this, I wrote the following program:
#include "datecls4.h"
#include "iostream.h"
void showDate(Date &dt)
{
cout << dt; // The (char *) type cast operator is in
} // effect here!
void main()
{
Date z("04/13/1967");
showDate(z+3);
}
RESULT:
*** destructor called *** // Temporary oject is destroyed
237/7/21
*** destructor called *** // Object 'z' is destroyed
As dictated by the result, the temporary object (created by the + operator)
is destroyed before its values are displayed.
By declaring the functions to return an actual Date object instead of a
reference, we force the compiler to make a copy of it and return it to the
calling program!
- Fix implementation of the prefix/postfix operators to properly reflect the
before/after syntax of the unary incrementor. (C++ provides only the
the facility to determine which type of operator is being used, but the
implementation is left to the programmer!)
- Moved all buffer variables to the class level and made them private static
member data.
. for the Date::formatDate() function, the buffer is renamed to 'cbuf'
. for the Date::Operator () function, the buffer is named 'buf'
- Move all publically declared variables/enums into the public portion of
the class. Also redefine the #define constants to an enum type. By doing
this, we are taking advantage of C++'s encapsulation feature and reduce
pollution of the global variable names. This concept is based on the ios
class. (ie. ios::hex, ios::dec, etc.)
- Also redeclare the 'friend' functions to be member functions (again, making
use of encapsulation!)
- Rewrote the Date::SetOption() function. (Made it more compact!)
- Made use of the 'const' feature of C++ to ensure the references returned by
most of the member functions will be non-modifiable by the calling program.
(ie. force them to make a copy of it if they want to modify it!)
- In the function Date::formatDate(), for the case Date::EUROPEAN and
Date::EUROPEAN, fix the code (day_of_week < 0) to (day_of_week < 1). Also
removed the statement strcat(cbuf, " ") and put the space into the
sprintf() statement:
sprintf( cbuf+strlen(cbuf), " %d", abs(year) );
===============================================================================
Additions/Changes to Version 4.1
================================
Fixed date display when using the * operator to get a string pointer.
The code would return xx/xx/ xx if you only supplied a 2 digit year.
Optimized the * operator so Invalid Dates would use a common "invalid date"
text pointer.
Fixed the +, - and * operators to get rid cases where memory leaks would
occur.
Fixed some variable casts so the code can be compiled with /W4
Added a destructor tp delete items created dynamically on behalf of the
object (ie. char *).
Release Documentation for Version 4.0
=====================================
Most of the modifications made to version 3.1 were to expand the public
interface. Below is a list of new features in v4.0:
1. Date &Set() - Sets self to current system date; this may also be
accomplished by passing initializing a date object like so:
Date oDate1("Today"); // See demo for examples
2. Date &Set(long lJulian) - Sets self to the specified julian date
3. Date &Set(int nMonth, int nDay, int nYear) - Sets self to specified
month, day, and year. The year must be 4 numbers long, not 2.
4. Date &AddWeeks(int nCount = 1) - Add or subtract(use a negative int)
a specified number of weeks to/from self
5. Date &AddMonths(int nCount = 1) - Add or subtract(use a negative int)
a specified number of months to/from self
6. Date &AddYears(int nCount = 1); - Add or subtract(use a negative int)
a specified number of years to/from self
7. int Day() const - Returns numeric day of the month for self
8. int DaysInMonth() - Returns number of days in month (1..31)
9. int FirstDOM() const - Returns the First Day Of Month for self as a
numeric (1..7)
10. char *CDOW() - Returns character Day Of Week ('Sunday'..'Saturday')
11. int NDOW() const - Returns the numeric day of the week for self(1..7)
12. int WOM() - Returns numeric Week Of Month (1..6)
13. int WOY() - Returns numeric Week Of Year (1..52)
14. char *CMonth() - Character Month name ("January")
15. int NMonth() const - Month Number (1..12)
16. Date BOM() - Returns a new date object that is the First Date Of
the Month in self. For example:
Date oDate1;
Date oDate2("Today");
oDate1 = oDate2.BOM();
17. Date EOM() - Returns a new date object that is the Last Date Of
the Month in self. (See example in 16 above)
18. int NYear4() const - Returns the numeric value of the year for self
in the form 1992.
19. Date BOY() - Returns a new date object that is the First Date Of
the Year in self. (See example 16 above)
20. Date EOY() - Returns a new date object that is the Last Date Of
the Year in self. (See example 16 above)
21. Added overloaded operators for + and - to accept int's.
22. Added overloaded operators for ++ and -- for Postfix notation
23. Switched from the Borland style DOS date structure(date) to the
Microsoft version(_dosdate_t).
Suggestions and general comments are always welcome!
Enjoy! Chuck :-}
Release Documentation for Version 3.1
=====================================
Subsequent to release 3.00, we (Hill & Simon) decided to collaborate on
several further releases of this date class. This, the first, contains two
new features, as well as a few minor bug fixes.
1. There was a minor bug in the original Computer Language julian/gregorian
date conversion routines having to do with negative years.
2. The isLeapYear function did not take into account that, prior to 1582,
years ending in 00 were also leap years.
3. The two-dimensional array of the number of days in each month has been
eliminated in favor of a computational approach.
4. The function Date::setFormat(XXXX) maintains a static variable (one
occurance for all Date objects, which controls the format which the
<< operator uses to print objects. "XXXX" can be MONTH, MDY, DAY, FULL,
or EUROPEAN. The setting defaults to MDY, but once altered, remains
altered until reset by another call to setFormat.
The function Date::setOption(Option, Action) maintains a similar static
variable which enables certain print formatting options. Available options
at this point are:
NO_CENTURY -- Suppress the printing of the century when
in the MDY format (ex: 01/01/91 instead of
01/01/1991).
DATE_ABBR -- Abbreviate month and day names when printing
in the MONTH, DAY, FULL or EUROPEAN formats.
(ex. MON, TUE, JAN, FEB, etc.) The length
or the abbreviation is controlled by a
DEFINED constant in DATECL31.HPP named
ABBR_LENGTH, preset to 3.
"Action" is either ON or OFF, and defaults to ON. (Example, the call
Date::setOption(NO_CENTURY) turns on the century suppression option, and
it remains set until the call Date::setOption(NO_CENTURY, OFF) is made.
More features, including further expanded print formatting features,
the derived Time class mentioned above, conversion into various calendar
formats (Jewish, Chinese, Arabic, etc.), ability to increment Date objects
by years and months instead of merely days, holiday computations, and more
are planned.
Sample run of DATEDEMO.EXE v4.0
===============================
Date Class v4.0 Demo
Saturday, October 20, 1962
Monday
Tuesday, October 10, 1995
Tuesday, October 30, 1962
5 October 1962
-14
8/6/1991
Tommorrow= Sunday, July 14, 1991
a1 (7-14-91) < 8-01-91 ? ==> TRUE
a1 (7-14-91) > 8-01-91 ? ==> FALSE
a1 (7-14-91)== 7-14-91 ? ==> TRUE
a1 (7-14-91)== a3 (7-14-91) ? ==> TRUE
a1 (7-14-91)== a4 (7-15-91) ? ==> FALSE
Today is: 6/28/1992
Today (a4) is: 6/28/1992
Today + 4 is: 7/2/1992
Today - 4 is: 6/24/1992
=========== Leap Year Test ===========
Wednesday, January 15, 1992 Leap day of year: 15
Tuesday, February 16, 1993 non-Leap day of year: 47
=========== eom test ==============
b1.eom() (s/b 2/28/91) ==> 2/28/1991
================== getDate test =====================
a1.getDate() (s/b 2/16/1993) ==> 2/16/1993
================== string assignment test ====================
a1 as a string (s/b 2/16/1993) ==> 2/16/1993
================== setFormat test ============================
a1 (s/b FULL format) ==> Tuesday, February 16, 1993
a1 (s/b EUROPEAN format) ==> 16 February 1993
================== setOption test ============================
Date abbreviation ON
a1 (s/b MONTH format) ==> Feb
a1 (s/b DAY format) ==> Tue
a1 (s/b FULL format) ==> Tue, Feb 16, 1993
a1 (s/b EUROPEAN format) ==> 16 Feb 1993
Century suppression ON
a1 (s/b MDY format) ==> 2/16/93
Century suppression OFF
a1 (s/b MDY format) ==> 2/16/1993
Century suppression ON
a1 (s/b MDY format) ==> 2/16/93
a1 (s/b FULL format) ==> Tue, Feb 16, 1993
=============== Version 4.0 Enhancement Test =================
---------- Set Stuff -----------
First, 'Set' to today...
Before 'Set' => Saturday, November 26, 1966
After 'Set' => Sunday, June 28, 1992
Set to 11/26/66 => Saturday, November 26, 1966
Current Julian => 2439455
Set to Julian 2450000L => Tuesday, October 10, 1995
See! => 2450000
---------- Add Stuff -----------
Start => Tuesday, October 10, 1995
Add 4 Weeks => Tuesday, November 7, 1995
Sub 1 Month => Saturday, October 7, 1995
Add 2 Years => Tuesday, October 7, 1997
---------- Misc Stuff -----------
The date aboves' day of the month is => 7
There are 31 days in this month.
The first day of this month lands on 4
This day happens to be Tuesday
the 3 day of the week,
on the 41 week of the year,
on the 2 week of the month,
(which is October)
the 10nth month in the year.
The year alone is 1997
---------- First and Last Stuff -----------
The first date of this month is Monday, June 1, 1992
The last date of this month is Tuesday, June 30, 1992
The first date of this year is Wednesday, January 1, 1992
The last date of this year is Thursday, December 31, 1992