API
 
Loading...
Searching...
No Matches
timespecX.hpp
Go to the documentation of this file.
1/** \file timespecX.hpp
2 * \brief A fixed-width timespec structure and utilities.
3 * \author Jared R. Males (jaredmales@gmail.com)
4 *
5 * \ingroup flatlogs_files
6 *
7 * History:
8 * - 2017-06-27 created by JRM
9 * - 2018-08-17 moved to flatlogs
10 */
11
12#ifndef flatlogs_timespecX_hpp
13#define flatlogs_timespecX_hpp
14
15#include <cstdint>
16#include <iostream>
17#include <cmath>
18#include <ctime>
19
20#include "logDefs.hpp"
21
22namespace flatlogs
23{
24
25///A fixed-width timespec structure.
26/** To ensure that binary encoding of time is stable regardless of environment, we use a custom timespec
27 * composed of fixed-width types.
28 *
29 * \note This is NOT binary compatible with plain timespec. Use the provided conversions.
30 *
31 * \ingroup flatlogs_time
32 *
33 */
34struct timespecX
35{
36 secT time_s {0}; ///< Time since the Unix epoch
37 nanosecT time_ns {0}; ///< Nanoseconds.
38
39 ///Default c'tor
41 {
42 }
43
44 ///Construct with time values
45 timespecX( secT s, nanosecT ns ) : time_s {s}, time_ns {ns}
46 {
47 }
48
49 ///Construct from timespec
50 timespecX( const timespec & ts)
51 {
52 operator=(ts);
53 }
54
55 ///Convert a native timespec to a timespecX.
56 /**
57 * \returns this reference, if values are 0 and 0 then the input was too big or negative.
58 */
59 timespecX & operator=( const timespec & ts /**< [in] the native timespec from which to get values */)
60 {
61 if(ts.tv_sec < 0 || ts.tv_sec > 4294967295) ///\todo make this use minval and maxval
62 {
63 time_s = 0;
64 time_ns = 0;
65 }
66 else
67 {
68 time_s = ts.tv_sec;
69 time_ns = ts.tv_nsec;
70 }
71
72 return *this;
73 }
74
75 ///Get a native timespec from this custom one.
76 timespec getTimespec()
77 {
78 struct timespec ts;
79
80 ts.tv_sec = time_s;
81 ts.tv_nsec = time_ns;
82
83 return ts;
84 }
85
86 ///Fill the the timespecX with the current time.
87 /** This is based on the usual clock_gettime. clockid_t is a template parameter
88 * since we probaby always want CLOCK_REALTIME, but if we don't for some reason
89 * it will be passed in the same order as in clock_gettime.
90 *
91 * \tparam clk_id specifies the type.
92 */
93 template<clockid_t clk_id=CLOCK_REALTIME>
94 void gettime()
95 {
96 struct timespec ts;
97 clock_gettime(clk_id, &ts);
98 (*this) = ts; //see operator=
99 }
100
101 ///Get the filename timestamp for this timespecX.
102 /** Fills in a string with the timestamp encoded as
103 * \verbatim
104 YYYYMMDDHHMMSSNNNNNNNNN
105 \endverbatim
106 *
107 */
108 int timeStamp(std::string & tstamp /**< [out] the string to hold the formatted time */)
109 {
110 tm uttime;//The broken down time.
111
112 time_t t0 = time_s;
113
114 if(gmtime_r(&t0, &uttime) == 0)
115 {
116 std::cerr << "Error getting UT time (gmtime_r returned 0). At: " << __FILE__ << " " << __LINE__ << "\n";
117 return -1;
118 }
119
120 char buffer[48];
121
122 snprintf(buffer, sizeof(buffer), "%04i%02i%02i%02i%02i%02i%09i", uttime.tm_year+1900, uttime.tm_mon+1, uttime.tm_mday, uttime.tm_hour, uttime.tm_min, uttime.tm_sec, static_cast<int>(time_ns)); //casting in case we switch type of time_ns.
123
124 tstamp = buffer;
125
126 return 0;
127 }
128
129 ///Get the filname timestamp for this timespecX.
130 /** Returns a string with the timestamp encoded as
131 * \verbatim
132 YYYYMMDDHHMMSSNNNNNNNNN
133 \endverbatim
134 *
135 */
136 std::string timeStamp()
137 {
138 std::string tstamp;
139 timeStamp(tstamp);
140 return tstamp;
141 }
142
143 /// Get a date-time string in ISO 8601 format for timespecX
144 /** Returns a string in the ISO 8601 format:
145 * \verbatim
146 YYYY-MM-DDTHH:MM:SS.SSSSSSSSS
147 \endverbatim
148 *
149 *
150 * \retval std::string containing the formated date/time
151 *
152 */
154 {
155 tm bdt; //broken down time
156 time_t tt = time_s;
157 gmtime_r( &tt, &bdt);
158
159 char tstr1[25];
160
161 strftime(tstr1, 25, "%FT%H:%M:%S", &bdt);
162
163 char tstr2[11];
164
165 snprintf(tstr2, 11, ".%09i", static_cast<int>(time_ns)); //casting in case we switch to int64_t
166
167 return std::string(tstr1) + std::string(tstr2);
168 }
169
171 {
172 tm bdt; //broken down time
173 time_t tt = time_s;
174 gmtime_r( &tt, &bdt);
175
176 char tstr1[25];
177
178 strftime(tstr1, 25, "%FT%H:%M", &bdt);
179
180 return std::string(tstr1);
181 }
182
183 /// Get a date-time string with just the second for timespecX
184 /** Returns a string in the format:
185 * \verbatim
186 SS.SSS
187 \endverbatim
188 * which is useful for real-time streams of log entries.
189 *
190 * \retval std::string containing the formated date/time
191 *
192 */
193 std::string secondStrX()
194 {
195 tm bdt; //broken down time
196 time_t tt = time_s;
197 gmtime_r( &tt, &bdt);
198
199 char tstr1[5];
200
201 strftime(tstr1, sizeof(tstr1), "%S", &bdt);
202
203 char tstr2[5];
204
205 snprintf(tstr2, sizeof(tstr2), ".%02i", static_cast<int>(time_ns)); //casting in case we switch to int64_t
206
207 return std::string(tstr1) + std::string(tstr2);
208 }
209
210 /// Get the minute from a timespecX
211 /**
212 *
213 * \returns the minute part.
214 *
215 */
216 int minute()
217 {
218 tm bdt; //broken down time
219 time_t tt = time_s;
220 gmtime_r( &tt, &bdt);
221
222 return bdt.tm_min;
223 }
224
225 /// Get the time as a double from a timespecX
226 /**
227 *
228 * \returns the time as a double.
229 *
230 */
231 double asDouble()
232 {
233 return ((double) time_s) + ((double) time_ns)/1e9;
234 }
235
236} __attribute__((packed));
237
238
239
240/// TimespecX comparison operator < (see caveats)
241/** Caveats:
242 * - If the inputs are in UTC (or similar scale) this does not account for leap seconds
243 * - Assumes that the `time_ns` field does not exceed 999999999 nanoseconds
244 *
245 * \returns true if tsL is earlier than tsR
246 * \returns false otherwise
247 *
248 * \ingroup timeutils_tscomp
249 */
250inline
251bool operator<( timespecX const& tsL, ///< [in] the left hand side of the comparison
252 timespecX const& tsR ///< [in] the right hand side of the comparison
253 )
254{
255 return ( ((tsL.time_s == tsR.time_s) && (tsL.time_ns < tsR.time_ns)) || (tsL.time_s < tsR.time_s));
256}
257
258/// TimespecX comparison operator > (see caveats)
259/** Caveats:
260 * - If the inputs are in UTC (or similar scale) this does not account for leap seconds
261 * - Assumes that the `time_ns` field does not exceed 999999999 nanoseconds
262 *
263 * \returns true if tsL is later than tsR
264 * \returns false otherwise
265 *
266 * \ingroup timeutils_tscomp
267 */
268inline
269bool operator>( timespecX const& tsL, ///< [in] the left hand side of the comparison
270 timespecX const& tsR ///< [in] the right hand side of the comparison
271 )
272{
273 return ( ((tsL.time_s == tsR.time_s) && (tsL.time_ns > tsR.time_ns)) || (tsL.time_s > tsR.time_s));
274}
275
276/// TimespecX comparison operator == (see caveats)
277/** Caveats:
278 * - If the inputs are in UTC (or similar scale) this does not account for leap seconds
279 * - Assumes that the `time_ns` field does not exceed 999999999 nanoseconds
280 *
281 * \returns true if tsL is exactly the same as tsR
282 * \returns false otherwise
283 *
284 * \ingroup timeutils_tscomp
285 */
286inline
287bool operator==( timespecX const& tsL, ///< [in] the left hand side of the comparison
288 timespecX const& tsR ///< [in] the right hand side of the comparison
289 )
290{
291 return ( (tsL.time_s == tsR.time_s) && (tsL.time_ns == tsR.time_ns) );
292}
293
294/// TimespecX comparison operator <= (see caveats)
295/** Caveats:
296 * - If the inputs are in UTC (or similar scale) this does not account for leap seconds
297 * - Assumes that the `time_ns` field does not exceed 999999999 nanoseconds.
298 *
299 * \returns true if tsL is earlier than or exactly equal to tsR
300 * \returns false otherwise
301 *
302 * \ingroup timeutils_tscomp
303 */
304inline
305bool operator<=( timespecX const& tsL, ///< [in] the left hand side of the comparison
306 timespecX const& tsR ///< [in] the right hand side of the comparison
307 )
308{
309 return ( tsL < tsR || tsL == tsR );
310}
311
312/// TimespecX comparison operator >= (see caveats)
313/** Caveats:
314 * - If the inputs are in UTC (or similar scale) this does not account for leap seconds
315 * - Assumes that the `time_ns` field does not exceed 999999999 nanoseconds
316 *
317 * \returns true if tsL is exactly equal to or is later than tsR
318 * \returns false otherwise
319 *
320 * \ingroup timeutils_tscomp
321 */
322inline
323bool operator>=( timespecX const& tsL, ///< [in] the left hand side of the comparison
324 timespecX const& tsR ///< [in] the right hand side of the comparison
325 )
326{
327 return ( tsL > tsR || tsL == tsR );
328}
329
330inline
332{
333 double means = ((double)(ts1.time_s + ts2.time_s))/2.0;
334 double meanns = ((double)(ts1.time_ns + ts2.time_ns))/2.0;
335
336 ts1.time_s = std::floor(means);
337 ts1.time_ns = std::round(meanns);
338
339 if( means != floor(means) )
340 {
341 ts1.time_ns += 5e8;
342
343 if(ts1.time_ns >= 1e9)
344 {
345 ts1.time_s += 1;
346 ts1.time_ns -= 1e9;
347 }
348 }
349
350 return ts1;
351}
352
353///Convert a timespecX to a native timespec
354/**
355 * \ingroup flatlogs_time
356 */
357inline
358void timespecFromX ( timespec & ts, ///< [out] the native timespec to set
359 const timespecX & tsX ///< [in] the fixed-width timespec from which to get values
360 )
361{
362 ts.tv_sec = tsX.time_s;
363 ts.tv_nsec = tsX.time_ns;
364
365}
366
367///Fill in a timespecX with the current time.
368/** This is based on the usual clock_gettime. clockid_t is a template parameter
369 * since we probaby always want CLOCK_REALTIME, but if we don't for some reason
370 * it will be passed in the same order as in clock_gettime.
371 *
372 * \tparam clk_id specifies the type.
373 *
374 * \ingroup flatlogs_time
375 *
376 */
377template<clockid_t clk_id=CLOCK_REALTIME>
378void clock_gettimeX( timespecX & tsX /**< [out] the fixed-width timespec to populate */)
379{
380 tsX.gettime<clk_id>();
381}
382
383}//namespace flatlogs
384
385
386#endif //flatlogs_timespecX_hpp
387
void clock_gettimeX(timespecX &tsX)
Fill in a timespecX with the current time.
void timespecFromX(timespec &ts, const timespecX &tsX)
Convert a timespecX to a native timespec.
uint32_t secT
The type used for seconds.
Definition logDefs.hpp:29
Type definitions for the flatlogs format.
bool operator<=(timespecX const &tsL, timespecX const &tsR)
TimespecX comparison operator <= (see caveats)
timespecX meanTimespecX(timespecX ts1, timespecX ts2)
bool operator>=(timespecX const &tsL, timespecX const &tsR)
TimespecX comparison operator >= (see caveats)
bool operator==(timespecX const &tsL, timespecX const &tsR)
TimespecX comparison operator == (see caveats)
bool operator>(timespecX const &tsL, timespecX const &tsR)
TimespecX comparison operator > (see caveats)
uint32_t nanosecT
The type used for nanoseconds.
Definition logDefs.hpp:34
bool operator<(timespecX const &tsL, timespecX const &tsR)
TimespecX comparison operator < (see caveats)
A fixed-width timespec structure.
Definition timespecX.hpp:35
std::string ISO8601DateTimeStr2MinX()
std::string timeStamp()
Get the filname timestamp for this timespecX.
timespecX()
Default c'tor.
Definition timespecX.hpp:40
int timeStamp(std::string &tstamp)
Get the filename timestamp for this timespecX.
nanosecT time_ns
Nanoseconds.
Definition timespecX.hpp:37
secT time_s
Time since the Unix epoch.
Definition timespecX.hpp:36
int minute()
Get the minute from a timespecX.
timespecX & operator=(const timespec &ts)
Convert a native timespec to a timespecX.
Definition timespecX.hpp:59
std::string secondStrX()
Get a date-time string with just the second for timespecX.
timespecX(secT s, nanosecT ns)
Construct with time values.
Definition timespecX.hpp:45
std::string ISO8601DateTimeStrX()
Get a date-time string in ISO 8601 format for timespecX.
timespecX(const timespec &ts)
Construct from timespec.
Definition timespecX.hpp:50
void gettime()
Fill the the timespecX with the current time.
Definition timespecX.hpp:94
timespec getTimespec()
Get a native timespec from this custom one.
Definition timespecX.hpp:76
double asDouble()
Get the time as a double from a timespecX.