Operator Overloading Implementation of a C++ Date Class
Date Comparison Operators
Equality check:
bool Date::operator==(const Date& other) const
{
return year_ == other.year_
&& month_ == other.month_
&& day_ == other.day_;
}
Inequality check can reuse the equality implemantation:
bool Date::operator!=(const Date& other) const
{
return !(*this == other);
}
Less than comparison:
bool Date::operator<(const Date& other) const
{
if (year_ != other.year_) {
return year_ < other.year_;
}
if (month_ != other.month_) {
return month_ < other.month_;
}
return day_ < other.day_;
}
Less than or equal comparison:
bool Date::operator<=(const Date& other) const
{
return *this < other || *this == other;
}
All remaining comparison operators (>, >=) can be derived by reusing the existing implementations:
bool Date::operator>(const Date& other) const
{
return !(*this <= other);
}
bool Date::operator>=(const Date& other) const
{
return !(*this < other);
}
Helper Function: Get Days in Month
We use a static lookup array to store standard month days, and add special handling for leap year February:
int Date::getMonthDays(int year, int month) const
{
assert(month > 0 && month < 13);
static int daysPerMonth[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))) {
return 29;
}
return daysPerMonth[month];
}
Add Days to a Date
We implement += first that modifies the current object, then + creates a copy and reuses += to avoid modifying the original date:
Date& Date::operator+=(int addDays)
{
day_ += addDays;
while (day_ > getMonthDays(year_, month_)) {
day_ -= getMonthDays(year_, month_);
month_++;
if (month_ > 12) {
year_++;
month_ = 1;
}
}
return *this;
}
Date Date::operator+(int addDays) const
{
Date temp = *this;
temp += addDays;
return temp;
}
Subtract Days from a Date
Similar to adding days, we use the same pattern of implementing -= firrst then reusing it for -:
Date& Date::operator-=(int subDays)
{
day_ -= subDays;
while (day_ <= 0) {
month_--;
if (month_ < 1) {
year_--;
month_ = 12;
}
day_ += getMonthDays(year_, month_);
}
return *this;
}
Date Date::operator-(int subDays) const
{
Date temp = *this;
temp -= subDays;
return temp;
}
Prefix and Postfix Increment/Decrement
To distinguish prefix and postfix overloads, postfix operators accept a dummy int parameter:
// Prefix increment: ++date
Date& Date::operator++()
{
*this += 1;
return *this;
}
// Postfix increment: date++
Date Date::operator++(int)
{
Date temp = *this;
*this += 1;
return temp;
}
// Prefix decrement: --date
Date& Date::operator--()
{
*this -= 1;
return *this;
}
// Postfix decrement: date--
Date Date::operator--(int)
{
Date temp = *this;
*this -= 1;
return temp;
}
Calculate Days Between Two Dates
Count the number of days by incrementing the smaller date until it matches the larger date:
int Date::operator-(const Date& other) const
{
int resultSign = 1;
Date larger = *this;
Date smaller = other;
if (*this < other) {
resultSign = -1;
larger = other;
smaller = *this;
}
int dayCount = 0;
while (smaller != larger) {
++smaller;
++dayCount;
}
return dayCount * resultSign;
}
Date Validation
Check if a constructed date is valid:
bool Date::isValid() const
{
if (year_ <= 0 || month_ < 1 || month_ > 12) {
return false;
}
return day_ >= 1 && day_ <= getMonthDays(year_, month_);
}
Stream Operator Overloading
Stream insertion (<<) and extraction (>>) cannot be member functions (since the left operand is the stream object), so we implement them as non-member functions with friend access to private members, and return stream references to support chaining:
Add friend declarations inside the Date class:
friend ostream& operator<<(ostream& out, const Date& date);
friend istream& operator>>(istream& in, Date& date);
Implementation of stream ensertion:
ostream& operator<<(ostream& out, const Date& date)
{
out << date.year_ << "/" << date.month_ << "/" << date.day_ << endl;
return out;
}
Implementation of stream extraction with input validation:
istream& operator>>(istream& in, Date& date)
{
while (true) {
in >> date.year_ >> date.month_ >> date.day_;
if (date.isValid()) {
break;
}
cout << "Invalid date entered, please re-enter: " << endl;
}
return in;
}
Full Header File (Date.h)
#pragma once
#include <iostream>
#include <cassert>
using namespace std;
class Date
{
public:
Date(int year = 1, int month = 1, int day = 1);
bool isValid() const;
// Comparison operators
bool operator<(const Date& other) const;
bool operator<=(const Date& other) const;
bool operator>(const Date& other) const;
bool operator>=(const Date& other) const;
bool operator==(const Date& other) const;
bool operator!=(const Date& other) const;
// Arithmetic operators
Date& operator+=(int addDays);
Date operator+(int addDays) const;
Date& operator-=(int subDays);
Date operator-(int subDays) const;
// Increment/decrement
Date& operator++();
Date operator++(int);
Date& operator--();
Date operator--(int);
// Days between two dates
int operator-(const Date& other) const;
private:
int getMonthDays(int year, int month) const;
int year_;
int month_;
int day_;
friend ostream& operator<<(ostream& out, const Date& d);
friend istream& operator>>(istream& in, Date& d);
};
ostream& operator<<(ostream& out, const Date& d);
istream& operator>>(istream& in, Date& d);
Full Source File (Date.cpp)
#include "Date.h"
Date::Date(int year, int month, int day)
{
year_ = year;
month_ = month;
day_ = day;
if (!isValid()) {
cout << "Warning: Constructed invalid date" << endl;
}
}
bool Date::isValid() const
{
if (year_ <= 0 || month_ < 1 || month_ > 12) {
return false;
}
return day_ >= 1 && day_ <= getMonthDays(year_, month_);
}
int Date::getMonthDays(int year, int month) const
{
assert(month > 0 && month < 13);
static int daysMap[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))) {
return 29;
}
return daysMap[month];
}
bool Date::operator<(const Date& other) const
{
if (year_ != other.year_) {
return year_ < other.year_;
}
if (month_ != other.month_) {
return month_ < other.month_;
}
return day_ < other.day_;
}
bool Date::operator<=(const Date& other) const
{
return *this < other || *this == other;
}
bool Date::operator>(const Date& other) const
{
return !(*this <= other);
}
bool Date::operator>=(const Date& other) const
{
return !(*this < other);
}
bool Date::operator==(const Date& other) const
{
return year_ == other.year_ && month_ == other.month_ && day_ == other.day_;
}
bool Date::operator!=(const Date& other) const
{
return !(*this == other);
}
Date& Date::operator+=(int addDays)
{
day_ += addDays;
while (day_ > getMonthDays(year_, month_)) {
day_ -= getMonthDays(year_, month_);
month_++;
if (month_ > 12) {
year_++;
month_ = 1;
}
}
return *this;
}
Date Date::operator+(int addDays) const
{
Date temp = *this;
temp += addDays;
return temp;
}
Date& Date::operator-=(int subDays)
{
day_ -= subDays;
while (day_ <= 0) {
month_--;
if (month_ < 1) {
year_--;
month_ = 12;
}
day_ += getMonthDays(year_, month_);
}
return *this;
}
Date Date::operator-(int subDays) const
{
Date temp = *this;
temp -= subDays;
return temp;
}
Date& Date::operator++()
{
*this += 1;
return *this;
}
Date Date::operator++(int)
{
Date temp = *this;
*this += 1;
return temp;
}
Date& Date::operator--()
{
*this -= 1;
return *this;
}
Date Date::operator--(int)
{
Date temp = *this;
*this -= 1;
return temp;
}
int Date::operator-(const Date& other) const
{
int resultSign = 1;
Date maxDate = *this;
Date minDate = other;
if (*this < other) {
resultSign = -1;
maxDate = other;
minDate = *this;
}
int daysBetween = 0;
while (minDate != maxDate) {
++minDate;
++daysBetween;
}
return daysBetween * resultSign;
}
ostream& operator<<(ostream& out, const Date& date)
{
out << date.year_ << "年" << date.month_ << "月" << date.day_ << "日" << endl;
return out;
}
istream& operator>>(istream& in, Date& date)
{
while (true) {
cout << "Enter year month day: ";
in >> date.year_ >> date.month_ >> date.day_;
if (date.isValid()) {
break;
}
cout << "Invalid date, please try again" << endl;
}
return in;
}