From 370240117101e85d7728cb48b947efadf278192c Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Tue, 4 Oct 2016 16:16:42 +0200 Subject: [PATCH 1/2] libCom/osi: add full epicsTime conversion from/to UTC struct tm (without timezone mechanism) --- src/libCom/osi/epicsTime.cpp | 89 ++++++++++++++++++++++++++++++++++-- src/libCom/osi/epicsTime.h | 13 +++++- 2 files changed, 96 insertions(+), 6 deletions(-) diff --git a/src/libCom/osi/epicsTime.cpp b/src/libCom/osi/epicsTime.cpp index 414bd5d4f..474515170 100644 --- a/src/libCom/osi/epicsTime.cpp +++ b/src/libCom/osi/epicsTime.cpp @@ -287,11 +287,80 @@ epicsTime::epicsTime (const local_tm_nano_sec &tm) throwWithLocation ( formatProblemWithStructTM () ); } + // Do the epoch conversion *this = epicsTime (ansiTimeTicks); + // Add the nSec part + *this = epicsTime (this->secPastEpoch, tm.nSec); +} - unsigned long nSecAdj = tm.nSec % nSecPerSec; - unsigned long secAdj = tm.nSec / nSecPerSec; - *this = epicsTime ( this->secPastEpoch+secAdj, this->nSec+nSecAdj ); +// +// epicsTime (const gm_tm_nano_sec &tm) +// + +// do conversion avoiding the timezone mechanism +static inline epicsInt32 is_leap(epicsInt32 year) +{ + if (year % 400 == 0) + return 1; + if (year % 100 == 0) + return 0; + if (year % 4 == 0) + return 1; + return 0; +} + +static inline epicsInt32 days_from_0(epicsInt32 year) +{ + year--; + return 365 * year + (year / 400) - (year / 100) + (year / 4); +} + +static inline epicsInt32 days_from_1970(epicsInt32 year) +{ + static const int days_from_0_to_1970 = days_from_0(1970); + return days_from_0(year) - days_from_0_to_1970; +} + +static inline epicsInt32 days_from_1jan(epicsInt32 year, + epicsInt32 month, + epicsInt32 day) +{ + static const epicsInt32 days[2][12] = + { + { 0,31,59,90,120,151,181,212,243,273,304,334}, + { 0,31,60,91,121,152,182,213,244,274,305,335} + }; + return days[is_leap(year)][month-1] + day - 1; +} + +epicsTime::epicsTime (const gm_tm_nano_sec &tm) +{ + time_t_wrapper ansiTimeTicks; + int year = tm.ansi_tm.tm_year + 1900; + int month = tm.ansi_tm.tm_mon; + if (month > 11) { + year += month / 12; + month %= 12; + } else if (month < 0) { + int years_diff = (-month + 11) / 12; + year -= years_diff; + month += 12 * years_diff; + } + month++; + int day = tm.ansi_tm.tm_mday; + int day_of_year = days_from_1jan(year, month, day); + int days_since_epoch = days_from_1970(year) + day_of_year; + + const time_t seconds_in_day = 3600 * 24; + ansiTimeTicks.ts = seconds_in_day * days_since_epoch + + 3600 * tm.ansi_tm.tm_hour + + 60 * tm.ansi_tm.tm_min + + tm.ansi_tm.tm_sec; + + // Do the epoch conversion + *this = epicsTime (ansiTimeTicks); + // Add the nSec part + *this = epicsTime (this->secPastEpoch, tm.nSec); } // @@ -905,6 +974,19 @@ extern "C" { } return epicsTimeOK; } + epicsShareFunc int epicsShareAPI epicsTimeFromGMTM (epicsTimeStamp *pDest, const struct tm *pSrc, unsigned long nSecSrc) + { + try { + gm_tm_nano_sec tmns; + tmns.ansi_tm = *pSrc; + tmns.nSec = nSecSrc; + *pDest = epicsTime (tmns); + } + catch (...) { + return epicsTimeERROR; + } + return epicsTimeOK; + } epicsShareFunc int epicsShareAPI epicsTimeToTimespec (struct timespec *pDest, const epicsTimeStamp *pSrc) { try { @@ -1036,4 +1118,3 @@ extern "C" { } } } - diff --git a/src/libCom/osi/epicsTime.h b/src/libCom/osi/epicsTime.h index a36d6afe3..1cb3733bc 100644 --- a/src/libCom/osi/epicsTime.h +++ b/src/libCom/osi/epicsTime.h @@ -105,10 +105,12 @@ public: epicsTime & operator = ( const local_tm_nano_sec & ); /* - * convert to ANSI Cs "struct tm" (with nano seconds) + * convert to and from ANSI Cs "struct tm" (with nano seconds) * adjusted for GM time (UTC) */ operator gm_tm_nano_sec () const; + epicsTime ( const gm_tm_nano_sec & ); + epicsTime & operator = ( const gm_tm_nano_sec & ); /* convert to and from POSIX RTs "struct timespec" */ operator struct timespec () const; @@ -194,13 +196,15 @@ epicsShareFunc int epicsShareAPI epicsTimeToTime_t ( epicsShareFunc int epicsShareAPI epicsTimeFromTime_t ( epicsTimeStamp * pDest, time_t src ); -/*convert to and from ANSI C's "struct tm" with nano seconds */ +/* convert to and from ANSI C's "struct tm" with nano seconds */ epicsShareFunc int epicsShareAPI epicsTimeToTM ( struct tm * pDest, unsigned long * pNSecDest, const epicsTimeStamp * pSrc ); epicsShareFunc int epicsShareAPI epicsTimeToGMTM ( struct tm * pDest, unsigned long * pNSecDest, const epicsTimeStamp * pSrc ); epicsShareFunc int epicsShareAPI epicsTimeFromTM ( epicsTimeStamp * pDest, const struct tm * pSrc, unsigned long nSecSrc ); +epicsShareFunc int epicsShareAPI epicsTimeFromGMTM ( + epicsTimeStamp * pDest, const struct tm * pSrc, unsigned long nSecSrc ); /* convert to and from POSIX RT's "struct timespec" */ epicsShareFunc int epicsShareAPI epicsTimeToTimespec ( @@ -312,6 +316,11 @@ inline epicsTime & epicsTime::operator = ( const local_tm_nano_sec & rhs ) return *this = epicsTime ( rhs ); } +inline epicsTime & epicsTime::operator = ( const gm_tm_nano_sec & rhs ) +{ + return *this = epicsTime ( rhs ); +} + inline epicsTime & epicsTime::operator = ( const struct timespec & rhs ) { *this = epicsTime ( rhs ); From 67323441ec002b7088f662015b50c7eea1a507c7 Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Tue, 4 Oct 2016 16:17:45 +0200 Subject: [PATCH 2/2] libCom/test: add roundtrip test for epicsTime from/to UTC struct tm conversion --- src/libCom/test/epicsTimeTest.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/libCom/test/epicsTimeTest.cpp b/src/libCom/test/epicsTimeTest.cpp index 83d0a8a07..823f57b6f 100644 --- a/src/libCom/test/epicsTimeTest.cpp +++ b/src/libCom/test/epicsTimeTest.cpp @@ -48,7 +48,7 @@ MAIN(epicsTimeTest) const int wasteTime = 100000; const int nTimes = 10; - testPlan(15 + nTimes * 18); + testPlan(15 + nTimes * 19); try { const epicsTimeStamp epochTS = {0, 0}; @@ -205,6 +205,11 @@ MAIN(epicsTimeTest) epicsTime beginANSI = ansiDate; testOk1(beginANSI + diff == now); + // test struct gmtm round-trip conversion + gm_tm_nano_sec ansiGmDate = begin; + epicsTime beginGMANSI = ansiGmDate; + testOk1(beginGMANSI + diff == now); + // test struct timespec round-trip conversion struct timespec ts = begin; epicsTime beginTS = ts;