Streaming C++ API  11.0.0.2
Timestamp.hpp
1 //
2 // Copyright (c) 2004-2022 TIBCO Software Inc. All rights reserved.
3 //
4 
5 #ifndef STREAMBASE_TIMESTAMP_H
6 #define STREAMBASE_TIMESTAMP_H
7 
8 #include "StreamBase.hpp"
9 
10 #include <time.h>
11 #include "Exceptions.hpp"
12 #include <NMSTL/ntime.hpp>
13 #include <NMSTL/platform.hpp>
14 
15 SB_NAMESPACE_BEGIN;
16 class Timestamp;
17 SB_NAMESPACE_END;
18 
19 SB_INTERNAL_FWD(TimestampTest);
20 SB_INTERNAL_FWD(TimestampUtil);
21 SB_INTERNAL_FWD(Errors);
22 
23 
24 #ifndef DOXYGEN_SKIP
25 NMSTL_NAMESPACE_BEGIN;
26 inline sb::Timestamp getUnaligned(const sb::Timestamp *p);
27 inline void setUnaligned(sb::Timestamp *p, sb::Timestamp value);
28 NMSTL_NAMESPACE_END;
29 #endif //DOXYGEN_SKIP
30 
31 
32 SB_NAMESPACE_BEGIN;
33 
34 /// Attempted to parse an invalid Timestamp string.
35 STREAMBASE_EXCEPTION_TYPE(TimestampException, sb_internal::Errors::NON_FATAL_ERROR);
36 /// Class for representing moments in time and intervals at
37 /// millisecond granularity.
38 class Timestamp
39 {
40  private:
41  enum TIMESTAMPTYPE { TIMESTAMP = 0, INTERVAL = 1 };
42  enum TIMESTAMP_FIELD {YEAR, MONTH, DAY, HOUR, MINUTE, SECOND};
43  // Field. Measures milliseconds since the start of the Unix epoch.
44  struct MS {
45 #ifdef sparc
46  // swap order for sparc
47  long long int value : 63;
48  long long int type : 1;
49 #else
50  long long int type : 1;
51  long long int value : 63;
52 #endif
53  };
54 
55  public:
56  static const int MIN_YEAR = 1400;
57  static const int MAX_YEAR = 9999;
58  static const int MIN_MONTH = 1;
59  static const int MAX_MONTH = 12;
60  static const int MIN_DAY = 1;
61  static const int MAX_DAY = 31;
62  static const int MIN_HOUR = 0;
63  static const int MAX_HOUR = 23;
64  static const int MIN_MINUTE = 0;
65  static const int MAX_MINUTE = 59;
66  static const int MIN_SECOND = 0;
67  static const int MAX_SECOND = 59;
68 
69  /// Create a default Timestamp.
70  /// Will initialized to 00:00:00 1 Jan 1970.
72  {
73  _ms.type = TIMESTAMP;
74  _ms.value = 0;
75  }
76 
77  /// Return a Timestamp representing the current moment in time.
78  static Timestamp now();
79 
80  /// Negate an interval to return an interval. Negate a timestamp
81  /// to return a timestamp, even though that doesn't make much sense.
82  Timestamp operator-() const;
83 
84  /// Subtract two Timestamps to return an interval. Subtract two
85  /// intervals to return an interval. Subtract an interval from a
86  /// Timestamp to return a Timestamp.
87  Timestamp operator-(const Timestamp &rhs) const;
88 
89  /// Add a Timestamp and an interval to get a Timestamp. Add two
90  /// intervals to return an interval.
91  Timestamp operator+(const Timestamp &rhs) const;
92 
93  /// Increment the Timestamp by the interval.
94  Timestamp &operator+=(const Timestamp &rhs);
95 
96  /// Decrement the Timestamp by the interval.
97  Timestamp &operator-=(const Timestamp &rhs);
98 
99  /// Multiply a Timestamp representing an interval by a constant.
100  template<typename T>
101  Timestamp operator*(T rhs) const {
102  MS t = makeMS((TIMESTAMPTYPE)_ms.type, (long long int)(_ms.value * rhs));
103  return Timestamp(t);
104  }
105  /// Multiply a Timestamp representing an interval by a constant.
106  template<typename T>
108  *this = *this * rhs;
109  return *this;
110  }
111  /// Divide a Timestamp representing an interval by a constant.
112  template<typename T>
113  Timestamp operator/(T rhs) const {
114  MS t = makeMS((TIMESTAMPTYPE)_ms.type, (long long int)(_ms.value / rhs));
115  return Timestamp(t);
116  }
117  /// Divide a Timestamp representing an interval by a constant.
118  template<typename T>
120  *this = *this / rhs;
121  return *this;
122  }
123 
124  /// Divide two Timestamps representing an interval to find their
125  /// quotient.
126  double operator/(Timestamp rhs) const {
127  return (double)_ms.value / (double)rhs._ms.value;
128  }
129 
130  /// Modulo a Timestamp by an interval.
131  Timestamp operator%(const Timestamp &rhs) const {
132  MS t = makeMS(INTERVAL, _ms.value % rhs._ms.value);
133  return Timestamp(t);
134  }
135 
136  /// Modulo a Timestamp by an interval.
138  *this = *this % rhs;
139  return *this;
140  }
141 
142  /// Return true if this Timestamp is before rhs.
143  bool operator<(const Timestamp &rhs) const {
144  return (_ms.value < rhs._ms.value);
145  }
146  /// Return true if this Timestamp is before or at the same time as
147  /// rhs.
148  bool operator<=(const Timestamp &rhs) const {
149  return (_ms.value <= rhs._ms.value);
150  }
151  /// Return true if this Timestamp is at the same time as rhs.
152  bool operator==(const Timestamp &rhs) const {
153  return (_ms.value == rhs._ms.value);
154  }
155  /// Return true if this Timestamp is not at the same time as rhs.
156  bool operator!=(const Timestamp &rhs) const {
157  return (_ms.value != rhs._ms.value);
158  }
159  /// Return true if this Timestamp is after or at the same time as
160  /// rhs.
161  bool operator>=(const Timestamp &rhs) const {
162  return (_ms.value >= rhs._ms.value);
163  }
164  /// Return true if this Timestamp is after rhs.
165  bool operator>(const Timestamp &rhs) const {
166  return (_ms.value > rhs._ms.value);
167  }
168 
169  /// Return true if this Timestamp is an interval.
170  bool isInterval() const {
171  return (_ms.type != TIMESTAMP);
172  }
173 
174  /// Create a time from a count of milliseconds.
175  static Timestamp milliseconds(long long milliseconds) {
176  MS t = makeMS(INTERVAL, milliseconds);
177  return Timestamp(t);
178  }
179 
180  /// Create a time from a count of seconds.
181  template<typename T>
182  static Timestamp seconds(T seconds) {
183  MS t = makeMS(INTERVAL, ((long long)(seconds * THOUSAND)));
184  return Timestamp(t);
185  }
186  /// Create a time from a count of seconds.
187  static Timestamp seconds(double seconds) {
188  double roundingValue = seconds > 0 ? 0.5 : -0.5;
189  MS t = makeMS(INTERVAL, ((long long)(seconds * THOUSAND + roundingValue)));
190  return Timestamp(t);
191  }
192 
193  /// Construct an interval from minutes
194  template<typename T>
195  static Timestamp minutes(T minutes) {
196  MS t = makeMS(INTERVAL, ((long long)minutes) * MILLISECONDS_PER_MINUTE);
197  return Timestamp(t);
198  }
199  /// Construct an interval from minutes
200  static Timestamp minutes(double minutes) {
201  double roundingValue = minutes > 0 ? 0.5 : -0.5;
202  MS t = makeMS(INTERVAL, (long long int)(minutes * MILLISECONDS_PER_MINUTE + roundingValue));
203  return Timestamp(t);
204  }
205 
206  /// Construct an interval from hours
207  template<typename T>
208  static Timestamp hours(T hours) {
209  MS t = makeMS(INTERVAL, ((long long)hours) * MILLISECONDS_PER_HOUR);
210  return Timestamp(t);
211  }
212  /// Construct an interval from hours
213  static Timestamp hours(double hours) {
214  double roundingValue = hours > 0 ? 0.5 : -0.5;
215  MS t = makeMS(INTERVAL, (long long int)(hours * MILLISECONDS_PER_HOUR + roundingValue));
216  return Timestamp(t);
217  }
218 
219  /// Construct an interval from days
220  template<typename T>
221  static Timestamp days(T days) {
222  MS t = makeMS(INTERVAL, ((long long)days) * MILLISECONDS_PER_DAY);
223  return Timestamp(t);
224  }
225  /// Construct an interval from days
226  static Timestamp days(double days) {
227  double roundingValue = days > 0 ? 0.5 : -0.5;
228  MS t = makeMS(INTERVAL, (long long int)(days * MILLISECONDS_PER_DAY + roundingValue));
229  return Timestamp(t);
230  }
231 
232  /// Construct an interval from weeks
233  template<typename T>
234  static Timestamp weeks(T weeks) {
235  MS t = makeMS(INTERVAL, ((long long)weeks) * MILLISECONDS_PER_DAY * DAYS_PER_WEEK);
236  return Timestamp(t);
237  }
238  /// Construct an interval from weeks
239  static Timestamp weeks(double weeks) {
240  double roundingValue = weeks > 0 ? 0.5 : -0.5;
241  MS t = makeMS(INTERVAL, (long long int)(weeks * MILLISECONDS_PER_DAY * DAYS_PER_WEEK + roundingValue));
242  return Timestamp(t);
243  }
244 
245  /// Return the time as milliseconds.
246  long long toMsecs() const {
247  return _ms.value;
248  }
249 
250  /// Return the time as seconds
251  long long toSecs() const {
252  return _ms.value / THOUSAND;
253  }
254 
255  /// compare 2 timestamps
256  /// return less than zero this < other
257  /// return greater than zero this > other
258  /// return 0 if they are the same
259  int compare(const Timestamp &other) const {
260  assert(_ms.type == other._ms.type);
261  if(_ms.value < other._ms.value) { return -1; }
262  if(_ms.value > other._ms.value) { return 1; }
263  return 0;
264  }
265 
266  /// Return seconds after the minute
267  double getSecond() const;
268 
269  /// Return milliseconds after the second
270  double getMillisecond() const;
271 
272  /// Return minutes after hour
273  int getMinute() const;
274 
275  /// Return hours since midnight
276  int getHour() const;
277 
278  /// Return day since Sunday
279  int getDayOfWeek() const;
280 
281  /// Return day of month
282  int getDayOfMonth() const;
283 
284  /// Return month since January
285  int getMonth() const;
286 
287  /// Return year
288  int getYear() const;
289 
290  /// Set seconds after the minute
291  void setSecond(double seconds);
292 
293  /// Set minutes after the hour
294  void setMinute(int minutes);
295 
296  /// Set hours since midnight
297  void setHour(int hours);
298 
299  /// Set day of month
300  void setDayOfMonth(int day_of_month);
301 
302  /// Set month since January
303  void setMonth(int month);
304 
305  /// Set year
306  void setYear(int year);
307 
308  /// Return a human readable string rep of this Timestamp
309  std::string as_string(bool displayTimezone=true) const;
310 
311 private:
312  friend class sb_internal::TimestampTest;
313 
314  /// Set an arbitrary Timestamp field
315  void setField(TIMESTAMP_FIELD, int *value);
316 
317  // Constants for use in our math when dealing with timevals.
318  static const long long MILLISECONDS_PER_MINUTE = 60000LL;
319  static const long long MILLISECONDS_PER_HOUR = 3600000LL;
320  static const long long MILLISECONDS_PER_DAY = 86400000LL;
321  static const long long DAYS_PER_WEEK = 7LL;
322  static const long long THOUSAND = 1000LL;
323  static const long long MILLION = 1000000LL;
324 
325  MS _ms;
326 
327  static MS makeMS(TIMESTAMPTYPE t, long long v);
328 
329  // Private constructor from a long long int.
330  explicit Timestamp(MS ms)
331  { _ms = ms;}
332 
333  static bool validateTimestampFields(
334  int year,
335  int month,
336  int day,
337  int hour,
338  int minute,
339  int second);
340 
341  Timestamp(long long int ts, int type=TIMESTAMP)
342  {
343  _ms.type = type;
344  _ms.value = ts;
345  }
346 
347  // Routines for dealing with potentially unaligned Timestamps. On
348  // SPARC, copy an int at a time; on Intel, read/write directly.
349 #ifdef sparc
350  union MSAndInts {
351  Timestamp::MS ms;
352  struct { int i1; int i2; };
353  };
354 
355  inline static Timestamp
356  getUnaligned(const Timestamp *p)
357  {
358  const int *dip = (const int*)p;
359  MSAndInts di;
360  di.i1 = dip[0];
361  di.i2 = dip[1];
362  return Timestamp(di.ms);
363  }
364 
365  inline static void
366  setUnaligned(Timestamp *p, Timestamp value)
367  {
368  int *dip = (int*)p;
369  MSAndInts di;
370  di.ms = value._ms;
371  dip[0] = di.i1;
372  dip[1] = di.i2;
373  }
374 #else
375  // Intel
376  inline static Timestamp getUnaligned(const Timestamp *p) { return *p; }
377  inline static void setUnaligned(Timestamp *p, Timestamp value) { *p = value; }
378 #endif
379 
380  friend class sb_internal::TimestampUtil;
381 
382 #ifndef DOXYGEN_SKIP
383  friend sb::Timestamp NMSTL::getUnaligned(const sb::Timestamp *p);
384  friend void NMSTL::setUnaligned(sb::Timestamp *p, sb::Timestamp value);
385 #endif
386 
387  // constants to be used in conjunction with the cpu counter to determine current time more efficiently
388  static const long long RESOLUTION_PER_SEC = 1000LL; // time resolution units = milliseconds
389  static const long long MIN_SYSTEM_INTERVAL = 10LL; // min system synchronization time interval = 10ms
390  static const long long MAX_SYSTEM_INTERVAL = 100LL; // max system synchronization time interval = 100ms
391  static const unsigned long long TICKS_PER_SEC; // computed from cpu frequency
392  static const unsigned long long TICKS_PER_RESOLUTION; // computed from cpu frequency
393 
394  // thread local storage to be used in conjunction with the cpu counter to determine current time more efficiently
395 #ifndef sun
396 #ifndef SWIG
397  static SB_THREAD_LOCAL unsigned long long systemTicks;
398  static SB_THREAD_LOCAL long long systemTime;
399  static SB_THREAD_LOCAL long long systemInterval;
400  static SB_THREAD_LOCAL long long lastTimestamp;
401 #endif // SWIG
402 #endif // sun
403  static unsigned long long initCpuTicksPerSecond();
404 
405  static unsigned long long cpuTicks();
406 };
407 
408 inline unsigned long long Timestamp::cpuTicks()
409 {
410  unsigned int low, high;
411 
412 #ifdef sparc
413  asm volatile ("rd %%tick, %%g1; srlx %%g1, 32, %1" : "=r" (low), "=r" (high));
414 #else
415 #if defined(WIN32)
416 LARGE_INTEGER timestamp;
417 
418 #if defined(_WIN64)
419  QueryPerformanceCounter(&timestamp);
420 #else
421  _asm
422  {
423  rdtsc
424  mov timestamp.LowPart, EAX
425  mov timestamp.HighPart, EDX
426  }
427 #endif /*WIN64*/
428 
429 high = timestamp.HighPart;
430 low = timestamp.LowPart;
431 
432 #else /*WIN32*/
433  asm volatile ("rdtsc" : "=a" (low), "=d" (high));
434 #endif
435 #endif
436  return ((unsigned long long)high<<32) + low;
437 };
438 
439 SB_NAMESPACE_END;
440 
441 #ifndef DOXYGEN_SKIP
442 NMSTL_NAMESPACE_BEGIN;
443 
444 inline sb::Timestamp getUnaligned(const sb::Timestamp *p)
445 {
446  return sb::Timestamp::getUnaligned(p);
447 }
448 
449 inline void setUnaligned(sb::Timestamp *p, sb::Timestamp value)
450 {
451  sb::Timestamp::setUnaligned(p, value);
452 }
453 
454 NMSTL_NAMESPACE_END;
455 #endif //DOXYGEN_SKIP
456 
457 #endif
458 
459 // LocalWords: StreamBase NMSTL ntime Timestamp timevals timeval tm TODO rhs
460 // LocalWords: gettimeofday