C++ Utilities: chrono/timespan.cpp Source File

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