#include "Date.hpp" #include //////////////////////////// // Private static helpers // //////////////////////////// // Determine whether the specified year is a leap year. bool Date::is_leap_year( unsigned int const year ) { // February 1582 occurred before the Gregorian-calendar // transition, so 1582 uses the Julian rule here. if ( year <= 1582 ) { return year%4 == 0; } return (year%400 == 0) || ((year%4 == 0) && (year%100 != 0)); } // Return the number of days in the specified month. unsigned int Date::days_in_month( unsigned int const year, unsigned int const month ) { assert( month >= 1 ); assert( month <= 12 ); if ( month == 2 ) { return is_leap_year( year ) ? 29 : 28; } if ( (month == 4) || (month == 6) || (month == 9) || (month == 11) ) { return 30; } return 31; } // Determine whether the specified values form a valid date. bool Date::is_valid( unsigned int const year, unsigned int const month, unsigned int const day ) { if ( year == 0 ) { return false; } if ( (month < 1) || (month > 12) ) { return false; } if ( (day < 1) || (day > days_in_month( year, month )) ) { return false; } // The Gregorian calendar followed October 4, 1582, // with October 15, 1582. if ( (year == 1582) && (month == 10) && (day >= 5) && (day <= 14) ) { return false; } return true; } ///////////////// // Constructor // ///////////////// // Construct the specified date. Date::Date( unsigned int const year, unsigned int const month, unsigned int const day ): year_{ year }, month_{ month }, day_{ day } { assert( is_valid( year_, month_, day_ ) ); } ///////////////////// // Date components // ///////////////////// // Return the year. unsigned int Date::year() const { return year_; } // Return the month. unsigned int Date::month() const { return month_; } // Return the day. unsigned int Date::day() const { return day_; } /////////////////////////// // Incrementing the date // /////////////////////////// // Move to the next date and return this object. Date &Date::operator++() { // The Gregorian calendar followed October 4, 1582, // with October 15, 1582. if ( (year_ == 1582) && (month_ == 10) && (day_ == 4) ) { day_ = 15; } else if ( day_ < days_in_month( year_, month_ ) ) { ++day_; } else if ( month_ < 12 ) { day_ = 1; ++month_; } else { day_ = 1; month_ = 1; ++year_; } return *this; } // Move to the next date and return the previous value. Date Date::operator++( int ) { Date old_date{ *this }; ++(*this); return old_date; } /////////////////////////// // Decrementing the date // /////////////////////////// // Move to the previous date and return this object. Date &Date::operator--() { // There is no supported date before January 1, 1. assert( (year_ != 1) || (month_ != 1) || (day_ != 1) ); // The Julian calendar ended on October 4, 1582. if ( (year_ == 1582) && (month_ == 10) && (day_ == 15) ) { day_ = 4; } else if ( day_ > 1 ) { --day_; } else if ( month_ > 1 ) { --month_; day_ = days_in_month( year_, month_ ); } else { --year_; month_ = 12; day_ = 31; } return *this; } // Move to the previous date and return the previous value. Date Date::operator--( int ) { Date old_date{ *this }; --(*this); return old_date; } /////////////////////////// // String representation // /////////////////////////// // Return a string representation of this date. std::string Date::to_string() const { std::string result{ std::to_string( year_ ) + "-" }; if ( month_ < 10 ) { result += "0"; } result += std::to_string( month_ ) + "-"; if ( day_ < 10 ) { result += "0"; } result += std::to_string( day_ ); return result; } /////////////////// // Stream output // /////////////////// // Insert date into an output stream. std::ostream &operator<<( std::ostream &out, Date const &date ) { out << date.to_string(); return out; }