C++ Utilities 5.26.1
Useful C++ classes and routines such as argument parser, IO and conversion utilities
Loading...
Searching...
No Matches
timespan.cpp
Go to the documentation of this file.
1#define CHRONO_UTILITIES_TIMESPAN_INTEGER_SCALE_OVERLOADS
2
3#include "./timespan.h"
4
7
8#include <array>
9#include <charconv>
10#include <cmath>
11#include <cstdlib>
12#include <iomanip>
13#include <sstream>
14
15using namespace std;
16
17namespace CppUtilities {
18
20
21#if defined(__GLIBCXX__) && _GLIBCXX_RELEASE < 10
22enum class chars_format { scientific = 1, fixed = 2, hex = 4, general = fixed | scientific };
23#else
24using char_format = std::chars_format;
25#endif
26
27inline std::from_chars_result from_chars(const char *first, const char *last, double &value, chars_format fmt = chars_format::general) noexcept
28{
29#if defined(_LIBCPP_VERSION) || (defined(__GLIBCXX__) && _GLIBCXX_RELEASE < 11)
30 // workaround std::from_chars() not being implemented for floating point numbers in libc++ and older libstdc++ versions
32 auto r = std::from_chars_result{ nullptr, std::errc() };
33 auto s = std::string(first, last);
34 auto l = s.data() + s.size();
35 auto d = std::strtod(s.data(), &l);
36 if (errno == ERANGE) {
37 r.ec = std::errc::result_out_of_range;
38 } else if (s.data() == l) {
39 r.ec = std::errc::invalid_argument;
40 } else {
41 value = d;
42 r.ptr = first + (l - s.data());
43 }
44 return r;
45#else
46 return std::from_chars(first, last, value, fmt);
47#endif
48}
50
74TimeSpan TimeSpan::fromString(const char *str, char separator)
75{
76 if (!*str) {
77 return TimeSpan();
78 }
79
80 auto parts = std::array<double, 4>();
81 auto partsPresent = std::size_t();
82 auto specificationsWithUnits = TimeSpan();
83
84 for (const char *i = str;; ++i) {
85 // skip over white-spaces
86 if (*i == ' ' && i == str) {
87 str = i + 1;
88 continue;
89 }
90
91 // consider non-separator and non-terminator characters as part to be interpreted as number
92 if (*i != separator && *i != '\0') {
93 continue;
94 }
95
96 // allow only up to 4 parts (days, hours, minutes and seconds)
97 if (partsPresent == 4) {
98 throw ConversionException("too many separators/parts");
99 }
100
101 // parse value of the part
102 auto valuePart = 0.0;
103 auto valueWithUnit = TimeSpan();
104 if (str != i) {
105 // parse value of the part as double
106 const auto res = from_chars(str, i, valuePart);
107 if (res.ec != std::errc()) {
108 const auto part = std::string_view(str, static_cast<std::string_view::size_type>(i - str));
109 if (res.ec == std::errc::result_out_of_range) {
110 throw ConversionException(argsToString("part \"", part, "\" is too large"));
111 } else {
112 throw ConversionException(argsToString("part \"", part, "\" cannot be interpreted as floating point number"));
113 }
114 }
115 // handle remaining characters; detect a possibly present unit suffix
116 for (const char *suffix = res.ptr; suffix != i; ++suffix) {
117 if (*suffix == ' ') {
118 continue;
119 }
120 if (valueWithUnit.isNull()) {
121 switch (*suffix) {
122 case 'w':
123 valueWithUnit = TimeSpan::fromDays(7.0 * valuePart);
124 continue;
125 case 'd':
126 valueWithUnit = TimeSpan::fromDays(valuePart);
127 continue;
128 case 'h':
129 valueWithUnit = TimeSpan::fromHours(valuePart);
130 continue;
131 case 'm':
132 valueWithUnit = TimeSpan::fromMinutes(valuePart);
133 continue;
134 case 's':
135 valueWithUnit = TimeSpan::fromSeconds(valuePart);
136 continue;
137 default:;
138 }
139 }
140 if (*suffix >= '0' && *suffix <= '9') {
141 str = i = suffix;
142 break;
143 }
144 throw ConversionException(argsToString("unexpected character \"", *suffix, '\"'));
145 }
146 }
147
148 // set part value; add value with unit
149 if (valueWithUnit.isNull()) {
150 parts[partsPresent++] = valuePart;
151 } else {
152 specificationsWithUnits += valueWithUnit;
153 }
154
155 // expect next part starting after the separator or stop if terminator reached
156 if (*i == separator) {
157 str = i + 1;
158 } else if (*i == '\0') {
159 break;
160 }
161 }
162
163 // compute and return total value from specifications with units and parts
164 switch (partsPresent) {
165 case 1:
166 return specificationsWithUnits + TimeSpan::fromSeconds(parts.front());
167 case 2:
168 return specificationsWithUnits + TimeSpan::fromMinutes(parts.front()) + TimeSpan::fromSeconds(parts[1]);
169 case 3:
170 return specificationsWithUnits + TimeSpan::fromHours(parts.front()) + TimeSpan::fromMinutes(parts[1]) + TimeSpan::fromSeconds(parts[2]);
171 default:
172 return specificationsWithUnits + TimeSpan::fromDays(parts.front()) + TimeSpan::fromHours(parts[1]) + TimeSpan::fromMinutes(parts[2])
173 + TimeSpan::fromSeconds(parts[3]);
174 }
175}
176
185void TimeSpan::toString(string &result, TimeSpanOutputFormat format, bool fullSeconds) const
186{
187 stringstream s(stringstream::in | stringstream::out);
188 TimeSpan positive(m_ticks);
189 if (positive.isNegative()) {
190 s << '-';
191 positive.m_ticks = -positive.m_ticks;
192 }
193 switch (format) {
195 s << setfill('0') << setw(2) << floor(positive.totalHours()) << ":" << setw(2) << positive.minutes() << ":" << setw(2) << positive.seconds();
196 if (!fullSeconds) {
197 const int milli(positive.milliseconds());
198 const int micro(positive.microseconds());
199 const int nano(positive.nanoseconds());
200 if (milli || micro || nano) {
201 s << '.' << setw(3) << milli;
202 if (micro || nano) {
203 s << setw(3) << micro;
204 if (nano) {
206 }
207 }
208 }
209 }
210 break;
212 if (isNull()) {
213 result = "0 s";
214 return;
215 } else {
216 if (!fullSeconds && positive.totalMilliseconds() < 1.0) {
217 s << setprecision(2) << positive.totalMicroseconds() << " µs";
218 } else {
219 bool needWhitespace = false;
220 if (const int days = positive.days()) {
221 needWhitespace = true;
222 s << days << " d";
223 }
224 if (const int hours = positive.hours()) {
225 if (needWhitespace)
226 s << ' ';
227 needWhitespace = true;
228 s << hours << " h";
229 }
230 if (const int minutes = positive.minutes()) {
231 if (needWhitespace)
232 s << ' ';
233 needWhitespace = true;
234 s << minutes << " min";
235 }
236 if (const int seconds = positive.seconds()) {
237 if (needWhitespace)
238 s << ' ';
239 needWhitespace = true;
240 s << seconds << " s";
241 }
242 if (!fullSeconds) {
243 if (const int milliseconds = positive.milliseconds()) {
244 if (needWhitespace)
245 s << ' ';
246 needWhitespace = true;
247 s << milliseconds << " ms";
248 }
249 if (const int microseconds = positive.microseconds()) {
250 if (needWhitespace)
251 s << ' ';
252 needWhitespace = true;
253 s << microseconds << " µs";
254 }
255 if (const int nanoseconds = positive.nanoseconds()) {
256 if (needWhitespace)
257 s << ' ';
258 s << nanoseconds << " ns";
259 }
260 }
261 }
262 }
263 break;
265 if (fullSeconds) {
266 s << setprecision(0);
267 } else {
268 s << setprecision(10);
269 }
270 s << positive.totalSeconds();
271 break;
272 }
273 result = s.str();
274}
275
276} // namespace CppUtilities
#define CPP_UTILITIES_UNUSED(x)
Prevents warnings about unused variables.
Definition global.h:92
The ConversionException class is thrown by the various conversion functions of this library when a co...
Represents a time interval.
Definition timespan.h:25
constexpr double totalHours() const
Returns the value of the current TimeSpan class expressed in whole and fractional hours.
Definition timespan.h:289
constexpr double totalSeconds() const
Returns the value of the current TimeSpan class expressed in whole and fractional seconds.
Definition timespan.h:273
constexpr bool isNull() const
Returns true if the time interval represented by the current TimeSpan class is null.
Definition timespan.h:538
static constexpr TickType nanosecondsPerTick
Definition timespan.h:99
constexpr int seconds() const
Returns the seconds component of the time interval represented by the current TimeSpan class.
Definition timespan.h:331
constexpr int minutes() const
Returns the minutes component of the time interval represented by the current TimeSpan class.
Definition timespan.h:339
constexpr double totalMicroseconds() const
Returns the value of the current TimeSpan class expressed in whole and fractional microseconds.
Definition timespan.h:257
constexpr TimeSpan()
Constructs a new instance of the TimeSpan class with zero ticks.
Definition timespan.h:114
constexpr int days() const
Returns the days component of the time interval represented by the current TimeSpan class.
Definition timespan.h:355
constexpr int milliseconds() const
Returns the milliseconds component of the time interval represented by the current TimeSpan class.
Definition timespan.h:323
static constexpr TimeSpan fromDays(double days)
Constructs a new instance of the TimeSpan class with the specified number of days.
Definition timespan.h:162
static constexpr TimeSpan fromHours(double hours)
Constructs a new instance of the TimeSpan class with the specified number of hours.
Definition timespan.h:154
static constexpr TimeSpan fromMinutes(double minutes)
Constructs a new instance of the TimeSpan class with the specified number of minutes.
Definition timespan.h:146
static constexpr TimeSpan fromSeconds(double seconds)
Constructs a new instance of the TimeSpan class with the specified number of seconds.
Definition timespan.h:138
constexpr int microseconds() const
Returns the microseconds component of the time interval represented by the current TimeSpan class.
Definition timespan.h:315
std::string toString(TimeSpanOutputFormat format=TimeSpanOutputFormat::Normal, bool fullSeconds=false) const
Converts the value of the current TimeSpan object to its equivalent std::string representation accord...
Definition timespan.h:528
static TimeSpan fromString(const std::string &str, char separator=':')
Parses the given std::string as TimeSpan.
Definition timespan.h:217
constexpr double totalMilliseconds() const
Returns the value of the current TimeSpan class expressed in whole and fractional milliseconds.
Definition timespan.h:265
constexpr bool isNegative() const
Returns true if the time interval represented by the current TimeSpan class is negative.
Definition timespan.h:546
constexpr int hours() const
Returns the hours component of the time interval represented by the current TimeSpan class.
Definition timespan.h:347
constexpr int nanoseconds() const
Returns the nanoseconds component of the time interval represented by the current TimeSpan class.
Definition timespan.h:307
Contains all utilities provides by the c++utilities library.
TimeSpanOutputFormat
Specifies the output format.
Definition timespan.h:19
StringType argsToString(Args &&...args)
STL namespace.
constexpr int i