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