#ifndef CHRONO_UTILITIES_TIMESPAN_H #define CHRONO_UTILITIES_TIMESPAN_H #include "../global.h" #include #include #include #include namespace CppUtilities { class DateTime; /*! * \brief Specifies the output format. * \sa TimeSpan::toString() */ enum class TimeSpanOutputFormat { Normal, /**< the normal form of specifying a time interval: hh:mm:ss */ WithMeasures, /**< measures are used, eg.: 34 d 5 h 10 min 7 s 31 ms */ TotalSeconds, /**< total seconds (as returned by totalSeconds()), eg. 2304.342 */ }; class CPP_UTILITIES_EXPORT TimeSpan { friend class DateTime; public: using TickType = std::int64_t; explicit constexpr TimeSpan(); explicit constexpr TimeSpan(TickType ticks); static constexpr TimeSpan fromMilliseconds(double milliseconds); static constexpr TimeSpan fromSeconds(double seconds); static constexpr TimeSpan fromMinutes(double minutes); static constexpr TimeSpan fromHours(double hours); static constexpr TimeSpan fromDays(double days); #ifdef CHRONO_UTILITIES_TIMESPAN_INTEGER_SCALE_OVERLOADS static constexpr TimeSpan fromMilliseconds(TickType milliseconds); static constexpr TimeSpan fromSeconds(TickType seconds); static constexpr TimeSpan fromMinutes(TickType minutes); static constexpr TimeSpan fromHours(TickType hours); static constexpr TimeSpan fromDays(TickType days); #endif static TimeSpan fromString(const std::string &str, char separator = ':'); static TimeSpan fromString(const char *str, char separator); static constexpr TimeSpan negativeInfinity(); static constexpr TimeSpan infinity(); TickType &ticks(); constexpr TickType totalTicks() const; constexpr double totalMicroseconds() const; constexpr double totalMilliseconds() const; constexpr double totalSeconds() const; constexpr double totalMinutes() const; constexpr double totalHours() const; constexpr double totalDays() const; constexpr int nanoseconds() const; constexpr int microseconds() const; constexpr int milliseconds() const; constexpr int seconds() const; constexpr int minutes() const; constexpr int hours() const; constexpr int days() const; constexpr bool operator==(const TimeSpan &other) const; constexpr bool operator!=(const TimeSpan &other) const; constexpr bool operator<(const TimeSpan &other) const; constexpr bool operator>(const TimeSpan &other) const; constexpr bool operator<=(const TimeSpan &other) const; constexpr bool operator>=(const TimeSpan &other) const; constexpr TimeSpan operator+(const TimeSpan &other) const; constexpr TimeSpan operator-(const TimeSpan &other) const; constexpr TimeSpan operator*(double factor) const; constexpr TimeSpan operator/(double factor) const; #ifdef CHRONO_UTILITIES_TIMESPAN_INTEGER_SCALE_OVERLOADS constexpr TimeSpan operator*(TickType factor) const; constexpr TimeSpan operator/(TickType factor) const; #endif constexpr double operator/(TimeSpan other) const; TimeSpan &operator+=(const TimeSpan &other); TimeSpan &operator-=(const TimeSpan &other); TimeSpan &operator*=(double factor); TimeSpan &operator/=(double factor); #ifdef CHRONO_UTILITIES_TIMESPAN_INTEGER_SCALE_OVERLOADS TimeSpan &operator*=(TickType factor); TimeSpan &operator/=(TickType factor); #endif std::string toString(TimeSpanOutputFormat format = TimeSpanOutputFormat::Normal, bool fullSeconds = false) const; void toString(std::string &result, TimeSpanOutputFormat format = TimeSpanOutputFormat::Normal, bool fullSeconds = false) const; constexpr bool isNull() const; constexpr bool isNegative() const; constexpr bool isNegativeInfinity() const; constexpr bool isInfinity() const; static constexpr TickType nanosecondsPerTick = 100L; static constexpr TickType ticksPerMicrosecond = 10L; static constexpr TickType ticksPerMillisecond = 10000L; static constexpr TickType ticksPerSecond = 10000000L; static constexpr TickType ticksPerMinute = 600000000L; static constexpr TickType ticksPerHour = 36000000000L; static constexpr TickType ticksPerDay = 864000000000L; private: TickType m_ticks; }; /*! * \brief Constructs a new instance of the TimeSpan class with zero ticks. */ constexpr inline TimeSpan::TimeSpan() : m_ticks(0) { } /*! * \brief Constructs a new instance of the TimeSpan class with the specified number of ticks. */ constexpr inline TimeSpan::TimeSpan(TickType ticks) : m_ticks(ticks) { } /*! * \brief Constructs a new instance of the TimeSpan class with the specified number of milliseconds. */ constexpr inline TimeSpan TimeSpan::fromMilliseconds(double milliseconds) { return TimeSpan(static_cast(milliseconds * static_cast(ticksPerMillisecond))); } /*! * \brief Constructs a new instance of the TimeSpan class with the specified number of seconds. */ constexpr inline TimeSpan TimeSpan::fromSeconds(double seconds) { return TimeSpan(static_cast(seconds * static_cast(ticksPerSecond))); } /*! * \brief Constructs a new instance of the TimeSpan class with the specified number of minutes. */ constexpr inline TimeSpan TimeSpan::fromMinutes(double minutes) { return TimeSpan(static_cast(minutes * static_cast(ticksPerMinute))); } /*! * \brief Constructs a new instance of the TimeSpan class with the specified number of hours. */ constexpr inline TimeSpan TimeSpan::fromHours(double hours) { return TimeSpan(static_cast(hours * static_cast(ticksPerHour))); } /*! * \brief Constructs a new instance of the TimeSpan class with the specified number of days. */ constexpr inline TimeSpan TimeSpan::fromDays(double days) { return TimeSpan(static_cast(days * static_cast(ticksPerDay))); } #ifdef CHRONO_UTILITIES_TIMESPAN_INTEGER_SCALE_OVERLOADS /*! * \brief Constructs a new instance of the TimeSpan class with the specified number of milliseconds. */ constexpr inline TimeSpan TimeSpan::fromMilliseconds(TickType milliseconds) { return TimeSpan(milliseconds * ticksPerMillisecond); } /*! * \brief Constructs a new instance of the TimeSpan class with the specified number of seconds. */ constexpr inline TimeSpan TimeSpan::fromSeconds(TickType seconds) { return TimeSpan(seconds * ticksPerSecond); } /*! * \brief Constructs a new instance of the TimeSpan class with the specified number of minutes. */ constexpr inline TimeSpan TimeSpan::fromMinutes(TickType minutes) { return TimeSpan(minutes * ticksPerMinute); } /*! * \brief Constructs a new instance of the TimeSpan class with the specified number of hours. */ constexpr inline TimeSpan TimeSpan::fromHours(TickType hours) { return TimeSpan(hours * ticksPerHour); } /*! * \brief Constructs a new instance of the TimeSpan class with the specified number of days. */ constexpr inline TimeSpan TimeSpan::fromDays(TickType days) { return TimeSpan(days * ticksPerDay); } #endif /*! * \brief Parses the given std::string as TimeSpan. * \throws Throws a ConversionException if the specified \a str does not match the expected format. * * The expected format is "days:hours:minutes:seconds", eg. "5:31:4.521" for 5 hours, 31 minutes * and 4.521 seconds. So parts at the front can be omitted and the parts can be fractions. The * colon can be changed by specifying another \a separator. */ inline TimeSpan TimeSpan::fromString(const std::string &str, char separator) { return TimeSpan::fromString(str.data(), separator); } /*! * \brief Constructs a new instance of the TimeSpan class with the minimal number of ticks. */ constexpr inline TimeSpan TimeSpan::negativeInfinity() { return TimeSpan(std::numeric_limits::min()); } /*! * \brief Constructs a new instance of the TimeSpan class with the maximal number of ticks. */ constexpr inline TimeSpan TimeSpan::infinity() { return TimeSpan(std::numeric_limits::max()); } /*! * \brief Returns a mutable reference to the total ticks. */ inline TimeSpan::TickType &TimeSpan::ticks() { return m_ticks; } /*! * \brief Returns the number of ticks that represent the value of the current TimeSpan class. */ constexpr inline TimeSpan::TickType TimeSpan::totalTicks() const { return m_ticks; } /*! * \brief Returns the value of the current TimeSpan class expressed in whole and fractional microseconds. */ constexpr double TimeSpan::totalMicroseconds() const { return static_cast(m_ticks) / static_cast(ticksPerMicrosecond); } /*! * \brief Returns the value of the current TimeSpan class expressed in whole and fractional milliseconds. */ constexpr inline double TimeSpan::totalMilliseconds() const { return static_cast(m_ticks) / static_cast(ticksPerMillisecond); } /*! * \brief Returns the value of the current TimeSpan class expressed in whole and fractional seconds. */ constexpr inline double TimeSpan::totalSeconds() const { return static_cast(m_ticks) / static_cast(ticksPerSecond); } /*! * \brief Returns the value of the current TimeSpan class expressed in whole and fractional minutes. */ constexpr inline double TimeSpan::totalMinutes() const { return static_cast(m_ticks) / static_cast(ticksPerMinute); } /*! * \brief Returns the value of the current TimeSpan class expressed in whole and fractional hours. */ constexpr inline double TimeSpan::totalHours() const { return static_cast(m_ticks) / static_cast(ticksPerHour); } /*! * \brief Returns the value of the current TimeSpan class expressed in whole and fractional days. */ constexpr inline double TimeSpan::totalDays() const { return static_cast(m_ticks) / static_cast(ticksPerDay); } /*! * \brief Returns the nanoseconds component of the time interval represented by the current TimeSpan class. * \remarks The accuracy of the TimeSpan class is 100-nanoseconds. Hence the returned value * will always have two zeros at the end (in decimal representation). */ constexpr int TimeSpan::nanoseconds() const { return static_cast(m_ticks % 10l * TimeSpan::nanosecondsPerTick); } /*! * \brief Returns the microseconds component of the time interval represented by the current TimeSpan class. */ constexpr int TimeSpan::microseconds() const { return static_cast((m_ticks / ticksPerMicrosecond) % 1000l); } /*! * \brief Returns the milliseconds component of the time interval represented by the current TimeSpan class. */ constexpr inline int TimeSpan::milliseconds() const { return static_cast((m_ticks / ticksPerMillisecond) % 1000l); } /*! * \brief Returns the seconds component of the time interval represented by the current TimeSpan class. */ constexpr inline int TimeSpan::seconds() const { return static_cast((m_ticks / ticksPerSecond) % 60l); } /*! * \brief Returns the minutes component of the time interval represented by the current TimeSpan class. */ constexpr inline int TimeSpan::minutes() const { return static_cast((m_ticks / ticksPerMinute) % 60l); } /*! * \brief Returns the hours component of the time interval represented by the current TimeSpan class. */ constexpr inline int TimeSpan::hours() const { return static_cast((m_ticks / ticksPerHour) % 24l); } /*! * \brief Returns the days component of the time interval represented by the current TimeSpan class. */ constexpr inline int TimeSpan::days() const { return static_cast((m_ticks / ticksPerDay)); } /*! * \brief Indicates whether two TimeSpan instances are equal. */ constexpr inline bool TimeSpan::operator==(const TimeSpan &other) const { return m_ticks == other.m_ticks; } /*! * \brief Indicates whether two TimeSpan instances are not equal. */ constexpr inline bool TimeSpan::operator!=(const TimeSpan &other) const { return m_ticks != other.m_ticks; } /*! * \brief Indicates whether a specified TimeSpan is less than another specified TimeSpan. */ constexpr inline bool TimeSpan::operator<(const TimeSpan &other) const { return m_ticks < other.m_ticks; } /*! * \brief Indicates whether a specified TimeSpan is greater than another specified TimeSpan. */ constexpr inline bool TimeSpan::operator>(const TimeSpan &other) const { return m_ticks > other.m_ticks; } /*! * \brief Indicates whether a specified TimeSpan is less or equal than another specified TimeSpan. */ constexpr inline bool TimeSpan::operator<=(const TimeSpan &other) const { return m_ticks <= other.m_ticks; } /*! * \brief Indicates whether a specified TimeSpan is greater or equal than another specified TimeSpan. */ constexpr inline bool TimeSpan::operator>=(const TimeSpan &other) const { return m_ticks >= other.m_ticks; } /*! * \brief Adds two TimeSpan instances. */ constexpr inline TimeSpan TimeSpan::operator+(const TimeSpan &other) const { return TimeSpan(m_ticks + other.m_ticks); } /*! * \brief Subtracts one TimeSpan instance from another. */ constexpr inline TimeSpan TimeSpan::operator-(const TimeSpan &other) const { return TimeSpan(m_ticks - other.m_ticks); } /*! * \brief Multiplies a TimeSpan by the specified \a factor. */ constexpr inline TimeSpan TimeSpan::operator*(double factor) const { return TimeSpan(static_cast(static_cast(m_ticks) * factor)); } /*! * \brief Divides a TimeSpan by the specified \a factor. */ constexpr inline TimeSpan TimeSpan::operator/(double factor) const { return TimeSpan(static_cast(static_cast(m_ticks) / factor)); } #ifdef CHRONO_UTILITIES_TIMESPAN_INTEGER_SCALE_OVERLOADS /*! * \brief Multiplies a TimeSpan by the specified \a factor. */ constexpr inline TimeSpan TimeSpan::operator*(std::int64_t factor) const { return TimeSpan(m_ticks * factor); } /*! * \brief Divides a TimeSpan by the specified \a factor. */ constexpr inline TimeSpan TimeSpan::operator/(std::int64_t factor) const { return TimeSpan(m_ticks / factor); } #endif /*! * \brief Computes the ratio between two TimeSpan instances. */ constexpr inline double TimeSpan::operator/(TimeSpan other) const { return static_cast(m_ticks) / static_cast(other.m_ticks); } /*! * \brief Adds another TimeSpan to the current instance. */ inline TimeSpan &TimeSpan::operator+=(const TimeSpan &other) { m_ticks += other.m_ticks; return *this; } /*! * \brief Subtracts another TimeSpan from the current instance. */ inline TimeSpan &TimeSpan::operator-=(const TimeSpan &other) { m_ticks -= other.m_ticks; return *this; } /*! * \brief Multiplies the current instance by the specified \a factor. */ inline TimeSpan &TimeSpan::operator*=(double factor) { m_ticks = static_cast(static_cast(m_ticks) * factor); return *this; } /*! * \brief Divides the current instance by the specified \a factor. */ inline TimeSpan &TimeSpan::operator/=(double factor) { m_ticks = static_cast(static_cast(m_ticks) / factor); return *this; } #ifdef CHRONO_UTILITIES_TIMESPAN_INTEGER_SCALE_OVERLOADS /*! * \brief Multiplies the current instance by the specified \a factor. */ inline TimeSpan &TimeSpan::operator*=(std::int64_t factor) { m_ticks *= factor; return *this; } /*! * \brief Divides the current instance by the specified \a factor. */ inline TimeSpan &TimeSpan::operator/=(std::int64_t factor) { m_ticks /= factor; return *this; } #endif /*! * \brief Converts the value of the current TimeSpan object to its equivalent std::string representation * according the given \a format. * * If \a fullSeconds is true the time interval will be rounded to full seconds. */ inline std::string TimeSpan::toString(TimeSpanOutputFormat format, bool fullSeconds) const { std::string result; toString(result, format, fullSeconds); return result; } /*! * \brief Returns true if the time interval represented by the current TimeSpan class is null. */ constexpr inline bool TimeSpan::isNull() const { return m_ticks == 0; } /*! * \brief Returns true if the time interval represented by the current TimeSpan class is negative. */ constexpr inline bool TimeSpan::isNegative() const { return m_ticks < 0; } /*! * \brief Returns whether the time interval represented by the current instance is the smallest representable TimeSpan. */ constexpr inline bool TimeSpan::isNegativeInfinity() const { return m_ticks == std::numeric_limits::min(); } /*! * \brief Returns whether the time interval represented by the current instance is the longest representable TimeSpan. */ constexpr inline bool TimeSpan::isInfinity() const { return m_ticks == std::numeric_limits::max(); } } // namespace CppUtilities namespace std { /// \brief Computes the hash for the CppUtilities::TimeSpan instance. template <> struct hash { inline size_t operator()(const CppUtilities::TimeSpan &timeSpan) const { return hash()(timeSpan.totalTicks()); } }; } // namespace std #endif // CHRONO_UTILITIES_TIMESPAN_H