#include "Time_hms.hpp" #include #include ////////////////// // Constructors // ////////////////// // Construct a non-negative time. Time_hms::Time_hms( std::uint32_t const hours, unsigned int const minutes, unsigned int const seconds ): hours_{ hours }, minutes_{ 0 }, seconds_{ 0 }, is_negative_{ false } { if ( minutes >= 60 ) { throw std::invalid_argument{ "minutes must be between 0 and 59" }; } if ( seconds >= 60 ) { throw std::invalid_argument{ "seconds must be between 0 and 59" }; } minutes_ = static_cast( minutes ); seconds_ = static_cast( seconds ); } // Construct a time from a sign and magnitude. // - This is a private constructor. Time_hms::Time_hms( std::uint32_t const hours, std::uint8_t const minutes, std::uint8_t const seconds, bool const is_negative ): hours_{ hours }, minutes_{ minutes }, seconds_{ seconds }, is_negative_{ is_negative && (hours != 0 || minutes != 0 || seconds != 0) } { // Everything is in the initialization } /////////////////////////////////////////////// // The hours, minutes, and seconds of a time // /////////////////////////////////////////////// // Return whether this time is negative. bool Time_hms::negative() const { return is_negative_; } // Return the hour component. std::uint32_t Time_hms::hours() const { return hours_; } // Return the minute component. std::uint8_t Time_hms::minutes() const { return minutes_; } // Return the second component. std::uint8_t Time_hms::seconds() const { return seconds_; } //////////////////////////////////////////// // Boolean-valued functions and operators // //////////////////////////////////////////// // Test if two times are equal. bool Time_hms::operator==( Time_hms const &other ) const { return (is_negative_ == other.is_negative_) && (hours_ == other.hours_) && (minutes_ == other.minutes_) && (seconds_ == other.seconds_); } // Test if two times are different. bool Time_hms::operator!=( Time_hms const &other ) const { return !(*this == other); } // Test if the left-hand time is less than the right-hand time. bool Time_hms::operator<( Time_hms const &other ) const { // A negative time is always less than a non-negative time. if ( is_negative_ != other.is_negative_ ) { return is_negative_; } if ( is_negative_ ) { return (hours_ > other.hours_) || ((hours_ == other.hours_) && (minutes_ > other.minutes_)) || ((hours_ == other.hours_) && (minutes_ == other.minutes_) && (seconds_ > other.seconds_)); } else { return (hours_ < other.hours_) || ((hours_ == other.hours_) && (minutes_ < other.minutes_)) || ((hours_ == other.hours_) && (minutes_ == other.minutes_) && (seconds_ < other.seconds_)); } } // Test if the left-hand time is less than or equal to the right-hand time. bool Time_hms::operator<=( Time_hms const &other ) const { return (*this < other) || (*this == other); } // Test if the left-hand time is greater than or equal to the right-hand time. bool Time_hms::operator>=( Time_hms const &other ) const { return (other < *this) || (other == *this); } // Test if the left-hand time is greater than the right-hand time. bool Time_hms::operator>( Time_hms const &other ) const { return other < *this; } ///////////////////////////////// // The unary operators + and - // ///////////////////////////////// // Return this time. Time_hms Time_hms::operator+() const { return *this; } // Return the additive inverse of this time. Time_hms Time_hms::operator-() const { return Time_hms{ hours_, minutes_, seconds_, !is_negative_ }; } ////////////////////////////// // The binary operators // // Time{...} + Time{...} // // Time{...} - Time{...} // ////////////////////////////// // Add another time. Time_hms Time_hms::operator+( Time_hms const &other ) const { Time_hms result{ *this }; return result += other; } // Subtract another time. Time_hms Time_hms::operator-( Time_hms const &other ) const { Time_hms result{ *this }; return result -= other; } /////////////////////////////////////// // The compound assignment operators // // Time{...} += Time{...} // // Time{...} -= Time{...} // /////////////////////////////////////// // Add another time to this time. Time_hms &Time_hms::operator+=( Time_hms const &other ) { if ( is_negative_ != other.is_negative_ ) { return *this -= -other; } // Add the seconds, carrying into minutes if necessary. // - The 0U indicates this is to be an unsigned addition unsigned int const seconds_sum{ 0U + seconds_ + other.seconds_ }; seconds_ = seconds_sum%60; // Add the minutes, including any carry from seconds. unsigned int const minutes_sum{ minutes_ + other.minutes_ + seconds_sum/60 }; minutes_ = minutes_sum%60; // Add the hours, including any carry from minutes. // Bounds checking would be appropriate here if // the number of hours could exceed the 32-bit range. hours_ += other.hours_ + minutes_sum/60; return *this; } // Subtract another time from this time. Time_hms &Time_hms::operator-=( Time_hms const &other ) { if ( is_negative_ != other.is_negative_ ) { return *this += -other; } // Determine which magnitude is larger. bool const this_is_larger{ (hours_ > other.hours_) || ((hours_ == other.hours_) && (minutes_ > other.minutes_)) || ((hours_ == other.hours_) && (minutes_ == other.minutes_) && (seconds_ >= other.seconds_)) }; // Subtract the smaller magnitude from the larger. if ( this_is_larger ) { unsigned int seconds_borrowed{ 0 }; unsigned int minutes_borrowed{ 0 }; // Borrow one minute if necessary. if ( seconds_ < other.seconds_ ) { seconds_borrowed = 60; minutes_borrowed = 1; } seconds_ = seconds_ + seconds_borrowed - other.seconds_; unsigned int hours_borrowed{ 0 }; // Borrow one hour if necessary. if ( minutes_ < other.minutes_ + minutes_borrowed ) { hours_borrowed = 1; } minutes_ = minutes_ + 60*hours_borrowed - other.minutes_ - minutes_borrowed; hours_ -= other.hours_ + hours_borrowed; } else { unsigned int minutes_borrowed{ 0 }; unsigned int hours_borrowed{ 0 }; // Borrow one minute from the other magnitude if necessary. if ( other.seconds_ < seconds_ ) { minutes_borrowed = 1; } unsigned int const seconds_difference{ other.seconds_ + 60*minutes_borrowed - seconds_ }; // Borrow one hour from the other magnitude if necessary. if ( other.minutes_ < minutes_ + minutes_borrowed ) { hours_borrowed = 1; } unsigned int const minutes_difference{ other.minutes_ + 60*hours_borrowed - minutes_ - minutes_borrowed }; hours_ = other.hours_ - hours_ - hours_borrowed; minutes_ = minutes_difference; seconds_ = seconds_difference; is_negative_ = !is_negative_; } // Zero must never be represented as negative. if ( hours_ == 0 && minutes_ == 0 && seconds_ == 0 ) { is_negative_ = false; } return *this; } /////////////////////////////////////////// // The increment and decrement operators // // ++time time++ // // --time time-- // /////////////////////////////////////////// // Increment this time by one second. Time_hms &Time_hms::operator++() { *this += Time_hms{ 0, 0, 1 }; return *this; } // Increment this time by one second, returning the original time. Time_hms Time_hms::operator++( int ) { Time_hms original{ *this }; ++(*this); return original; } // Decrement this time by one second. Time_hms &Time_hms::operator--() { *this -= Time_hms{ 0, 0, 1 }; return *this; } // Decrement this time by one second, returning the original time. Time_hms Time_hms::operator--( int ) { Time_hms original{ *this }; --(*this); return original; } /////////////////////////////// // std::string and std::cout // /////////////////////////////// // Return a string representation of this time. std::string Time_hms::to_string() const { std::string result{}; if ( is_negative_ ) { result += "-"; } result += std::to_string( hours_ ); result += ":"; if ( minutes_ < 10 ) { result += "0"; } result += std::to_string( minutes_ ); result += ":"; if ( seconds_ < 10 ) { result += "0"; } result += std::to_string( seconds_ ); return result; } // Insert a time into an output stream. std::ostream &operator<<( std::ostream &out, Time_hms const &time ) { return out << time.to_string(); }