API
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 
22 namespace 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  */
34 struct 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  */
153  std::string ISO8601DateTimeStrX()
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  */
250 inline
251 bool 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  */
268 inline
269 bool 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  */
286 inline
287 bool 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  */
304 inline
305 bool 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  */
322 inline
323 bool 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 
330 inline
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  */
357 inline
358 void 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  */
377 template<clockid_t clk_id=CLOCK_REALTIME>
378 void 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.
Definition: timespecX.hpp:378
void timespecFromX(timespec &ts, const timespecX &tsX)
Convert a timespecX to a native timespec.
Definition: timespecX.hpp:358
uint32_t secT
The type used for seconds.
Definition: logDefs.hpp:29
Type definitions for the flatlogs format.
std::ostream & cerr()
bool operator<=(timespecX const &tsL, timespecX const &tsR)
TimespecX comparison operator <= (see caveats)
Definition: timespecX.hpp:305
timespecX meanTimespecX(timespecX ts1, timespecX ts2)
Definition: timespecX.hpp:331
bool operator>=(timespecX const &tsL, timespecX const &tsR)
TimespecX comparison operator >= (see caveats)
Definition: timespecX.hpp:323
bool operator==(timespecX const &tsL, timespecX const &tsR)
TimespecX comparison operator == (see caveats)
Definition: timespecX.hpp:287
bool operator>(timespecX const &tsL, timespecX const &tsR)
TimespecX comparison operator > (see caveats)
Definition: timespecX.hpp:269
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)
Definition: timespecX.hpp:251
A fixed-width timespec structure.
Definition: timespecX.hpp:35
std::string ISO8601DateTimeStr2MinX()
Definition: timespecX.hpp:170
std::string timeStamp()
Get the filname timestamp for this timespecX.
Definition: timespecX.hpp:136
timespecX()
Default c'tor.
Definition: timespecX.hpp:40
int timeStamp(std::string &tstamp)
Get the filename timestamp for this timespecX.
Definition: timespecX.hpp:108
nanosecT time_ns
Nanoseconds.
Definition: timespecX.hpp:37
timespecX & operator=(const timespec &ts)
Convert a native timespec to a timespecX.
Definition: timespecX.hpp:59
secT time_s
Time since the Unix epoch.
Definition: timespecX.hpp:36
int minute()
Get the minute from a timespecX.
Definition: timespecX.hpp:216
std::string secondStrX()
Get a date-time string with just the second for timespecX.
Definition: timespecX.hpp:193
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.
Definition: timespecX.hpp:153
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.
Definition: timespecX.hpp:231