This is Unofficial EPICS BASE Doxygen Site
epicsTime.cpp
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2011 LANS LLC, as Operator of
3 * Los Alamos National Laboratory.
4 * Copyright (c) 2002 The Regents of the University of California, as
5 * Operator of Los Alamos National Laboratory.
6 * Copyright (c) 2007 UChicago Argonne LLC, as Operator of Argonne
7 * National Laboratory.
8 * EPICS BASE is distributed subject to a Software License Agreement found
9 * in file LICENSE that is included with this distribution.
10 \*************************************************************************/
11 /* epicsTime.cpp */
12 /* Author Jeffrey O. Hill */
13 
14 // Notes:
15 // 1) The epicsTime::nSec field is not public and so it could be
16 // changed to work more like the fractional seconds field in the NTP time
17 // stamp. That would significantly improve the precision of epicsTime on
18 // 64 bit architectures.
19 //
20 
21 #include <stdexcept>
22 
23 #include <ctype.h>
24 #include <stddef.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <limits.h>
28 #include <float.h>
29 #include <string> // vxWorks 6.0 requires this include
30 
31 #include "locationException.h"
32 #include "epicsAssert.h"
33 #include "epicsVersion.h"
34 #include "envDefs.h"
35 #include "epicsTime.h"
36 #include "osiSock.h" /* pull in struct timeval */
37 #include "epicsStdio.h"
38 
39 static const char pEpicsTimeVersion[] =
40  "@(#) " EPICS_VERSION_STRING ", Common Utilities Library";
41 
42 //
43 // useful public constants
44 //
45 static const unsigned mSecPerSec = 1000u;
46 static const unsigned uSecPerMSec = 1000u;
47 static const unsigned uSecPerSec = uSecPerMSec * mSecPerSec;
48 static const unsigned nSecPerUSec = 1000u;
49 static const unsigned nSecPerSec = nSecPerUSec * uSecPerSec;
50 static const unsigned nSecFracDigits = 9u;
51 
52 
53 // Timescale conversion data
54 
55 static const unsigned long NTP_TIME_AT_POSIX_EPOCH = 2208988800ul;
56 static const unsigned long NTP_TIME_AT_EPICS_EPOCH =
57  NTP_TIME_AT_POSIX_EPOCH + POSIX_TIME_AT_EPICS_EPOCH;
58 
59 //
60 // epicsTime (const unsigned long secIn, const unsigned long nSecIn)
61 //
62 inline epicsTime::epicsTime (const unsigned long secIn, const unsigned long nSecIn) :
63  secPastEpoch ( secIn ), nSec ( nSecIn )
64 {
65  if (nSecIn >= nSecPerSec) {
66  this->secPastEpoch += nSecIn / nSecPerSec;
67  this->nSec = nSecIn % nSecPerSec;
68  }
69 }
70 
71 //
72 // epicsTimeLoadTimeInit
73 //
75 public:
77  double epicsEpochOffset; // seconds
78  double time_tSecPerTick; // seconds (both NTP and EPICS use int sec)
81 };
82 
83 //
84 // epicsTimeLoadTimeInit ()
85 //
87 {
88  // All we know about time_t is that it is an arithmetic type.
89  time_t t_zero = static_cast<time_t> (0);
90  time_t t_one = static_cast<time_t> (1);
91  this->time_tSecPerTick = difftime (t_one, t_zero);
92 
93  /* The EPICS epoch (1/1/1990 00:00:00UTC) was 631152000 seconds after
94  * the ANSI epoch (1/1/1970 00:00:00UTC)
95  * Convert this offset into time_t units, however this must not be
96  * calculated using local time (i.e. using mktime() or similar), since
97  * in the UK the ANSI Epoch had daylight saving time in effect, and
98  * the value calculated would be 3600 seconds wrong.*/
99  this->epicsEpochOffset =
101 
102  if (this->time_tSecPerTick == 1.0 &&
103  this->epicsEpochOffset <= ULONG_MAX &&
104  this->epicsEpochOffset >= 0) {
105  // We can use simpler code on Posix-compliant systems
106  this->useDiffTimeOptimization = true;
108  static_cast<unsigned long>(this->epicsEpochOffset);
109  } else {
110  // Forced to use the slower but correct code
111  this->useDiffTimeOptimization = false;
113  }
114 }
115 
116 //
117 // private epicsTime::addNanoSec ()
118 //
119 // Most formats keep the nSec value as an unsigned long, so are +ve.
120 // struct timeval's tv_usec may be -1, but I think that means error,
121 // so this private method never needs to handle -ve offsets.
122 //
123 void epicsTime :: addNanoSec ( long nSecAdj )
124 {
125  if (nSecAdj <= 0)
126  return;
127 
128  if (static_cast<unsigned long>(nSecAdj) >= nSecPerSec) {
129  this->secPastEpoch += nSecAdj / nSecPerSec;
130  nSecAdj %= nSecPerSec;
131  }
132 
133  this->nSec += nSecAdj; // Can't overflow
134  if (this->nSec >= nSecPerSec) {
135  this->secPastEpoch++;
136  this->nSec -= nSecPerSec;
137  }
138 }
139 
140 //
141 // epicsTime (const time_t_wrapper &tv)
142 //
143 epicsTime::epicsTime ( const time_t_wrapper & ansiTimeTicks )
144 {
145  // avoid c++ static initialization order issues
146  static epicsTimeLoadTimeInit & lti = * new epicsTimeLoadTimeInit ();
147 
148  //
149  // try to directly map time_t into an unsigned long integer because this is
150  // faster on systems w/o hardware floating point and a simple integer type time_t.
151  //
152  if ( lti.useDiffTimeOptimization ) {
153  // LONG_MAX is used here and not ULONG_MAX because some systems (linux)
154  // still store time_t as a long.
155  if ( ansiTimeTicks.ts > 0 && ansiTimeTicks.ts <= LONG_MAX ) {
156  unsigned long ticks = static_cast < unsigned long > ( ansiTimeTicks.ts );
157  if ( ticks >= lti.epicsEpochOffsetAsAnUnsignedLong ) {
158  this->secPastEpoch = ticks - lti.epicsEpochOffsetAsAnUnsignedLong;
159  }
160  else {
161  this->secPastEpoch = ( ULONG_MAX - lti.epicsEpochOffsetAsAnUnsignedLong ) + ticks;
162  }
163  this->nSec = 0;
164  return;
165  }
166  }
167 
168  //
169  // otherwise map time_t, which ANSI C and POSIX define as any arithmetic type,
170  // into type double
171  //
172  double sec = ansiTimeTicks.ts * lti.time_tSecPerTick - lti.epicsEpochOffset;
173 
174  //
175  // map into the the EPICS time stamp range (which allows rollover)
176  //
177  static double uLongMax = static_cast<double> (ULONG_MAX);
178  if ( sec < 0.0 ) {
179  if ( sec < -uLongMax ) {
180  sec = sec + static_cast<unsigned long> ( -sec / uLongMax ) * uLongMax;
181  }
182  sec += uLongMax;
183  }
184  else if ( sec > uLongMax ) {
185  sec = sec - static_cast<unsigned long> ( sec / uLongMax ) * uLongMax;
186  }
187 
188  this->secPastEpoch = static_cast <unsigned long> ( sec );
189  this->nSec = static_cast <unsigned long> ( ( sec-this->secPastEpoch ) * nSecPerSec );
190 }
191 
192 epicsTime::epicsTime (const epicsTimeStamp &ts)
193 {
194  if ( ts.nsec < nSecPerSec ) {
195  this->secPastEpoch = ts.secPastEpoch;
196  this->nSec = ts.nsec;
197  }
198  else {
199  throw std::logic_error (
200  "epicsTimeStamp has overflow in nano-seconds field" );
201  }
202 }
203 
204 epicsTime::epicsTime () :
205  secPastEpoch(0u), nSec(0u) {}
206 
207 epicsTime epicsTime::getCurrent ()
208 {
209  epicsTimeStamp current;
210  int status = epicsTimeGetCurrent (&current);
211  if (status) {
212  throwWithLocation ( unableToFetchCurrentTime () );
213  }
214  return epicsTime ( current );
215 }
216 
217 epicsTime epicsTime::getMonotonic()
218 {
219  epicsTimeStamp current;
220  epicsTimeGetMonotonic (&current); // can't fail
221  return epicsTime ( current );
222 }
223 
224 epicsTime epicsTime::getEvent (const epicsTimeEvent &event)
225 {
226  epicsTimeStamp current;
227  int status = epicsTimeGetEvent (&current, event);
228  if (status) {
229  throwWithLocation ( unableToFetchCurrentTime () );
230  }
231  return epicsTime ( current );
232 }
233 
234 //
235 // operator time_t_wrapper ()
236 //
237 epicsTime::operator time_t_wrapper () const
238 {
239  // avoid c++ static initialization order issues
240  static epicsTimeLoadTimeInit & lti = * new epicsTimeLoadTimeInit ();
241  time_t_wrapper wrap;
242 
243  if ( lti.useDiffTimeOptimization ) {
244  if ( this->secPastEpoch < ULONG_MAX - lti.epicsEpochOffsetAsAnUnsignedLong ) {
245  wrap.ts = static_cast <time_t> ( this->secPastEpoch + lti.epicsEpochOffsetAsAnUnsignedLong );
246  return wrap;
247  }
248  }
249 
250  //
251  // map type double into time_t which ansi C defines as some arithmetic type
252  //
253  double tmp = (this->secPastEpoch + lti.epicsEpochOffset) / lti.time_tSecPerTick;
254  tmp += (this->nSec / lti.time_tSecPerTick) / nSecPerSec;
255 
256  wrap.ts = static_cast <time_t> ( tmp );
257 
258  return wrap;
259 }
260 
261 //
262 // convert to ANSI C struct tm (with nano seconds) adjusted for the local time zone
263 //
264 epicsTime::operator local_tm_nano_sec () const
265 {
266  time_t_wrapper ansiTimeTicks = *this;
267 
268  local_tm_nano_sec tm;
269 
270  int status = epicsTime_localtime ( &ansiTimeTicks.ts, &tm.ansi_tm );
271  if ( status ) {
272  throw std::logic_error ( "epicsTime_localtime failed" );
273  }
274 
275  tm.nSec = this->nSec;
276 
277  return tm;
278 }
279 
280 //
281 // convert to ANSI C struct tm (with nano seconds) adjusted for UTC
282 //
283 epicsTime::operator gm_tm_nano_sec () const
284 {
285  time_t_wrapper ansiTimeTicks = *this;
286 
287  gm_tm_nano_sec tm;
288 
289  int status = epicsTime_gmtime ( &ansiTimeTicks.ts, &tm.ansi_tm );
290  if ( status ) {
291  throw std::logic_error ( "epicsTime_gmtime failed" );
292  }
293 
294  tm.nSec = this->nSec;
295 
296  return tm;
297 }
298 
299 //
300 // epicsTime (const local_tm_nano_sec &tm)
301 //
302 epicsTime::epicsTime (const local_tm_nano_sec &tm)
303 {
304  struct tm tmp = tm.ansi_tm;
305  time_t_wrapper ansiTimeTicks = { mktime (&tmp) };
306 
307  static const time_t mktimeError = static_cast <time_t> (-1);
308  if (ansiTimeTicks.ts == mktimeError) {
309  throwWithLocation ( formatProblemWithStructTM () );
310  }
311 
312  *this = epicsTime(ansiTimeTicks);
313  this->addNanoSec(tm.nSec);
314 }
315 
316 //
317 // epicsTime (const gm_tm_nano_sec &tm)
318 //
319 
320 // do conversion avoiding the timezone mechanism
321 static inline int is_leap(int year)
322 {
323  if (year % 400 == 0)
324  return 1;
325  if (year % 100 == 0)
326  return 0;
327  if (year % 4 == 0)
328  return 1;
329  return 0;
330 }
331 
332 static inline int days_from_0(int year)
333 {
334  year--;
335  return 365 * year + (year / 400) - (year / 100) + (year / 4);
336 }
337 
338 static inline int days_from_1970(int year)
339 {
340  static const int days_from_0_to_1970 = days_from_0(1970);
341  return days_from_0(year) - days_from_0_to_1970;
342 }
343 
344 static inline int days_from_1jan(int year, int month, int day)
345 {
346  static const int days[2][12] =
347  {
348  { 0,31,59,90,120,151,181,212,243,273,304,334},
349  { 0,31,60,91,121,152,182,213,244,274,305,335}
350  };
351  return days[is_leap(year)][month-1] + day - 1;
352 }
353 
354 epicsTime::epicsTime (const gm_tm_nano_sec &tm)
355 {
356  int year = tm.ansi_tm.tm_year + 1900;
357  int month = tm.ansi_tm.tm_mon;
358  if (month > 11) {
359  year += month / 12;
360  month %= 12;
361  } else if (month < 0) {
362  int years_diff = (-month + 11) / 12;
363  year -= years_diff;
364  month += 12 * years_diff;
365  }
366  month++;
367 
368  int day = tm.ansi_tm.tm_mday;
369  int day_of_year = days_from_1jan(year, month, day);
370  int days_since_epoch = days_from_1970(year) + day_of_year;
371 
372  time_t_wrapper ansiTimeTicks;
373  ansiTimeTicks.ts = ((days_since_epoch
374  * 24 + tm.ansi_tm.tm_hour)
375  * 60 + tm.ansi_tm.tm_min)
376  * 60 + tm.ansi_tm.tm_sec;
377 
378  *this = epicsTime(ansiTimeTicks);
379  this->addNanoSec(tm.nSec);
380 }
381 
382 //
383 // operator struct timespec ()
384 //
385 epicsTime::operator struct timespec () const
386 {
387  struct timespec ts;
388  time_t_wrapper ansiTimeTicks;
389 
390  ansiTimeTicks = *this;
391  ts.tv_sec = ansiTimeTicks.ts;
392  ts.tv_nsec = static_cast<long> (this->nSec);
393  return ts;
394 }
395 
396 //
397 // epicsTime (const struct timespec &ts)
398 //
399 epicsTime::epicsTime (const struct timespec &ts)
400 {
401  time_t_wrapper ansiTimeTicks;
402 
403  ansiTimeTicks.ts = ts.tv_sec;
404  *this = epicsTime (ansiTimeTicks);
405  this->addNanoSec (ts.tv_nsec);
406 }
407 
408 //
409 // operator struct timeval ()
410 //
411 epicsTime::operator struct timeval () const
412 {
413  struct timeval ts;
414  time_t_wrapper ansiTimeTicks;
415 
416  ansiTimeTicks = *this;
417  // On Posix systems timeval :: tv_sec is a time_t so this can be
418  // a direct assignment. On other systems I dont know that we can
419  // guarantee that time_t and timeval :: tv_sec will have the
420  // same epoch or have the same scaling factor to discrete seconds.
421  // For example, on windows time_t changed recently to a 64 bit
422  // quantity but timeval is still a long. That can cause problems
423  // on 32 bit systems. So technically, we should have an os
424  // dependent conversion between time_t and timeval :: tv_sec?
425  ts.tv_sec = ansiTimeTicks.ts;
426  ts.tv_usec = static_cast < long > ( this->nSec / nSecPerUSec );
427  return ts;
428 }
429 
430 //
431 // epicsTime (const struct timeval &ts)
432 //
433 epicsTime::epicsTime (const struct timeval &ts)
434 {
435  time_t_wrapper ansiTimeTicks;
436  // On Posix systems timeval :: tv_sec is a time_t so this can be
437  // a direct assignment. On other systems I dont know that we can
438  // guarantee that time_t and timeval :: tv_sec will have the
439  // same epoch or have the same scaling factor to discrete seconds.
440  // For example, on windows time_t changed recently to a 64 bit
441  // quantity but timeval is still a long. That can cause problems
442  // on 32 bit systems. So technically, we should have an os
443  // dependent conversion between time_t and timeval :: tv_sec?
444  ansiTimeTicks.ts = ts.tv_sec;
445  *this = epicsTime (ansiTimeTicks);
446  this->addNanoSec (ts.tv_usec * nSecPerUSec);
447 }
448 
449 
450 static const double NTP_FRACTION_DENOMINATOR = 1.0 + 0xffffffff;
451 
452 struct l_fp { /* NTP time stamp */
453  epicsUInt32 l_ui; /* sec past NTP epoch */
454  epicsUInt32 l_uf; /* fractional seconds */
455 };
456 
457 //
458 // epicsTime::l_fp ()
459 //
460 epicsTime::operator l_fp () const
461 {
462  l_fp ts;
463  ts.l_ui = this->secPastEpoch + NTP_TIME_AT_EPICS_EPOCH;
464  ts.l_uf = static_cast < unsigned long >
465  ( ( this->nSec * NTP_FRACTION_DENOMINATOR ) / nSecPerSec );
466  return ts;
467 }
468 
469 //
470 // epicsTime::epicsTime ( const l_fp & ts )
471 //
472 epicsTime::epicsTime ( const l_fp & ts )
473 {
474  this->secPastEpoch = ts.l_ui - NTP_TIME_AT_EPICS_EPOCH;
475  this->nSec = static_cast < unsigned long >
476  ( ( ts.l_uf / NTP_FRACTION_DENOMINATOR ) * nSecPerSec );
477 }
478 
479 epicsTime::operator epicsTimeStamp () const
480 {
481  if ( this->nSec >= nSecPerSec ) {
482  throw std::logic_error (
483  "epicsTimeStamp has overflow in nano-seconds field?" );
484  }
485  epicsTimeStamp ts;
486  //
487  // truncation by design
488  // -------------------
489  // epicsTime::secPastEpoch is based on ulong and has much greater range
490  // on 64 bit hosts than the original epicsTimeStamp::secPastEpoch. The
491  // epicsTimeStamp::secPastEpoch is based on epicsUInt32 so that it will
492  // match the original network protocol. Of course one can anticipate
493  // that eventually, a epicsUInt64 based network time stamp will be
494  // introduced when 64 bit architectures are more ubiquitous.
495  //
496  // Truncation usually works fine here because the routines in this code
497  // that compute time stamp differences and compare time stamps produce
498  // good results when the operands are on either side of a time stamp
499  // rollover as long as the difference between the operands does not exceed
500  // 1/2 of full range.
501  //
502  ts.secPastEpoch = static_cast < epicsUInt32 > ( this->secPastEpoch );
503  ts.nsec = static_cast < epicsUInt32 > ( this->nSec );
504  return ts;
505 }
506 
507 // Break up a format string into "<strftime prefix>%0<nnn>f<postfix>"
508 // (where <nnn> in an unsigned integer)
509 // Result:
510 // A) Copies a prefix which is valid for ANSI strftime into the supplied
511 // buffer setting the buffer to an empty string if no prefix is present.
512 // B) Indicates whether a valid "%0<n>f]" is present or not and if so
513 // specifying its nnnn
514 // C) returning a pointer to the postfix (which might be passed again
515 // to fracFormatFind.
516 static const char * fracFormatFind (
517  const char * const pFormat,
518  char * const pPrefixBuf,
519  const size_t prefixBufLen,
520  bool & fracFmtFound,
521  unsigned long & fracFmtWidth )
522 {
523  assert ( prefixBufLen > 1 );
524  unsigned long width = ULONG_MAX;
525  bool fracFound = false;
526  const char * pAfter = pFormat;
527  const char * pFmt = pFormat;
528  while ( *pFmt != '\0' ) {
529  if ( *pFmt == '%' ) {
530  if ( pFmt[1] == '%' ) {
531  pFmt++;
532  }
533  else if ( pFmt[1] == 'f' ) {
534  fracFound = true;
535  pAfter = & pFmt[2];
536  break;
537  }
538  else {
539  errno = 0;
540  char * pAfterTmp;
541  unsigned long result = strtoul ( pFmt + 1, & pAfterTmp, 10 );
542  if ( errno == 0 && *pAfterTmp == 'f' && result > 0 ) {
543  width = result;
544  fracFound = true;
545  pAfter = pAfterTmp + 1;
546  break;
547  }
548  }
549  }
550  pFmt++;
551  pAfter = pFmt;
552  }
553  size_t len = pFmt - pFormat;
554  if ( len < prefixBufLen ) {
555  strncpy ( pPrefixBuf, pFormat, len );
556  pPrefixBuf [ len ] = '\0';
557  if ( fracFound ) {
558  fracFmtFound = true;
559  fracFmtWidth = width;
560  }
561  else {
562  fracFmtFound = false;
563  }
564  }
565  else {
566  strncpy ( pPrefixBuf, "<invalid format>", prefixBufLen - 1 );
567  pPrefixBuf [ prefixBufLen - 1 ] = '\0';
568  fracFmtFound = false;
569  pAfter = "";
570  }
571 
572  return pAfter;
573 }
574 
575 //
576 // size_t epicsTime::strftime ()
577 //
578 size_t epicsTime::strftime (
579  char * pBuff, size_t bufLength, const char * pFormat ) const
580 {
581  if ( bufLength == 0u ) {
582  return 0u;
583  }
584 
585  // presume that EPOCH date is an uninitialized time stamp
586  if ( this->secPastEpoch == 0 && this->nSec == 0u ) {
587  strncpy ( pBuff, "<undefined>", bufLength );
588  pBuff[bufLength-1] = '\0';
589  return strlen ( pBuff );
590  }
591 
592  char * pBufCur = pBuff;
593  const char * pFmt = pFormat;
594  size_t bufLenLeft = bufLength;
595  while ( *pFmt != '\0' && bufLenLeft > 1 ) {
596  // look for "%0<n>f" at the end (used for fractional second formatting)
597  char strftimePrefixBuf [256];
598  bool fracFmtFound;
599  unsigned long fracWid = 0;
600  pFmt = fracFormatFind (
601  pFmt,
602  strftimePrefixBuf, sizeof ( strftimePrefixBuf ),
603  fracFmtFound, fracWid );
604 
605  // nothing more in the string, then quit
606  if ( ! ( strftimePrefixBuf[0] != '\0' || fracFmtFound ) ) {
607  break;
608  }
609  // all but fractional seconds use strftime formatting
610  if ( strftimePrefixBuf[0] != '\0' ) {
611  local_tm_nano_sec tmns = *this;
612  size_t strftimeNumChar = :: strftime (
613  pBufCur, bufLenLeft, strftimePrefixBuf, & tmns.ansi_tm );
614  pBufCur [ strftimeNumChar ] = '\0';
615  pBufCur += strftimeNumChar;
616  bufLenLeft -= strftimeNumChar;
617  }
618 
619  // fractional seconds formating
620  if ( fracFmtFound && bufLenLeft > 1 ) {
621  if ( fracWid > nSecFracDigits ) {
622  fracWid = nSecFracDigits;
623  }
624  // verify that there are enough chars left for the fractional seconds
625  if ( fracWid < bufLenLeft )
626  {
627  local_tm_nano_sec tmns = *this;
628  if ( tmns.nSec < nSecPerSec ) {
629  // divisors for fraction (see below)
630  static const unsigned long div[] = {
631  static_cast < unsigned long > ( 1e9 ),
632  static_cast < unsigned long > ( 1e8 ),
633  static_cast < unsigned long > ( 1e7 ),
634  static_cast < unsigned long > ( 1e6 ),
635  static_cast < unsigned long > ( 1e5 ),
636  static_cast < unsigned long > ( 1e4 ),
637  static_cast < unsigned long > ( 1e3 ),
638  static_cast < unsigned long > ( 1e2 ),
639  static_cast < unsigned long > ( 1e1 ),
640  static_cast < unsigned long > ( 1e0 )
641  };
642  // round without overflowing into whole seconds
643  unsigned long frac = tmns.nSec + div[fracWid] / 2;
644  if (frac >= nSecPerSec)
645  frac = nSecPerSec - 1;
646  // convert nanosecs to integer of correct range
647  frac /= div[fracWid];
648  char fracFormat[32];
649  sprintf ( fracFormat, "%%0%lulu", fracWid );
650  int status = epicsSnprintf ( pBufCur, bufLenLeft, fracFormat, frac );
651  if ( status > 0 ) {
652  unsigned long nChar = static_cast < unsigned long > ( status );
653  if ( nChar >= bufLenLeft ) {
654  nChar = bufLenLeft - 1;
655  }
656  pBufCur[nChar] = '\0';
657  pBufCur += nChar;
658  bufLenLeft -= nChar;
659  }
660  }
661  else {
662  static const char pOVF [] = "OVF";
663  size_t tmpLen = sizeof ( pOVF ) - 1;
664  if ( tmpLen >= bufLenLeft ) {
665  tmpLen = bufLenLeft - 1;
666  }
667  strncpy ( pBufCur, pOVF, tmpLen );
668  pBufCur[tmpLen] = '\0';
669  pBufCur += tmpLen;
670  bufLenLeft -= tmpLen;
671  }
672  }
673  else {
674  static const char pDoesntFit [] = "************";
675  size_t tmpLen = sizeof ( pDoesntFit ) - 1;
676  if ( tmpLen >= bufLenLeft ) {
677  tmpLen = bufLenLeft - 1;
678  }
679  strncpy ( pBufCur, pDoesntFit, tmpLen );
680  pBufCur[tmpLen] = '\0';
681  pBufCur += tmpLen;
682  bufLenLeft -= tmpLen;
683  break;
684  }
685  }
686  }
687  return pBufCur - pBuff;
688 }
689 
690 //
691 // epicsTime::show (unsigned)
692 //
693 void epicsTime::show ( unsigned level ) const
694 {
695  char bigBuffer[256];
696 
697  size_t numChar = this->strftime ( bigBuffer, sizeof ( bigBuffer ),
698  "%a %b %d %Y %H:%M:%S.%09f" );
699  if ( numChar > 0 ) {
700  printf ( "epicsTime: %s\n", bigBuffer );
701  }
702 
703  if ( level > 1 ) {
704  // this also suppresses the "defined, but not used"
705  // warning message
706  printf ( "epicsTime: revision \"%s\"\n",
707  pEpicsTimeVersion );
708  }
709 
710 }
711 
712 //
713 // epicsTime::operator + (const double &rhs)
714 //
715 // rhs has units seconds
716 //
717 epicsTime epicsTime::operator + (const double &rhs) const
718 {
719  unsigned long newSec, newNSec, secOffset, nSecOffset;
720  double fnsec;
721 
722  if (rhs >= 0) {
723  secOffset = static_cast <unsigned long> (rhs);
724  fnsec = rhs - secOffset;
725  nSecOffset = static_cast <unsigned long> ( (fnsec * nSecPerSec) + 0.5 );
726 
727  newSec = this->secPastEpoch + secOffset; // overflow expected
728  newNSec = this->nSec + nSecOffset;
729  if (newNSec >= nSecPerSec) {
730  newSec++; // overflow expected
731  newNSec -= nSecPerSec;
732  }
733  }
734  else {
735  secOffset = static_cast <unsigned long> (-rhs);
736  fnsec = rhs + secOffset;
737  nSecOffset = static_cast <unsigned long> ( (-fnsec * nSecPerSec) + 0.5 );
738 
739  newSec = this->secPastEpoch - secOffset; // underflow expected
740  if (this->nSec>=nSecOffset) {
741  newNSec = this->nSec - nSecOffset;
742  }
743  else {
744  // borrow
745  newSec--; // underflow expected
746  newNSec = this->nSec + (nSecPerSec - nSecOffset);
747  }
748  }
749  return epicsTime (newSec, newNSec);
750 }
751 
752 //
753 // operator -
754 //
755 // To make this code robust during timestamp rollover events
756 // time stamp differences greater than one half full scale are
757 // interpreted as rollover situations:
758 //
759 // when RHS is greater than THIS:
760 // RHS-THIS > one half full scale => return THIS + (ULONG_MAX-RHS)
761 // RHS-THIS <= one half full scale => return -(RHS-THIS)
762 //
763 // when THIS is greater than or equal to RHS
764 // THIS-RHS > one half full scale => return -(RHS + (ULONG_MAX-THIS))
765 // THIS-RHS <= one half full scale => return THIS-RHS
766 //
767 double epicsTime::operator - (const epicsTime &rhs) const
768 {
769  double nSecRes, secRes;
770 
771  //
772  // first compute the difference between the nano-seconds members
773  //
774  // nano sec member is not allowed to be greater that 1/2 full scale
775  // so the unsigned to signed conversion is ok
776  //
777  if (this->nSec>=rhs.nSec) {
778  nSecRes = this->nSec - rhs.nSec;
779  }
780  else {
781  nSecRes = rhs.nSec - this->nSec;
782  nSecRes = -nSecRes;
783  }
784 
785  //
786  // next compute the difference between the seconds members
787  // and invert the sign of the nano seconds result if there
788  // is a range violation
789  //
790  if (this->secPastEpoch<rhs.secPastEpoch) {
791  secRes = rhs.secPastEpoch - this->secPastEpoch;
792  if (secRes > ULONG_MAX/2) {
793  //
794  // In this situation where the difference is more than
795  // 68 years assume that the seconds counter has rolled
796  // over and compute the "wrap around" difference
797  //
798  secRes = 1 + (ULONG_MAX-secRes);
799  nSecRes = -nSecRes;
800  }
801  else {
802  secRes = -secRes;
803  }
804  }
805  else {
806  secRes = this->secPastEpoch - rhs.secPastEpoch;
807  if (secRes > ULONG_MAX/2) {
808  //
809  // In this situation where the difference is more than
810  // 68 years assume that the seconds counter has rolled
811  // over and compute the "wrap around" difference
812  //
813  secRes = 1 + (ULONG_MAX-secRes);
814  secRes = -secRes;
815  nSecRes = -nSecRes;
816  }
817  }
818 
819  return secRes + nSecRes/nSecPerSec;
820 }
821 
822 //
823 // operator <=
824 //
825 bool epicsTime::operator <= (const epicsTime &rhs) const
826 {
827  bool rc;
828 
829  if (this->secPastEpoch<rhs.secPastEpoch) {
830  if (rhs.secPastEpoch-this->secPastEpoch < ULONG_MAX/2) {
831  //
832  // In this situation where the difference is less than
833  // 69 years compute the expected result
834  //
835  rc = true;
836  }
837  else {
838  //
839  // In this situation where the difference is more than
840  // 69 years assume that the seconds counter has rolled
841  // over and compute the "wrap around" result
842  //
843  rc = false;
844  }
845  }
846  else if (this->secPastEpoch>rhs.secPastEpoch) {
847  if (this->secPastEpoch-rhs.secPastEpoch < ULONG_MAX/2) {
848  //
849  // In this situation where the difference is less than
850  // 69 years compute the expected result
851  //
852  rc = false;
853  }
854  else {
855  //
856  // In this situation where the difference is more than
857  // 69 years assume that the seconds counter has rolled
858  // over and compute the "wrap around" result
859  //
860  rc = true;
861  }
862  }
863  else {
864  if (this->nSec<=rhs.nSec) {
865  rc = true;
866  }
867  else {
868  rc = false;
869  }
870  }
871  return rc;
872 }
873 
874 //
875 // operator <
876 //
877 bool epicsTime::operator < (const epicsTime &rhs) const
878 {
879  bool rc;
880 
881  if (this->secPastEpoch<rhs.secPastEpoch) {
882  if (rhs.secPastEpoch-this->secPastEpoch < ULONG_MAX/2) {
883  //
884  // In this situation where the difference is less than
885  // 69 years compute the expected result
886  //
887  rc = true;
888  }
889  else {
890  //
891  // In this situation where the difference is more than
892  // 69 years assume that the seconds counter has rolled
893  // over and compute the "wrap around" result
894  //
895  rc = false;
896  }
897  }
898  else if (this->secPastEpoch>rhs.secPastEpoch) {
899  if (this->secPastEpoch-rhs.secPastEpoch < ULONG_MAX/2) {
900  //
901  // In this situation where the difference is less than
902  // 69 years compute the expected result
903  //
904  rc = false;
905  }
906  else {
907  //
908  // In this situation where the difference is more than
909  // 69 years assume that the seconds counter has rolled
910  // over and compute the "wrap around" result
911  //
912  rc = true;
913  }
914  }
915  else {
916  if (this->nSec<rhs.nSec) {
917  rc = true;
918  }
919  else {
920  rc = false;
921  }
922  }
923  return rc;
924 }
925 
926 extern "C" {
927  //
928  // ANSI C interface
929  //
930  // its too bad that these cant be implemented with inline functions
931  // at least when running the GNU compiler
932  //
933  LIBCOM_API int epicsStdCall epicsTimeToTime_t (time_t *pDest, const epicsTimeStamp *pSrc)
934  {
935  try {
936  time_t_wrapper dst = epicsTime (*pSrc);
937  *pDest = dst.ts;
938  }
939  catch (...) {
940  return S_time_conversion;
941  }
942  return epicsTimeOK;
943  }
944  LIBCOM_API int epicsStdCall epicsTimeFromTime_t (epicsTimeStamp *pDest, time_t src)
945  {
946  try {
947  time_t_wrapper dst;
948  dst.ts = src;
949  *pDest = epicsTime ( dst );
950  }
951  catch (...) {
952  return S_time_conversion;
953  }
954  return epicsTimeOK;
955  }
956  LIBCOM_API int epicsStdCall epicsTimeToTM (struct tm *pDest, unsigned long *pNSecDest, const epicsTimeStamp *pSrc)
957  {
958  try {
959  local_tm_nano_sec tmns = epicsTime (*pSrc);
960  *pDest = tmns.ansi_tm;
961  if (pNSecDest)
962  *pNSecDest = tmns.nSec;
963  }
964  catch (...) {
965  return S_time_conversion;
966  }
967  return epicsTimeOK;
968  }
969  LIBCOM_API int epicsStdCall epicsTimeToGMTM (struct tm *pDest, unsigned long *pNSecDest, const epicsTimeStamp *pSrc)
970  {
971  try {
972  gm_tm_nano_sec gmtmns = epicsTime (*pSrc);
973  *pDest = gmtmns.ansi_tm;
974  if (pNSecDest)
975  *pNSecDest = gmtmns.nSec;
976  }
977  catch (...) {
978  return S_time_conversion;
979  }
980  return epicsTimeOK;
981  }
982  LIBCOM_API int epicsStdCall epicsTimeFromTM (epicsTimeStamp *pDest, const struct tm *pSrc, unsigned long nSecSrc)
983  {
984  try {
985  local_tm_nano_sec tmns;
986  tmns.ansi_tm = *pSrc;
987  tmns.nSec = nSecSrc;
988  *pDest = epicsTime (tmns);
989  }
990  catch (...) {
991  return S_time_conversion;
992  }
993  return epicsTimeOK;
994  }
995  LIBCOM_API int epicsStdCall epicsTimeFromGMTM (epicsTimeStamp *pDest, const struct tm *pSrc, unsigned long nSecSrc)
996  {
997  try {
998  gm_tm_nano_sec tmns;
999  tmns.ansi_tm = *pSrc;
1000  tmns.nSec = nSecSrc;
1001  *pDest = epicsTime (tmns);
1002  }
1003  catch (...) {
1004  return S_time_conversion;
1005  }
1006  return epicsTimeOK;
1007  }
1008  LIBCOM_API int epicsStdCall epicsTimeToTimespec (struct timespec *pDest, const epicsTimeStamp *pSrc)
1009  {
1010  try {
1011  *pDest = epicsTime (*pSrc);
1012  }
1013  catch (...) {
1014  return S_time_conversion;
1015  }
1016  return epicsTimeOK;
1017  }
1018  LIBCOM_API int epicsStdCall epicsTimeFromTimespec (epicsTimeStamp *pDest, const struct timespec *pSrc)
1019  {
1020  try {
1021  *pDest = epicsTime (*pSrc);
1022  }
1023  catch (...) {
1024  return S_time_conversion;
1025  }
1026  return epicsTimeOK;
1027  }
1028  LIBCOM_API int epicsStdCall epicsTimeToTimeval (struct timeval *pDest, const epicsTimeStamp *pSrc)
1029  {
1030  try {
1031  *pDest = epicsTime (*pSrc);
1032  }
1033  catch (...) {
1034  return S_time_conversion;
1035  }
1036  return epicsTimeOK;
1037  }
1038  LIBCOM_API int epicsStdCall epicsTimeFromTimeval (epicsTimeStamp *pDest, const struct timeval *pSrc)
1039  {
1040  try {
1041  *pDest = epicsTime (*pSrc);
1042  }
1043  catch (...) {
1044  return S_time_conversion;
1045  }
1046  return epicsTimeOK;
1047  }
1048  LIBCOM_API double epicsStdCall epicsTimeDiffInSeconds (const epicsTimeStamp *pLeft, const epicsTimeStamp *pRight)
1049  {
1050  try {
1051  return epicsTime (*pLeft) - epicsTime (*pRight);
1052  }
1053  catch (...) {
1054  return - DBL_MAX;
1055  }
1056  }
1057  LIBCOM_API void epicsStdCall epicsTimeAddSeconds (epicsTimeStamp *pDest, double seconds)
1058  {
1059  try {
1060  *pDest = epicsTime (*pDest) + seconds;
1061  }
1062  catch ( ... ) {
1063  *pDest = epicsTime ();
1064  }
1065  }
1066  LIBCOM_API int epicsStdCall epicsTimeEqual (const epicsTimeStamp *pLeft, const epicsTimeStamp *pRight)
1067  {
1068  try {
1069  return epicsTime (*pLeft) == epicsTime (*pRight);
1070  }
1071  catch ( ... ) {
1072  return 0;
1073  }
1074  }
1075  LIBCOM_API int epicsStdCall epicsTimeNotEqual (const epicsTimeStamp *pLeft, const epicsTimeStamp *pRight)
1076  {
1077  try {
1078  return epicsTime (*pLeft) != epicsTime (*pRight);
1079  }
1080  catch ( ... ) {
1081  return 1;
1082  }
1083  }
1084  LIBCOM_API int epicsStdCall epicsTimeLessThan (const epicsTimeStamp *pLeft, const epicsTimeStamp *pRight)
1085  {
1086  try {
1087  return epicsTime (*pLeft) < epicsTime (*pRight);
1088  }
1089  catch ( ... ) {
1090  return 0;
1091  }
1092  }
1093  LIBCOM_API int epicsStdCall epicsTimeLessThanEqual (const epicsTimeStamp *pLeft, const epicsTimeStamp *pRight)
1094  {
1095  try {
1096  return epicsTime (*pLeft) <= epicsTime (*pRight);
1097  }
1098  catch ( ... ) {
1099  return 0;
1100  }
1101  }
1102  LIBCOM_API int epicsStdCall epicsTimeGreaterThan (const epicsTimeStamp *pLeft, const epicsTimeStamp *pRight)
1103  {
1104  try {
1105  return epicsTime (*pLeft) > epicsTime (*pRight);
1106  }
1107  catch ( ... ) {
1108  return 0;
1109  }
1110  }
1111  LIBCOM_API int epicsStdCall epicsTimeGreaterThanEqual (const epicsTimeStamp *pLeft, const epicsTimeStamp *pRight)
1112  {
1113  try {
1114  return epicsTime (*pLeft) >= epicsTime (*pRight);
1115  }
1116  catch ( ... ) {
1117  return 0;
1118  }
1119  }
1120  LIBCOM_API size_t epicsStdCall epicsTimeToStrftime (char *pBuff, size_t bufLength, const char *pFormat, const epicsTimeStamp *pTS)
1121  {
1122  try {
1123  return epicsTime(*pTS).strftime (pBuff, bufLength, pFormat);
1124  }
1125  catch ( ... ) {
1126  return 0;
1127  }
1128  }
1129  LIBCOM_API void epicsStdCall epicsTimeShow (const epicsTimeStamp *pTS, unsigned interestLevel)
1130  {
1131  try {
1132  epicsTime(*pTS).show (interestLevel);
1133  }
1134  catch ( ... ) {
1135  printf ( "Invalid epicsTimeStamp\n" );
1136  }
1137  }
1138 }
Network Time Protocol timestamp.
Definition: epicsTime.cpp:452
LIBCOM_API int epicsStdCall epicsTimeFromTimespec(epicsTimeStamp *pDest, const struct timespec *pSrc)
Set epicsTimeStamp from struct timespec
Definition: epicsTime.cpp:1018
LIBCOM_API int epicsStdCall epicsTimeLessThan(const epicsTimeStamp *pLeft, const epicsTimeStamp *pRight)
left was before right
Definition: epicsTime.cpp:1084
LIBCOM_API int epicsStdCall epicsTimeToGMTM(struct tm *pDest, unsigned long *pNSecDest, const epicsTimeStamp *pSrc)
Convert epicsTimeStamp to struct tm in UTC/GMT.
Definition: epicsTime.cpp:969
pvac::PutEvent result
Definition: clientSync.cpp:117
#define assert(exp)
Declare that a condition should be true.
Definition: epicsAssert.h:70
LIBCOM_API int epicsStdCall epicsTimeNotEqual(const epicsTimeStamp *pLeft, const epicsTimeStamp *pRight)
left not equal to right
Definition: epicsTime.cpp:1075
pvd::Status status
An EPICS-specific replacement for ANSI C&#39;s assert.
LIBCOM_API void epicsStdCall epicsTimeShow(const epicsTimeStamp *pTS, unsigned interestLevel)
Dump current state to stdout.
Definition: epicsTime.cpp:1129
LIBCOM_API int epicsStdCall epicsTimeFromTime_t(epicsTimeStamp *pDest, time_t src)
Convert ANSI C time_t to epicsTimeStamp.
Definition: epicsTime.cpp:944
Routines to get and set EPICS environment parameters.
LIBCOM_API int epicsStdCall epicsTimeToTimespec(struct timespec *pDest, const epicsTimeStamp *pSrc)
Convert epicsTimeStamp to struct timespec
Definition: epicsTime.cpp:1008
epicsUInt32 l_uf
Definition: epicsTime.cpp:454
unsigned long epicsEpochOffsetAsAnUnsignedLong
Definition: epicsTime.cpp:79
#define printf
Definition: epicsStdio.h:41
LIBCOM_API int epicsStdCall epicsTimeEqual(const epicsTimeStamp *pLeft, const epicsTimeStamp *pRight)
left equals right
Definition: epicsTime.cpp:1066
#define epicsTimeOK
Success.
Definition: epicsTime.h:339
LIBCOM_API int epicsStdCall epicsTimeFromTM(epicsTimeStamp *pDest, const struct tm *pSrc, unsigned long nSecSrc)
Set epicsTimeStamp from struct tm in local time zone.
Definition: epicsTime.cpp:982
unsigned int epicsUInt32
Definition: epicsTypes.h:43
const unsigned uSecPerSec
Definition: fdManager.cpp:35
time_t tv_sec
Definition: osdTime.h:22
epicsUInt32 secPastEpoch
seconds since 0000 Jan 1, 1990
Definition: epicsTime.h:34
LIBCOM_API int epicsStdCall epicsTimeGreaterThan(const epicsTimeStamp *pLeft, const epicsTimeStamp *pRight)
left was after right
Definition: epicsTime.cpp:1102
LIBCOM_API size_t epicsStdCall epicsTimeToStrftime(char *pBuff, size_t bufLength, const char *pFormat, const epicsTimeStamp *pTS)
Convert epicsTimeStamp to string. See epicsTime::strftime()
Definition: epicsTime.cpp:1120
LIBCOM_API int epicsStdCall epicsTimeToTime_t(time_t *pDest, const epicsTimeStamp *pSrc)
Convert epicsTimeStamp to ANSI C time_t.
Definition: epicsTime.cpp:933
long tv_nsec
Definition: osdTime.h:23
struct epicsTimeStamp epicsTimeStamp
EPICS time stamp, for use from C code.
int epicsTimeGetMonotonic(epicsTimeStamp *pDest)
Get monotonic time into *pDest.
LIBCOM_API int epicsStdCall epicsTime_localtime(const time_t *clock, struct tm *result)
Break down a time_t into a struct tm in the local timezone.
Definition: osdTime.cpp:61
LIBCOM_API int epicsStdCall epicsTimeGreaterThanEqual(const epicsTimeStamp *pLeft, const epicsTimeStamp *pRight)
right was not before left
Definition: epicsTime.cpp:1111
LIBCOM_API void epicsStdCall epicsTimeAddSeconds(epicsTimeStamp *pDest, double seconds)
Add some number of seconds to dest.
Definition: epicsTime.cpp:1057
epicsUInt32 l_ui
Definition: epicsTime.cpp:453
bool operator<(shared_ptr< T > const &a, shared_ptr< U > const &b) BOOST_NOEXCEPT
Definition: shared_ptr.hpp:778
LIBCOM_API int epicsStdCall epicsTimeToTimeval(struct timeval *pDest, const epicsTimeStamp *pSrc)
Convert epicsTimeStamp to struct timeval
Definition: epicsTime.cpp:1028
int epicsStdCall epicsTimeGetCurrent(epicsTimeStamp *pDest)
Get current time into *pDest.
LIBCOM_API int epicsStdCall epicsTime_gmtime(const time_t *clock, struct tm *result)
Break down a time_t into a struct tm in the UTC timezone.
Definition: osdTime.cpp:55
BSD and SRV5 Unix timestamp.
Definition: epicsTime.h:52
#define POSIX_TIME_AT_EPICS_EPOCH
The EPICS Epoch is 00:00:00 Jan 1, 1990 UTC.
Definition: epicsTime.h:26
LIBCOM_API int epicsStdCall epicsTimeFromTimeval(epicsTimeStamp *pDest, const struct timeval *pSrc)
Set epicsTimeStamp from struct timeval
Definition: epicsTime.cpp:1038
LIBCOM_API int epicsStdCall epicsTimeLessThanEqual(const epicsTimeStamp *pLeft, const epicsTimeStamp *pRight)
right was no later than left
Definition: epicsTime.cpp:1093
EPICS time stamp, for use from C code.
Definition: epicsTime.h:33
LIBCOM_API int epicsStdCall epicsTimeFromGMTM(epicsTimeStamp *pDest, const struct tm *pSrc, unsigned long nSecSrc)
Set epicsTimeStamp from struct tm in UTC/GMT.
Definition: epicsTime.cpp:995
int epicsStdCall epicsTimeGetEvent(epicsTimeStamp *pDest, int eventNumber)
Get time of event eventNumber into *pDest.
#define S_time_conversion
Time conversion error.
Definition: epicsTime.h:353
Defined by POSIX Real Time.
Definition: osdTime.h:21
LIBCOM_API double epicsStdCall epicsTimeDiffInSeconds(const epicsTimeStamp *pLeft, const epicsTimeStamp *pRight)
Time difference between left and right in seconds.
Definition: epicsTime.cpp:1048
EPICS time-stamps (epicsTimeStamp), epicsTime C++ class and C functions for handling wall-clock times...
const unsigned mSecPerSec
Definition: fdManager.cpp:34
#define throwWithLocation(parm)
LIBCOM_API int epicsStdCall epicsSnprintf(char *str, size_t size, const char *format,...) EPICS_PRINTF_STYLE(3
epicsUInt32 nsec
nanoseconds within second
Definition: epicsTime.h:35
LIBCOM_API int epicsStdCall epicsTimeToTM(struct tm *pDest, unsigned long *pNSecDest, const epicsTimeStamp *pSrc)
Convert epicsTimeStamp to struct tm in local time zone.
Definition: epicsTime.cpp:956