33 #include "epicsVersion.h" 39 static const char pEpicsTimeVersion[] =
40 "@(#) " EPICS_VERSION_STRING
", Common Utilities Library";
46 static const unsigned uSecPerMSec = 1000u;
48 static const unsigned nSecPerUSec = 1000u;
49 static const unsigned nSecPerSec = nSecPerUSec *
uSecPerSec;
50 static const unsigned nSecFracDigits = 9u;
55 static const unsigned long NTP_TIME_AT_POSIX_EPOCH = 2208988800ul;
56 static const unsigned long NTP_TIME_AT_EPICS_EPOCH =
62 inline epicsTime::epicsTime (
const unsigned long secIn,
const unsigned long nSecIn) :
63 secPastEpoch ( secIn ), nSec ( nSecIn )
65 if (nSecIn >= nSecPerSec) {
66 this->secPastEpoch += nSecIn / nSecPerSec;
67 this->nSec = nSecIn % nSecPerSec;
89 time_t t_zero =
static_cast<time_t
> (0);
90 time_t t_one =
static_cast<time_t
> (1);
123 void epicsTime :: addNanoSec (
long nSecAdj )
128 if (static_cast<unsigned long>(nSecAdj) >= nSecPerSec) {
129 this->secPastEpoch += nSecAdj / nSecPerSec;
130 nSecAdj %= nSecPerSec;
133 this->nSec += nSecAdj;
134 if (this->nSec >= nSecPerSec) {
135 this->secPastEpoch++;
136 this->nSec -= nSecPerSec;
143 epicsTime::epicsTime (
const time_t_wrapper & ansiTimeTicks )
155 if ( ansiTimeTicks.ts > 0 && ansiTimeTicks.ts <= LONG_MAX ) {
156 unsigned long ticks = static_cast <
unsigned long > ( ansiTimeTicks.ts );
177 static double uLongMax =
static_cast<double> (ULONG_MAX);
179 if ( sec < -uLongMax ) {
180 sec = sec +
static_cast<unsigned long> ( -sec / uLongMax ) * uLongMax;
184 else if ( sec > uLongMax ) {
185 sec = sec -
static_cast<unsigned long> ( sec / uLongMax ) * uLongMax;
188 this->secPastEpoch = static_cast <
unsigned long> ( sec );
189 this->nSec = static_cast <
unsigned long> ( ( sec-this->secPastEpoch ) * nSecPerSec );
194 if ( ts.
nsec < nSecPerSec ) {
196 this->nSec = ts.
nsec;
199 throw std::logic_error (
200 "epicsTimeStamp has overflow in nano-seconds field" );
204 epicsTime::epicsTime () :
205 secPastEpoch(0u), nSec(0u) {}
207 epicsTime epicsTime::getCurrent ()
214 return epicsTime ( current );
217 epicsTime epicsTime::getMonotonic()
221 return epicsTime ( current );
224 epicsTime epicsTime::getEvent (
const epicsTimeEvent &event)
231 return epicsTime ( current );
237 epicsTime::operator time_t_wrapper ()
const 256 wrap.ts = static_cast <time_t> ( tmp );
264 epicsTime::operator local_tm_nano_sec ()
const 266 time_t_wrapper ansiTimeTicks = *
this;
268 local_tm_nano_sec tm;
272 throw std::logic_error (
"epicsTime_localtime failed" );
275 tm.nSec = this->nSec;
283 epicsTime::operator gm_tm_nano_sec ()
const 285 time_t_wrapper ansiTimeTicks = *
this;
291 throw std::logic_error (
"epicsTime_gmtime failed" );
294 tm.nSec = this->nSec;
302 epicsTime::epicsTime (
const local_tm_nano_sec &tm)
304 struct tm tmp = tm.ansi_tm;
305 time_t_wrapper ansiTimeTicks = { mktime (&tmp) };
307 static const time_t mktimeError = static_cast <time_t> (-1);
308 if (ansiTimeTicks.ts == mktimeError) {
312 *
this = epicsTime(ansiTimeTicks);
313 this->addNanoSec(tm.nSec);
321 static inline int is_leap(
int year)
332 static inline int days_from_0(
int year)
335 return 365 * year + (year / 400) - (year / 100) + (year / 4);
338 static inline int days_from_1970(
int year)
340 static const int days_from_0_to_1970 = days_from_0(1970);
341 return days_from_0(year) - days_from_0_to_1970;
344 static inline int days_from_1jan(
int year,
int month,
int day)
346 static const int days[2][12] =
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}
351 return days[is_leap(year)][month-1] + day - 1;
354 epicsTime::epicsTime (
const gm_tm_nano_sec &tm)
356 int year = tm.ansi_tm.tm_year + 1900;
357 int month = tm.ansi_tm.tm_mon;
361 }
else if (month < 0) {
362 int years_diff = (-month + 11) / 12;
364 month += 12 * years_diff;
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;
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;
378 *
this = epicsTime(ansiTimeTicks);
379 this->addNanoSec(tm.nSec);
385 epicsTime::operator
struct timespec () const
388 time_t_wrapper ansiTimeTicks;
390 ansiTimeTicks = *
this;
391 ts.
tv_sec = ansiTimeTicks.ts;
392 ts.
tv_nsec =
static_cast<long> (this->nSec);
399 epicsTime::epicsTime (
const struct timespec &ts)
401 time_t_wrapper ansiTimeTicks;
403 ansiTimeTicks.ts = ts.
tv_sec;
404 *
this = epicsTime (ansiTimeTicks);
411 epicsTime::operator
struct timeval () const
414 time_t_wrapper ansiTimeTicks;
416 ansiTimeTicks = *
this;
425 ts.tv_sec = ansiTimeTicks.ts;
426 ts.tv_usec = static_cast <
long > ( this->nSec / nSecPerUSec );
433 epicsTime::epicsTime (
const struct timeval &ts)
435 time_t_wrapper ansiTimeTicks;
444 ansiTimeTicks.ts = ts.tv_sec;
445 *
this = epicsTime (ansiTimeTicks);
446 this->addNanoSec (ts.tv_usec * nSecPerUSec);
450 static const double NTP_FRACTION_DENOMINATOR = 1.0 + 0xffffffff;
460 epicsTime::operator
l_fp ()
const 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 );
472 epicsTime::epicsTime (
const l_fp & ts )
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 );
481 if ( this->nSec >= nSecPerSec ) {
482 throw std::logic_error (
483 "epicsTimeStamp has overflow in nano-seconds field?" );
516 static const char * fracFormatFind (
517 const char *
const pFormat,
518 char *
const pPrefixBuf,
519 const size_t prefixBufLen,
521 unsigned long & fracFmtWidth )
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] ==
'%' ) {
533 else if ( pFmt[1] ==
'f' ) {
541 unsigned long result = strtoul ( pFmt + 1, & pAfterTmp, 10 );
542 if ( errno == 0 && *pAfterTmp ==
'f' && result > 0 ) {
545 pAfter = pAfterTmp + 1;
553 size_t len = pFmt - pFormat;
554 if ( len < prefixBufLen ) {
555 strncpy ( pPrefixBuf, pFormat, len );
556 pPrefixBuf [ len ] =
'\0';
559 fracFmtWidth = width;
562 fracFmtFound =
false;
566 strncpy ( pPrefixBuf,
"<invalid format>", prefixBufLen - 1 );
567 pPrefixBuf [ prefixBufLen - 1 ] =
'\0';
568 fracFmtFound =
false;
578 size_t epicsTime::strftime (
579 char * pBuff,
size_t bufLength,
const char * pFormat )
const 581 if ( bufLength == 0u ) {
586 if ( this->secPastEpoch == 0 && this->nSec == 0u ) {
587 strncpy ( pBuff,
"<undefined>", bufLength );
588 pBuff[bufLength-1] =
'\0';
589 return strlen ( pBuff );
592 char * pBufCur = pBuff;
593 const char * pFmt = pFormat;
594 size_t bufLenLeft = bufLength;
595 while ( *pFmt !=
'\0' && bufLenLeft > 1 ) {
597 char strftimePrefixBuf [256];
599 unsigned long fracWid = 0;
600 pFmt = fracFormatFind (
602 strftimePrefixBuf,
sizeof ( strftimePrefixBuf ),
603 fracFmtFound, fracWid );
606 if ( ! ( strftimePrefixBuf[0] !=
'\0' || fracFmtFound ) ) {
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;
620 if ( fracFmtFound && bufLenLeft > 1 ) {
621 if ( fracWid > nSecFracDigits ) {
622 fracWid = nSecFracDigits;
625 if ( fracWid < bufLenLeft )
627 local_tm_nano_sec tmns = *
this;
628 if ( tmns.nSec < nSecPerSec ) {
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 )
643 unsigned long frac = tmns.nSec + div[fracWid] / 2;
644 if (frac >= nSecPerSec)
645 frac = nSecPerSec - 1;
647 frac /= div[fracWid];
649 sprintf ( fracFormat,
"%%0%lulu", fracWid );
652 unsigned long nChar = static_cast <
unsigned long > (
status );
653 if ( nChar >= bufLenLeft ) {
654 nChar = bufLenLeft - 1;
656 pBufCur[nChar] =
'\0';
662 static const char pOVF [] =
"OVF";
663 size_t tmpLen =
sizeof ( pOVF ) - 1;
664 if ( tmpLen >= bufLenLeft ) {
665 tmpLen = bufLenLeft - 1;
667 strncpy ( pBufCur, pOVF, tmpLen );
668 pBufCur[tmpLen] =
'\0';
670 bufLenLeft -= tmpLen;
674 static const char pDoesntFit [] =
"************";
675 size_t tmpLen =
sizeof ( pDoesntFit ) - 1;
676 if ( tmpLen >= bufLenLeft ) {
677 tmpLen = bufLenLeft - 1;
679 strncpy ( pBufCur, pDoesntFit, tmpLen );
680 pBufCur[tmpLen] =
'\0';
682 bufLenLeft -= tmpLen;
687 return pBufCur - pBuff;
693 void epicsTime::show (
unsigned level )
const 697 size_t numChar = this->strftime ( bigBuffer,
sizeof ( bigBuffer ),
698 "%a %b %d %Y %H:%M:%S.%09f" );
700 printf (
"epicsTime: %s\n", bigBuffer );
706 printf (
"epicsTime: revision \"%s\"\n",
717 epicsTime epicsTime::operator + (
const double &rhs)
const 719 unsigned long newSec, newNSec, secOffset, nSecOffset;
723 secOffset = static_cast <
unsigned long> (rhs);
724 fnsec = rhs - secOffset;
725 nSecOffset = static_cast <
unsigned long> ( (fnsec * nSecPerSec) + 0.5 );
727 newSec = this->secPastEpoch + secOffset;
728 newNSec = this->nSec + nSecOffset;
729 if (newNSec >= nSecPerSec) {
731 newNSec -= nSecPerSec;
735 secOffset = static_cast <
unsigned long> (-rhs);
736 fnsec = rhs + secOffset;
737 nSecOffset = static_cast <
unsigned long> ( (-fnsec * nSecPerSec) + 0.5 );
739 newSec = this->secPastEpoch - secOffset;
740 if (this->nSec>=nSecOffset) {
741 newNSec = this->nSec - nSecOffset;
746 newNSec = this->nSec + (nSecPerSec - nSecOffset);
749 return epicsTime (newSec, newNSec);
767 double epicsTime::operator - (
const epicsTime &rhs)
const 769 double nSecRes, secRes;
777 if (this->nSec>=rhs.nSec) {
778 nSecRes = this->nSec - rhs.nSec;
781 nSecRes = rhs.nSec - this->nSec;
790 if (this->secPastEpoch<rhs.secPastEpoch) {
791 secRes = rhs.secPastEpoch - this->secPastEpoch;
792 if (secRes > ULONG_MAX/2) {
798 secRes = 1 + (ULONG_MAX-secRes);
806 secRes = this->secPastEpoch - rhs.secPastEpoch;
807 if (secRes > ULONG_MAX/2) {
813 secRes = 1 + (ULONG_MAX-secRes);
819 return secRes + nSecRes/nSecPerSec;
825 bool epicsTime::operator <= (
const epicsTime &rhs)
const 829 if (this->secPastEpoch<rhs.secPastEpoch) {
830 if (rhs.secPastEpoch-this->secPastEpoch < ULONG_MAX/2) {
846 else if (this->secPastEpoch>rhs.secPastEpoch) {
847 if (this->secPastEpoch-rhs.secPastEpoch < ULONG_MAX/2) {
864 if (this->nSec<=rhs.nSec) {
881 if (this->secPastEpoch<rhs.secPastEpoch) {
882 if (rhs.secPastEpoch-this->secPastEpoch < ULONG_MAX/2) {
898 else if (this->secPastEpoch>rhs.secPastEpoch) {
899 if (this->secPastEpoch-rhs.secPastEpoch < ULONG_MAX/2) {
916 if (this->nSec<rhs.nSec) {
936 time_t_wrapper dst = epicsTime (*pSrc);
949 *pDest = epicsTime ( dst );
959 local_tm_nano_sec tmns = epicsTime (*pSrc);
960 *pDest = tmns.ansi_tm;
962 *pNSecDest = tmns.nSec;
972 gm_tm_nano_sec gmtmns = epicsTime (*pSrc);
973 *pDest = gmtmns.ansi_tm;
975 *pNSecDest = gmtmns.nSec;
985 local_tm_nano_sec tmns;
986 tmns.ansi_tm = *pSrc;
988 *pDest = epicsTime (tmns);
999 tmns.ansi_tm = *pSrc;
1000 tmns.nSec = nSecSrc;
1001 *pDest = epicsTime (tmns);
1011 *pDest = epicsTime (*pSrc);
1021 *pDest = epicsTime (*pSrc);
1031 *pDest = epicsTime (*pSrc);
1041 *pDest = epicsTime (*pSrc);
1051 return epicsTime (*pLeft) - epicsTime (*pRight);
1060 *pDest = epicsTime (*pDest) + seconds;
1063 *pDest = epicsTime ();
1069 return epicsTime (*pLeft) == epicsTime (*pRight);
1078 return epicsTime (*pLeft) != epicsTime (*pRight);
1087 return epicsTime (*pLeft) < epicsTime (*pRight);
1096 return epicsTime (*pLeft) <= epicsTime (*pRight);
1105 return epicsTime (*pLeft) > epicsTime (*pRight);
1114 return epicsTime (*pLeft) >= epicsTime (*pRight);
1123 return epicsTime(*pTS).strftime (pBuff, bufLength, pFormat);
1132 epicsTime(*pTS).show (interestLevel);
1135 printf (
"Invalid epicsTimeStamp\n" );
Network Time Protocol timestamp.
LIBCOM_API int epicsStdCall epicsTimeFromTimespec(epicsTimeStamp *pDest, const struct timespec *pSrc)
Set epicsTimeStamp from struct timespec
LIBCOM_API int epicsStdCall epicsTimeLessThan(const epicsTimeStamp *pLeft, const epicsTimeStamp *pRight)
left was before right
LIBCOM_API int epicsStdCall epicsTimeToGMTM(struct tm *pDest, unsigned long *pNSecDest, const epicsTimeStamp *pSrc)
Convert epicsTimeStamp to struct tm in UTC/GMT.
#define assert(exp)
Declare that a condition should be true.
LIBCOM_API int epicsStdCall epicsTimeNotEqual(const epicsTimeStamp *pLeft, const epicsTimeStamp *pRight)
left not equal to right
An EPICS-specific replacement for ANSI C's assert.
LIBCOM_API void epicsStdCall epicsTimeShow(const epicsTimeStamp *pTS, unsigned interestLevel)
Dump current state to stdout.
LIBCOM_API int epicsStdCall epicsTimeFromTime_t(epicsTimeStamp *pDest, time_t src)
Convert ANSI C time_t to epicsTimeStamp.
Routines to get and set EPICS environment parameters.
LIBCOM_API int epicsStdCall epicsTimeToTimespec(struct timespec *pDest, const epicsTimeStamp *pSrc)
Convert epicsTimeStamp to struct timespec
unsigned long epicsEpochOffsetAsAnUnsignedLong
LIBCOM_API int epicsStdCall epicsTimeEqual(const epicsTimeStamp *pLeft, const epicsTimeStamp *pRight)
left equals right
#define epicsTimeOK
Success.
LIBCOM_API int epicsStdCall epicsTimeFromTM(epicsTimeStamp *pDest, const struct tm *pSrc, unsigned long nSecSrc)
Set epicsTimeStamp from struct tm in local time zone.
const unsigned uSecPerSec
epicsUInt32 secPastEpoch
seconds since 0000 Jan 1, 1990
LIBCOM_API int epicsStdCall epicsTimeGreaterThan(const epicsTimeStamp *pLeft, const epicsTimeStamp *pRight)
left was after right
bool useDiffTimeOptimization
LIBCOM_API size_t epicsStdCall epicsTimeToStrftime(char *pBuff, size_t bufLength, const char *pFormat, const epicsTimeStamp *pTS)
Convert epicsTimeStamp to string. See epicsTime::strftime()
LIBCOM_API int epicsStdCall epicsTimeToTime_t(time_t *pDest, const epicsTimeStamp *pSrc)
Convert epicsTimeStamp to ANSI C time_t.
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.
LIBCOM_API int epicsStdCall epicsTimeGreaterThanEqual(const epicsTimeStamp *pLeft, const epicsTimeStamp *pRight)
right was not before left
LIBCOM_API void epicsStdCall epicsTimeAddSeconds(epicsTimeStamp *pDest, double seconds)
Add some number of seconds to dest.
bool operator<(shared_ptr< T > const &a, shared_ptr< U > const &b) BOOST_NOEXCEPT
LIBCOM_API int epicsStdCall epicsTimeToTimeval(struct timeval *pDest, const epicsTimeStamp *pSrc)
Convert epicsTimeStamp to struct timeval
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.
BSD and SRV5 Unix timestamp.
#define POSIX_TIME_AT_EPICS_EPOCH
The EPICS Epoch is 00:00:00 Jan 1, 1990 UTC.
LIBCOM_API int epicsStdCall epicsTimeFromTimeval(epicsTimeStamp *pDest, const struct timeval *pSrc)
Set epicsTimeStamp from struct timeval
LIBCOM_API int epicsStdCall epicsTimeLessThanEqual(const epicsTimeStamp *pLeft, const epicsTimeStamp *pRight)
right was no later than left
EPICS time stamp, for use from C code.
LIBCOM_API int epicsStdCall epicsTimeFromGMTM(epicsTimeStamp *pDest, const struct tm *pSrc, unsigned long nSecSrc)
Set epicsTimeStamp from struct tm in UTC/GMT.
int epicsStdCall epicsTimeGetEvent(epicsTimeStamp *pDest, int eventNumber)
Get time of event eventNumber into *pDest.
#define S_time_conversion
Time conversion error.
Defined by POSIX Real Time.
LIBCOM_API double epicsStdCall epicsTimeDiffInSeconds(const epicsTimeStamp *pLeft, const epicsTimeStamp *pRight)
Time difference between left and right in seconds.
EPICS time-stamps (epicsTimeStamp), epicsTime C++ class and C functions for handling wall-clock times...
const unsigned mSecPerSec
#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
LIBCOM_API int epicsStdCall epicsTimeToTM(struct tm *pDest, unsigned long *pNSecDest, const epicsTimeStamp *pSrc)
Convert epicsTimeStamp to struct tm in local time zone.