1 #ifndef CHRONO_UTILITIES_TIMESPAN_H
2 #define CHRONO_UTILITIES_TIMESPAN_H
3 
4 #include "../global.h"
5 
6 #include <cstdint>
7 #include <functional>
8 #include <limits>
9 #include <string>
10 
11 namespace CppUtilities {
12 
13 class DateTime;
14 
15 /*!
16  * \brief Specifies the output format.
17  * \sa TimeSpan::toString()
18  */
19 enum class TimeSpanOutputFormat {
20     Normal, /**< the normal form of specifying a time interval: hh:mm:ss */
21     WithMeasures, /**< measures are used, eg.: 34 d 5 h 10 min 7 s 31 ms */
22     TotalSeconds, /**< total seconds (as returned by totalSeconds()), eg. 2304.342 */
23 };
24 
25 class CPP_UTILITIES_EXPORT TimeSpan {
26     friend class DateTime;
27 
28 public:
29     explicit constexpr TimeSpan();
30     explicit constexpr TimeSpan(std::int64_t ticks);
31 
32     static constexpr TimeSpan fromMilliseconds(double milliseconds);
33     static constexpr TimeSpan fromSeconds(double seconds);
34     static constexpr TimeSpan fromMinutes(double minutes);
35     static constexpr TimeSpan fromHours(double hours);
36     static constexpr TimeSpan fromDays(double days);
37     static TimeSpan fromString(const std::string &str, char separator = ':');
38     static TimeSpan fromString(const char *str, char separator);
39     static constexpr TimeSpan negativeInfinity();
40     static constexpr TimeSpan infinity();
41 
42     std::int64_t &ticks();
43     constexpr std::int64_t totalTicks() const;
44     constexpr double totalMicroseconds() const;
45     constexpr double totalMilliseconds() const;
46     constexpr double totalSeconds() const;
47     constexpr double totalMinutes() const;
48     constexpr double totalHours() const;
49     constexpr double totalDays() const;
50 
51     constexpr int nanoseconds() const;
52     constexpr int microseconds() const;
53     constexpr int milliseconds() const;
54     constexpr int seconds() const;
55     constexpr int minutes() const;
56     constexpr int hours() const;
57     constexpr int days() const;
58 
59     constexpr bool operator==(const TimeSpan &other) const;
60     constexpr bool operator!=(const TimeSpan &other) const;
61     constexpr bool operator<(const TimeSpan &other) const;
62     constexpr bool operator>(const TimeSpan &other) const;
63     constexpr bool operator<=(const TimeSpan &other) const;
64     constexpr bool operator>=(const TimeSpan &other) const;
65     constexpr TimeSpan operator+(const TimeSpan &other) const;
66     constexpr TimeSpan operator-(const TimeSpan &other) const;
67     constexpr TimeSpan operator*(double factor) const;
68     constexpr TimeSpan operator/(double factor) const;
69     constexpr double operator/(TimeSpan other) const;
70     TimeSpan &operator+=(const TimeSpan &other);
71     TimeSpan &operator-=(const TimeSpan &other);
72     TimeSpan &operator*=(double factor);
73     TimeSpan &operator/=(double factor);
74 
75     std::string toString(TimeSpanOutputFormat format = TimeSpanOutputFormat::Normal, bool fullSeconds = false) const;
76     void toString(std::string &result, TimeSpanOutputFormat format = TimeSpanOutputFormat::Normal, bool fullSeconds = false) const;
77     constexpr bool isNull() const;
78     constexpr bool isNegative() const;
79     constexpr bool isNegativeInfinity() const;
80     constexpr bool isInfinity() const;
81 
82     static constexpr std::int64_t nanosecondsPerTick = 100uL;
83     static constexpr std::int64_t ticksPerMicrosecond = 10uL;
84     static constexpr std::int64_t ticksPerMillisecond = 10000uL;
85     static constexpr std::int64_t ticksPerSecond = 10000000uL;
86     static constexpr std::int64_t ticksPerMinute = 600000000uL;
87     static constexpr std::int64_t ticksPerHour = 36000000000uL;
88     static constexpr std::int64_t ticksPerDay = 864000000000uL;
89 
90 private:
91     std::int64_t m_ticks;
92 };
93 
94 /*!
95  * \brief Constructs a new instance of the TimeSpan class with zero ticks.
96  */
TimeSpan()97 constexpr inline TimeSpan::TimeSpan()
98     : m_ticks(0)
99 {
100 }
101 
102 /*!
103  * \brief Constructs a new instance of the TimeSpan class with the specified number of ticks.
104  */
TimeSpan(std::int64_t ticks)105 constexpr inline TimeSpan::TimeSpan(std::int64_t ticks)
106     : m_ticks(ticks)
107 {
108 }
109 
110 /*!
111  * \brief Constructs a new instance of the TimeSpan class with the specified number of milliseconds.
112  */
fromMilliseconds(double milliseconds)113 constexpr inline TimeSpan TimeSpan::fromMilliseconds(double milliseconds)
114 {
115     return TimeSpan(static_cast<std::int64_t>(milliseconds * static_cast<double>(ticksPerMillisecond)));
116 }
117 
118 /*!
119  * \brief Constructs a new instance of the TimeSpan class with the specified number of seconds.
120  */
fromSeconds(double seconds)121 constexpr inline TimeSpan TimeSpan::fromSeconds(double seconds)
122 {
123     return TimeSpan(static_cast<std::int64_t>(seconds * static_cast<double>(ticksPerSecond)));
124 }
125 
126 /*!
127  * \brief Constructs a new instance of the TimeSpan class with the specified number of minutes.
128  */
fromMinutes(double minutes)129 constexpr inline TimeSpan TimeSpan::fromMinutes(double minutes)
130 {
131     return TimeSpan(static_cast<std::int64_t>(minutes * static_cast<double>(ticksPerMinute)));
132 }
133 
134 /*!
135  * \brief Constructs a new instance of the TimeSpan class with the specified number of hours.
136  */
fromHours(double hours)137 constexpr inline TimeSpan TimeSpan::fromHours(double hours)
138 {
139     return TimeSpan(static_cast<std::int64_t>(hours * static_cast<double>(ticksPerHour)));
140 }
141 
142 /*!
143  * \brief Constructs a new instance of the TimeSpan class with the specified number of days.
144  */
fromDays(double days)145 constexpr inline TimeSpan TimeSpan::fromDays(double days)
146 {
147     return TimeSpan(static_cast<std::int64_t>(days * static_cast<double>(ticksPerDay)));
148 }
149 
150 /*!
151  * \brief Parses the given std::string as TimeSpan.
152  * \throws Throws a ConversionException if the specified \a str does not match the expected format.
153  *
154  * The expected format is "days:hours:minutes:seconds", eg. "5:31:4.521" for 5 hours, 31 minutes
155  * and 4.521 seconds. So parts at the front can be omitted and the parts can be fractions. The
156  * colon can be changed by specifying another \a separator.
157  */
fromString(const std::string & str,char separator)158 inline TimeSpan TimeSpan::fromString(const std::string &str, char separator)
159 {
160     return TimeSpan::fromString(str.data(), separator);
161 }
162 
163 /*!
164  * \brief Constructs a new instance of the TimeSpan class with the minimal number of ticks.
165  */
negativeInfinity()166 constexpr inline TimeSpan TimeSpan::negativeInfinity()
167 {
168     return TimeSpan(std::numeric_limits<decltype(m_ticks)>::min());
169 }
170 
171 /*!
172  * \brief Constructs a new instance of the TimeSpan class with the maximal number of ticks.
173  */
infinity()174 constexpr inline TimeSpan TimeSpan::infinity()
175 {
176     return TimeSpan(std::numeric_limits<decltype(m_ticks)>::max());
177 }
178 
179 /*!
180  * \brief Returns a mutable reference to the total ticks.
181  */
ticks()182 inline std::int64_t &TimeSpan::ticks()
183 {
184     return m_ticks;
185 }
186 
187 /*!
188  * \brief Returns the number of ticks that represent the value of the current TimeSpan class.
189  */
totalTicks()190 constexpr inline std::int64_t TimeSpan::totalTicks() const
191 {
192     return m_ticks;
193 }
194 
195 /*!
196  * \brief Returns the value of the current TimeSpan class expressed in whole and fractional microseconds.
197  */
totalMicroseconds()198 constexpr double TimeSpan::totalMicroseconds() const
199 {
200     return static_cast<double>(m_ticks) / static_cast<double>(ticksPerMicrosecond);
201 }
202 
203 /*!
204  * \brief Returns the value of the current TimeSpan class expressed in whole and fractional milliseconds.
205  */
totalMilliseconds()206 constexpr inline double TimeSpan::totalMilliseconds() const
207 {
208     return static_cast<double>(m_ticks) / static_cast<double>(ticksPerMillisecond);
209 }
210 
211 /*!
212  * \brief Returns the value of the current TimeSpan class expressed in whole and fractional seconds.
213  */
totalSeconds()214 constexpr inline double TimeSpan::totalSeconds() const
215 {
216     return static_cast<double>(m_ticks) / static_cast<double>(ticksPerSecond);
217 }
218 
219 /*!
220  * \brief Returns the value of the current TimeSpan class expressed in whole and fractional minutes.
221  */
totalMinutes()222 constexpr inline double TimeSpan::totalMinutes() const
223 {
224     return static_cast<double>(m_ticks) / static_cast<double>(ticksPerMinute);
225 }
226 
227 /*!
228  * \brief Returns the value of the current TimeSpan class expressed in whole and fractional hours.
229  */
totalHours()230 constexpr inline double TimeSpan::totalHours() const
231 {
232     return static_cast<double>(m_ticks) / static_cast<double>(ticksPerHour);
233 }
234 
235 /*!
236  * \brief Returns the value of the current TimeSpan class expressed in whole and fractional days.
237  */
totalDays()238 constexpr inline double TimeSpan::totalDays() const
239 {
240     return static_cast<double>(m_ticks) / static_cast<double>(ticksPerDay);
241 }
242 
243 /*!
244  * \brief Returns the nanoseconds component of the time interval represented by the current TimeSpan class.
245  * \remarks The accuracy of the TimeSpan class is 100-nanoseconds. Hence the returned value
246  *          will always have two zeros at the end (in decimal representation).
247  */
nanoseconds()248 constexpr int TimeSpan::nanoseconds() const
249 {
250     return static_cast<int>(m_ticks % 10l * TimeSpan::nanosecondsPerTick);
251 }
252 
253 /*!
254  * \brief Returns the microseconds component of the time interval represented by the current TimeSpan class.
255  */
microseconds()256 constexpr int TimeSpan::microseconds() const
257 {
258     return static_cast<int>((m_ticks / ticksPerMicrosecond) % 1000l);
259 }
260 
261 /*!
262  * \brief Returns the milliseconds component of the time interval represented by the current TimeSpan class.
263  */
milliseconds()264 constexpr inline int TimeSpan::milliseconds() const
265 {
266     return static_cast<int>((m_ticks / ticksPerMillisecond) % 1000l);
267 }
268 
269 /*!
270  * \brief Returns the seconds component of the time interval represented by the current TimeSpan class.
271  */
seconds()272 constexpr inline int TimeSpan::seconds() const
273 {
274     return static_cast<int>((m_ticks / ticksPerSecond) % 60l);
275 }
276 
277 /*!
278  * \brief Returns the minutes component of the time interval represented by the current TimeSpan class.
279  */
minutes()280 constexpr inline int TimeSpan::minutes() const
281 {
282     return static_cast<int>((m_ticks / ticksPerMinute) % 60l);
283 }
284 
285 /*!
286  * \brief Returns the hours component of the time interval represented by the current TimeSpan class.
287  */
hours()288 constexpr inline int TimeSpan::hours() const
289 {
290     return static_cast<int>((m_ticks / ticksPerHour) % 24l);
291 }
292 
293 /*!
294  * \brief Returns the days component of the time interval represented by the current TimeSpan class.
295  */
days()296 constexpr inline int TimeSpan::days() const
297 {
298     return static_cast<int>((m_ticks / ticksPerDay));
299 }
300 
301 /*!
302  * \brief Indicates whether two TimeSpan instances are equal.
303  */
304 constexpr inline bool TimeSpan::operator==(const TimeSpan &other) const
305 {
306     return m_ticks == other.m_ticks;
307 }
308 
309 /*!
310  * \brief Indicates whether two TimeSpan instances are not equal.
311  */
312 constexpr inline bool TimeSpan::operator!=(const TimeSpan &other) const
313 {
314     return m_ticks != other.m_ticks;
315 }
316 
317 /*!
318  * \brief Indicates whether a specified TimeSpan is less than another specified TimeSpan.
319  */
320 constexpr inline bool TimeSpan::operator<(const TimeSpan &other) const
321 {
322     return m_ticks < other.m_ticks;
323 }
324 
325 /*!
326  * \brief Indicates whether a specified TimeSpan is greater than another specified TimeSpan.
327  */
328 constexpr inline bool TimeSpan::operator>(const TimeSpan &other) const
329 {
330     return m_ticks > other.m_ticks;
331 }
332 
333 /*!
334  * \brief Indicates whether a specified TimeSpan is less or equal than another specified TimeSpan.
335  */
336 constexpr inline bool TimeSpan::operator<=(const TimeSpan &other) const
337 {
338     return m_ticks <= other.m_ticks;
339 }
340 
341 /*!
342  * \brief Indicates whether a specified TimeSpan is greater or equal than another specified TimeSpan.
343  */
344 constexpr inline bool TimeSpan::operator>=(const TimeSpan &other) const
345 {
346     return m_ticks >= other.m_ticks;
347 }
348 
349 /*!
350  * \brief Adds two TimeSpan instances.
351  */
352 constexpr inline TimeSpan TimeSpan::operator+(const TimeSpan &other) const
353 {
354     return TimeSpan(m_ticks + other.m_ticks);
355 }
356 
357 /*!
358  * \brief Subtracts one TimeSpan instance from another.
359  */
360 constexpr inline TimeSpan TimeSpan::operator-(const TimeSpan &other) const
361 {
362     return TimeSpan(m_ticks - other.m_ticks);
363 }
364 
365 /*!
366  * \brief Multiplies a TimeSpan by the specified \a factor.
367  */
368 constexpr inline TimeSpan TimeSpan::operator*(double factor) const
369 {
370     return TimeSpan(static_cast<std::int64_t>(static_cast<double>(m_ticks) * factor));
371 }
372 
373 /*!
374  * \brief Divides a TimeSpan by the specified \a factor.
375  */
376 constexpr inline TimeSpan TimeSpan::operator/(double factor) const
377 {
378     return TimeSpan(static_cast<std::int64_t>(static_cast<double>(m_ticks) / factor));
379 }
380 
381 /*!
382  * \brief Computes the ratio between two TimeSpan instances.
383  */
384 constexpr inline double TimeSpan::operator/(TimeSpan other) const
385 {
386     return static_cast<double>(m_ticks) / static_cast<double>(other.m_ticks);
387 }
388 
389 /*!
390  * \brief Adds another TimeSpan to the current instance.
391  */
392 inline TimeSpan &TimeSpan::operator+=(const TimeSpan &other)
393 {
394     m_ticks += other.m_ticks;
395     return *this;
396 }
397 
398 /*!
399  * \brief Subtracts another TimeSpan from the current instance.
400  */
401 inline TimeSpan &TimeSpan::operator-=(const TimeSpan &other)
402 {
403     m_ticks -= other.m_ticks;
404     return *this;
405 }
406 
407 /*!
408  * \brief Multiplies the current instance by the specified \a factor.
409  */
410 inline TimeSpan &TimeSpan::operator*=(double factor)
411 {
412     m_ticks = static_cast<std::int64_t>(static_cast<double>(m_ticks) * factor);
413     return *this;
414 }
415 
416 /*!
417  * \brief Divides the current instance by the specified \a factor.
418  */
419 inline TimeSpan &TimeSpan::operator/=(double factor)
420 {
421     m_ticks = static_cast<std::int64_t>(static_cast<double>(m_ticks) / factor);
422     return *this;
423 }
424 
425 /*!
426  * \brief Converts the value of the current TimeSpan object to its equivalent std::string representation
427  *        according the given \a format.
428  *
429  * If \a fullSeconds is true the time interval will be rounded to full seconds.
430  */
toString(TimeSpanOutputFormat format,bool fullSeconds)431 inline std::string TimeSpan::toString(TimeSpanOutputFormat format, bool fullSeconds) const
432 {
433     std::string result;
434     toString(result, format, fullSeconds);
435     return result;
436 }
437 
438 /*!
439  * \brief Returns true if the time interval represented by the current TimeSpan class is null.
440  */
isNull()441 constexpr inline bool TimeSpan::isNull() const
442 {
443     return m_ticks == 0;
444 }
445 
446 /*!
447  * \brief Returns true if the time interval represented by the current TimeSpan class is negative.
448  */
isNegative()449 constexpr inline bool TimeSpan::isNegative() const
450 {
451     return m_ticks < 0;
452 }
453 
454 /*!
455  * \brief Returns whether the time interval represented by the current instance is the smallest representable TimeSpan.
456  */
isNegativeInfinity()457 constexpr inline bool TimeSpan::isNegativeInfinity() const
458 {
459     return m_ticks == std::numeric_limits<decltype(m_ticks)>::min();
460 }
461 
462 /*!
463  * \brief Returns whether the time interval represented by the current instance is the longest representable TimeSpan.
464  */
isInfinity()465 constexpr inline bool TimeSpan::isInfinity() const
466 {
467     return m_ticks == std::numeric_limits<decltype(m_ticks)>::max();
468 }
469 } // namespace CppUtilities
470 
471 namespace std {
472 /// \brief Computes the hash for the CppUtilities::TimeSpan instance.
473 template <> struct hash<CppUtilities::TimeSpan> {
474     inline size_t operator()(const CppUtilities::TimeSpan &timeSpan) const
475     {
476         return hash<decltype(timeSpan.totalTicks())>()(timeSpan.totalTicks());
477     }
478 };
479 } // namespace std
480 
481 #endif // CHRONO_UTILITIES_TIMESPAN_H
482