StreamBase C++ API 10.3.0.4

- Main Page
- Related Pages
- Classes
- Files

- File List

Timestamp.hpp
1 //
2 // Copyright (c) 2004-2018 Cloud Software Group, 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.
71 Timestamp()
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>
107 Timestamp &operator*=(T rhs) {
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>
119 Timestamp &operator/=(T rhs) {
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.
137 Timestamp operator%=(const Timestamp &rhs) {
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