C++ Utilities 5.24.3
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
5#include "../conversion/stringbuilder.h"
6#include "../conversion/stringconversion.h"
7
8#include <charconv>
9#include <cmath>
10#include <cstdlib>
11#include <iomanip>
12#include <sstream>
13#include <vector>
14
15using namespace std;
16
17namespace CppUtilities {
18
20inline std::from_chars_result from_chars(
21 const char *first, const char *last, double &value, std::chars_format fmt = std::chars_format::general) noexcept
22{
23#if _LIBCPP_VERSION
24 // workaround std::from_chars() not being implemented for floating point numbers in libc++
26 auto r = std::from_chars_result{ nullptr, std::errc() };
27 auto s = std::string(first, last);
28 auto l = s.data() + s.size();
29 auto d = std::strtod(s.data(), &l);
30 if (errno == ERANGE) {
31 r.ec = std::errc::result_out_of_range;
32 } else if (s.data() == l) {
33 r.ec = std::errc::invalid_argument;
34 } else {
35 value = d;
36 r.ptr = first + (l - s.data());
37 }
38 return r;
39#else
40 return std::from_chars(first, last, value, fmt);
41#endif
42}
44
68TimeSpan TimeSpan::fromString(const char *str, char separator)
69{
70 if (!*str) {
71 return TimeSpan();
72 }
73
74 auto parts = std::array<double, 4>();
75 auto partsPresent = std::size_t();
76 auto specificationsWithUnits = TimeSpan();
77
78 for (const char *i = str;; ++i) {
79 // skip over white-spaces
80 if (*i == ' ' && i == str) {
81 str = i + 1;
82 continue;
83 }
84
85 // consider non-separator and non-terminator characters as part to be interpreted as number
86 if (*i != separator && *i != '\0') {
87 continue;
88 }
89
90 // allow only up to 4 parts (days, hours, minutes and seconds)
91 if (partsPresent == 4) {
92 throw ConversionException("too many separators/parts");
93 }
94
95 // parse value of the part
96 auto valuePart = 0.0;
97 auto valueWithUnit = TimeSpan();
98 if (str != i) {
99 // parse value of the part as double
100 const auto res = from_chars(str, i, valuePart);
101 if (res.ec != std::errc()) {
102 const auto part = std::string_view(str, static_cast<std::string_view::size_type>(i - str));
103 if (res.ec == std::errc::result_out_of_range) {
104 throw ConversionException(argsToString("part \"", part, "\" is too large"));
105 } else {
106 throw ConversionException(argsToString("part \"", part, "\" cannot be interpreted as floating point number"));
107 }
108 }
109 // handle remaining characters; detect a possibly present unit suffix
110 for (const char *suffix = res.ptr; suffix != i; ++suffix) {
111 if (*suffix == ' ') {
112 continue;
113 }
114 if (valueWithUnit.isNull()) {
115 switch (*suffix) {
116 case 'w':
117 valueWithUnit = TimeSpan::fromDays(7.0 * valuePart);
118 continue;
119 case 'd':
120 valueWithUnit = TimeSpan::fromDays(valuePart);
121 continue;
122 case 'h':
123 valueWithUnit = TimeSpan::fromHours(valuePart);
124 continue;
125 case 'm':
126 valueWithUnit = TimeSpan::fromMinutes(valuePart);
127 continue;
128 case 's':
129 valueWithUnit = TimeSpan::fromSeconds(valuePart);
130 continue;
131 default:;
132 }
133 }
134 if (*suffix >= '0' && *suffix <= '9') {
135 str = i = suffix;
136 break;
137 }
138 throw ConversionException(argsToString("unexpected character \"", *suffix, '\"'));
139 }
140 }
141
142 // set part value; add value with unit
143 if (valueWithUnit.isNull()) {
144 parts[partsPresent++] = valuePart;
145 } else {
146 specificationsWithUnits += valueWithUnit;
147 }
148
149 // expect next part starting after the separator or stop if terminator reached
150 if (*i == separator) {
151 str = i + 1;
152 } else if (*i == '\0') {
153 break;
154 }
155 }
156
157 // compute and return total value from specifications with units and parts
158 switch (partsPresent) {
159 case 1:
160 return specificationsWithUnits + TimeSpan::fromSeconds(parts.front());
161 case 2:
162 return specificationsWithUnits + TimeSpan::fromMinutes(parts.front()) + TimeSpan::fromSeconds(parts[1]);
163 case 3:
164 return specificationsWithUnits + TimeSpan::fromHours(parts.front()) + TimeSpan::fromMinutes(parts[1]) + TimeSpan::fromSeconds(parts[2]);
165 default:
166 return specificationsWithUnits + TimeSpan::fromDays(parts.front()) + TimeSpan::fromHours(parts[1]) + TimeSpan::fromMinutes(parts[2])
167 + TimeSpan::fromSeconds(parts[3]);
168 }
169}
170
179void TimeSpan::toString(string &result, TimeSpanOutputFormat format, bool fullSeconds) const
180{
181 stringstream s(stringstream::in | stringstream::out);
182 TimeSpan positive(m_ticks);
183 if (positive.isNegative()) {
184 s << '-';
185 positive.m_ticks = -positive.m_ticks;
186 }
187 switch (format) {
189 s << setfill('0') << setw(2) << floor(positive.totalHours()) << ":" << setw(2) << positive.minutes() << ":" << setw(2) << positive.seconds();
190 if (!fullSeconds) {
191 const int milli(positive.milliseconds());
192 const int micro(positive.microseconds());
193 const int nano(positive.nanoseconds());
194 if (milli || micro || nano) {
195 s << '.' << setw(3) << milli;
196 if (micro || nano) {
197 s << setw(3) << micro;
198 if (nano) {
200 }
201 }
202 }
203 }
204 break;
206 if (isNull()) {
207 result = "0 s";
208 return;
209 } else {
210 if (!fullSeconds && positive.totalMilliseconds() < 1.0) {
211 s << setprecision(2) << positive.totalMicroseconds() << " µs";
212 } else {
213 bool needWhitespace = false;
214 if (const int days = positive.days()) {
215 needWhitespace = true;
216 s << days << " d";
217 }
218 if (const int hours = positive.hours()) {
219 if (needWhitespace)
220 s << ' ';
221 needWhitespace = true;
222 s << hours << " h";
223 }
224 if (const int minutes = positive.minutes()) {
225 if (needWhitespace)
226 s << ' ';
227 needWhitespace = true;
228 s << minutes << " min";
229 }
230 if (const int seconds = positive.seconds()) {
231 if (needWhitespace)
232 s << ' ';
233 needWhitespace = true;
234 s << seconds << " s";
235 }
236 if (!fullSeconds) {
237 if (const int milliseconds = positive.milliseconds()) {
238 if (needWhitespace)
239 s << ' ';
240 needWhitespace = true;
241 s << milliseconds << " ms";
242 }
243 if (const int microseconds = positive.microseconds()) {
244 if (needWhitespace)
245 s << ' ';
246 needWhitespace = true;
247 s << microseconds << " µs";
248 }
249 if (const int nanoseconds = positive.nanoseconds()) {
250 if (needWhitespace)
251 s << ' ';
252 s << nanoseconds << " ns";
253 }
254 }
255 }
256 }
257 break;
259 if (fullSeconds) {
260 s << setprecision(0);
261 } else {
262 s << setprecision(10);
263 }
264 s << positive.totalSeconds();
265 break;
266 }
267 result = s.str();
268}
269
270} // 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