Using the functions supplied in this component, we can easily implement a C++ class that represents abstract (mathematical) date values and performs a few common operations on them. The internal representation could be any of the three supported by this component; in this example, we will choose to represent the date value internally as a "serial date": class MyDate {
int d_serialDate;
friend MyDate operator+(const MyDate&, int);
friend MyDate operator+(int, const MyDate&);
friend int operator- (const MyDate&, const MyDate&);
friend bool operator==(const MyDate&, const MyDate&);
private:
explicit MyDate(int serialDate);
Next we define the public interface of the class, with function-level documentation conspicuously omitted (note, however, that reference implementations with preconditions asserted will follow): public:
enum Day {
SUN = 1,
MON = 2,
TUE = 3,
WED = 4,
THU = 5,
FRI = 6,
SAT = 7
};
static bool isValid(int year, int month, int day);
MyDate();
MyDate(const MyDate& original);
~MyDate();
MyDate& operator=(const MyDate& rhs);
MyDate& operator++();
MyDate& operator--();
MyDate& operator+=(int numDays);
MyDate& operator-=(int numDays);
void setYearMonthDay(int year, int month, int day);
bool setYearMonthDayIfValid(int year, int month, int day);
void getYearMonthDay(int *year, int *month, int *day) const;
int year() const;
int month() const;
int day() const;
Day dayOfWeek() const;
bool isLeapYear() const;
bsl::ostream& print(bsl::ostream& stream) const;
};
bool operator==(const MyDate& lhs, const MyDate& rhs);
bool operator!=(const MyDate& lhs, const MyDate& rhs);
bsl::ostream& operator<<(bsl::ostream& stream, const MyDate& rhs);
MyDate operator+(const MyDate& lhs, int rhs);
MyDate operator+(int lhs, const MyDate& rhs);
int operator-(const MyDate& lhs, const MyDate& rhs);
MyDate operator++(MyDate& object, int);
MyDate operator--(MyDate& object, int);
We now provide a reference implementation of each of the methods and free (operator) functions associated with the MyDate
class defined above (using bsls_assert
to identify preconditions and invariants where appropriate):
inline
MyDate::MyDate(int serialDate)
: d_serialDate(serialDate)
{
}
inline
bool MyDate::isValid(int year, int month, int day)
{
return bdlt::PosixDateImpUtil::isValidYearMonthDay(year, month, day);
}
inline
MyDate::MyDate()
: d_serialDate(1)
{
}
inline
MyDate::MyDate(const MyDate& original)
: d_serialDate(original.d_serialDate)
{
}
inline
MyDate::~MyDate()
{
}
inline
MyDate& MyDate::operator=(const MyDate& rhs)
{
d_serialDate = rhs.d_serialDate;
return *this;
}
inline
MyDate& MyDate::operator++()
{
++d_serialDate;
BSLS_ASSERT_SAFE(bdlt::PosixDateImpUtil::isValidSerial(d_serialDate));
return *this;
}
inline
MyDate& MyDate::operator--()
{
--d_serialDate;
BSLS_ASSERT_SAFE(bdlt::PosixDateImpUtil::isValidSerial(d_serialDate));
return *this;
}
inline
MyDate& MyDate::operator+=(int numDays)
{
d_serialDate += numDays;
BSLS_ASSERT_SAFE(bdlt::PosixDateImpUtil::isValidSerial(d_serialDate));
return *this;
}
inline
MyDate& MyDate::operator-=(int numDays)
{
d_serialDate -= numDays;
BSLS_ASSERT_SAFE(bdlt::PosixDateImpUtil::isValidSerial(d_serialDate));
return *this;
}
inline
void MyDate::setYearMonthDay(int year, int month, int day)
{
d_serialDate = bdlt::PosixDateImpUtil::ymdToSerial(year, month, day);
BSLS_ASSERT_SAFE(bdlt::PosixDateImpUtil::isValidSerial(d_serialDate));
}
inline
bool MyDate::setYearMonthDayIfValid(int year, int month, int day)
{
const int newDate = bdlt::PosixDateImpUtil::ymdToSerial(year,
month,
day);
if (bdlt::PosixDateImpUtil::isValidSerial(newDate)) {
d_serialDate = newDate;
return true;
}
return false;
}
inline
void MyDate::getYearMonthDay(int *year, int *month, int *day) const
{
bdlt::PosixDateImpUtil::serialToYmd(year, month, day, d_serialDate);
}
inline
int MyDate::year() const
{
return bdlt::PosixDateImpUtil::serialToYear(d_serialDate);
}
inline
int MyDate::month() const
{
return bdlt::PosixDateImpUtil::serialToMonth(d_serialDate);
}
inline
int MyDate::day() const
{
return bdlt::PosixDateImpUtil::serialToDay(d_serialDate);
}
inline
MyDate::Day MyDate::dayOfWeek() const
{
return MyDate::Day(bdlt::PosixDateImpUtil::serialToDayOfWeek(
d_serialDate));
}
inline
bool MyDate::isLeapYear() const
{
return bdlt::PosixDateImpUtil::isLeapYear(year());
}
inline
bool operator==(const MyDate& lhs, const MyDate& rhs)
{
return lhs.d_serialDate == rhs.d_serialDate;
}
inline
bool operator!=(const MyDate& lhs, const MyDate& rhs)
{
return !(lhs == rhs);
}
inline
bsl::ostream& operator<<(bsl::ostream& stream, const MyDate& rhs)
{
return rhs.print(stream);
}
inline
MyDate operator+(const MyDate& lhs, int rhs)
{
return MyDate(lhs.d_serialDate + rhs);
}
inline
MyDate operator+(int lhs, const MyDate& rhs)
{
return MyDate(lhs + rhs.d_serialDate);
}
inline
int operator-(const MyDate& lhs, const MyDate& rhs)
{
return lhs.d_serialDate - rhs.d_serialDate;
}
inline
MyDate operator++(MyDate& object, int)
{
MyDate tmp(object);
++object;
return tmp;
}
inline
MyDate operator--(MyDate& object, int)
{
MyDate tmp(object);
--object;
return tmp;
}
The following definitions would appropriately appear in the implementation (.cpp
) file: const char *const monthNames[] = {
0, "JAN", "FEB", "MAR", "APR",
"MAY", "JUN", "JUL", "AUG",
"SEP", "OCT", "NOV", "DEC"
};
bsl::ostream& MyDate::print(bsl::ostream& stream) const
{
if (!stream) {
return stream;
}
const int SIZE = 2 + 3 + 4 + 1;
char buf[SIZE];
int y, m, d;
bdlt::PosixDateImpUtil::serialToYmd(&y, &m, &d, d_serialDate);
buf[0] = d / 10 + '0';
buf[1] = d % 10 + '0';
bsl::memcpy(&buf[2], monthNames[m], 3);
buf[5] = y / 1000 + '0';
buf[6] = ((y % 1000) / 100) + '0';
buf[7] = ((y % 100) / 10) + '0';
buf[8] = y % 10 + '0';
buf[9] = 0;
stream << buf;
return stream;
}
The following snippets of code illustrate how to create and use a Mydate
object. First create a default object, d1
: MyDate d1; assert( 1 == d1.year());
assert( 1 == d1.month());
assert( 1 == d1.day());
Next, set d1
to July 4, 1776: d1.setYearMonthDay(1776, 7, 4); assert(1776 == d1.year());
assert( 7 == d1.month());
assert( 4 == d1.day());
Then create d2
as a copy of d1
: MyDate d2(d1); assert(1776 == d2.year());
assert( 7 == d2.month());
assert( 4 == d2.day());
Now, add six days to the value of d2
: d2 += 6; assert(1776 == d2.year());
assert( 7 == d2.month());
assert( 10 == d2.day());
Next subtract d1
from d2
, storing the difference (in days) in dDays
: int dDays = d2 - d1; assert(6 == dDays);
Finally, stream the value of d2
to stdout
: bsl::cout << d2 << bsl::endl;
The streaming operator produces the following output on stdout
: