EPICS Controls Argonne National Laboratory

Experimental Physics and
Industrial Control System

2002  2003  2004  2005  2006  2007  <20082009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024  Index 2002  2003  2004  2005  2006  2007  <20082009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
<== Date ==> <== Thread ==>

Subject: Re: Problems within epicsTime.cpp
From: Andrew Johnson <[email protected]>
To: Kay-Uwe Kasemir <[email protected]>
Cc: [email protected]
Date: Thu, 31 Jan 2008 08:44:26 -0600
> On Jan 31, 2008, at 05:22 , Denison, PN (Peter) asked:
>>
>> Can I replace this code in epicsTimeLoadTimeInit with a constant?

Kay-Uwe Kasemir wrote:

Yes, make it a constant.

No, don't. Apply the attached patch instead, which is a diff between R3.14.9 and the current head of the R3.14 branch and should work in all timezones.

The Posix spec apparently does not require that a time_t be expressed in seconds, although Unix historically has used that. The existing (broken) code does not make that assumption, and neither does my patched version (which I did tell Peter about several months ago), but a using constant probably does.

- Andrew
--
When a distinguished but elderly scientist states that something is
possible, he is almost certainly right.  When he states that something
is impossible, he is very probably wrong.  -- Arthur C. Clarke
Index: epicsTime.cpp
===================================================================
RCS file: /net/phoebus/epicsmgr/cvsroot/epics/base/src/libCom/osi/epicsTime.cpp,v
retrieving revision 1.25.2.15
retrieving revision 1.25.2.18
diff -u -b -r1.25.2.15 -r1.25.2.18
--- epicsTime.cpp	2 Jan 2007 19:37:57 -0000	1.25.2.15
+++ epicsTime.cpp	13 Nov 2007 22:54:20 -0000	1.25.2.18
@@ -1,10 +1,9 @@
 /*************************************************************************\
-* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
+* Copyright (c) 2007 UChicago Argonne LLC, as Operator of Argonne
 *     National Laboratory.
 * Copyright (c) 2002 The Regents of the University of California, as
 *     Operator of Los Alamos National Laboratory.
-* EPICS BASE Versions 3.13.7
-* and higher are distributed subject to a Software License Agreement found
+* EPICS BASE is distributed subject to a Software License Agreement found
 * in file LICENSE that is included with this distribution. 
 \*************************************************************************/
 /* epicsTime.cpp */
@@ -44,17 +43,19 @@
 // useful public constants
 //
 static const unsigned mSecPerSec = 1000u;
-static const unsigned uSecPerSec = 1000u * mSecPerSec;
-static const unsigned nSecPerSec = 1000u * uSecPerSec;
+static const unsigned uSecPerMSec = 1000u;
+static const unsigned uSecPerSec = uSecPerMSec * mSecPerSec;
 static const unsigned nSecPerUSec = 1000u;
-static const unsigned secPerMin = 60u;
+static const unsigned nSecPerSec = nSecPerUSec * uSecPerSec;
 static const unsigned nSecFracDigits = 9u;
 
-static const unsigned tmStructEpochYear = 1900;
-
+static const unsigned tmEpochYear = 1900;
+static const unsigned ansiEpochYear = 1970;
 static const unsigned epicsEpochYear = 1990;
-static const unsigned epicsEpocMonth = 0; // January
-static const unsigned epicsEpocDayOfTheMonth = 1; // the 1st day of the month
+
+static const unsigned epochMonth = 0;           // January
+static const unsigned epochDayOfTheMonth = 1;   // the 1st
+
 
 //
 // epicsTime (const unsigned long secIn, const unsigned long nSecIn)
@@ -81,53 +82,47 @@
 //
 epicsTimeLoadTimeInit::epicsTimeLoadTimeInit ()
 {
-    static const time_t ansiEpoch = 0;
-    double secWest;
-
-    {
-        time_t current = time ( NULL );
-        time_t error;
-        struct tm date; // vxWorks 6.0 requires "struct" here 
-
-        int status = epicsTime_gmtime ( &current, &date );
-        assert ( status == epicsTimeOK );
-        error = mktime ( &date );
-        assert ( error != (time_t) - 1 );
-        secWest =  difftime ( error, current );
-    }
-    
-    {
-        time_t first = static_cast<time_t> (0);
-        time_t last = static_cast<time_t> (1);
-        this->time_tSecPerTick = difftime (last, first);
-    }
-
-    {
-        struct tm tmEpicsEpoch;
-        time_t epicsEpoch;
-
-        tmEpicsEpoch.tm_sec = 0;
-        tmEpicsEpoch.tm_min = 0;
-        tmEpicsEpoch.tm_hour = 0;
-        tmEpicsEpoch.tm_mday = epicsEpocDayOfTheMonth;
-        tmEpicsEpoch.tm_mon = epicsEpocMonth;
-        tmEpicsEpoch.tm_year = epicsEpochYear - tmStructEpochYear;
-        // must not correct for DST because secWest does 
-        // not include a DST offset
-        tmEpicsEpoch.tm_isdst = 0; 
-
-        epicsEpoch = mktime (&tmEpicsEpoch);
-        assert (epicsEpoch!=(time_t)-1);
-        this->epicsEpochOffset = difftime ( epicsEpoch, ansiEpoch ) - secWest;
-    }
-
-    if ( this->time_tSecPerTick == 1.0 && this->epicsEpochOffset <= ULONG_MAX &&
-           this->epicsEpochOffset >= 0 ) {
+    // All we know about time_t is that it is an arithmetic type.
+    time_t t_zero = static_cast<time_t> (0);
+    time_t t_one  = static_cast<time_t> (1);
+    this->time_tSecPerTick = difftime (t_one, t_zero);
+
+    /* We calculate the difference in seconds between the ANSI and EPICS
+     * epochs (1970-1-1, 1990-1-1).  However mktime() takes a local time
+     * and adds a timezone-specified Daylight Savings Time offset to the
+     * result it returns.  Luckily we only need the time difference in
+     * seconds between the two epochs, so the two DST corrections cancel
+     * each other out.  We offset the local time used by 12 hours so the
+     * ANSI result can never go negative whatever timezone we're in.
+     */
+
+    struct tm tmEpoch;
+    tmEpoch.tm_sec = 0;
+    tmEpoch.tm_min = 0;
+    tmEpoch.tm_hour = 12;
+    tmEpoch.tm_mday = epochDayOfTheMonth;
+    tmEpoch.tm_mon = epochMonth;
+    tmEpoch.tm_isdst = 0;
+
+    tmEpoch.tm_year = ansiEpochYear - tmEpochYear;
+    time_t ansiEpoch = mktime(&tmEpoch);
+    assert(ansiEpoch != (time_t) -1);
+
+    tmEpoch.tm_year = epicsEpochYear - tmEpochYear;
+    time_t epicsEpoch = mktime(&tmEpoch);
+    assert(epicsEpoch != (time_t) -1);
+
+    this->epicsEpochOffset = difftime (epicsEpoch, ansiEpoch);
+
+    if (this->time_tSecPerTick == 1.0 &&
+        this->epicsEpochOffset <= ULONG_MAX &&
+        this->epicsEpochOffset >= 0) {
+        // We can use simpler code on Posix-compliant systems
         this->useDiffTimeOptimization = true;
         this->epicsEpochOffsetAsAnUnsignedLong = 
-            static_cast < unsigned long > ( this->epicsEpochOffset );
-    }
-    else {
+            static_cast<unsigned long>(this->epicsEpochOffset);
+    } else {
+        // Forced to use the slower but correct code
         this->useDiffTimeOptimization = false;
         this->epicsEpochOffsetAsAnUnsignedLong = 0;
     }
@@ -205,7 +200,8 @@
     }
 }
 
-epicsTime::epicsTime () : secPastEpoch(0u), nSec(0u) {}	
+epicsTime::epicsTime () :
+    secPastEpoch(0u), nSec(0u) {}
 
 epicsTime::epicsTime (const epicsTime &t) : 
     secPastEpoch (t.secPastEpoch), nSec (t.nSec) {}
@@ -230,7 +226,7 @@
     return epicsTime ( current );
 }
 
-void epicsTime::synchronize () {} // depricated
+void epicsTime::synchronize () {} // deprecated
 
 //
 // operator time_t_wrapper ()
@@ -268,7 +264,7 @@
 
     int status = epicsTime_localtime ( &ansiTimeTicks.ts, &tm.ansi_tm );
     if ( status != epicsTimeOK ) {
-        throw std::logic_error ( "epicsTime_gmtime failed" );
+        throw std::logic_error ( "epicsTime_localtime failed" );
     }
 
     tm.nSec = this->nSec;
@@ -583,7 +579,7 @@
                     frac %= static_cast < unsigned long > ( 1e9 );
                     frac /= div[fracWid];
                     char fracFormat[32];
-                    sprintf ( fracFormat, "%%0%uu", fracWid );
+                    sprintf ( fracFormat, "%%0%lulu", fracWid );
                     int status = epicsSnprintf ( pBufCur, bufLenLeft, fracFormat, frac );
                     if ( status > 0 ) {
                         unsigned long nChar = static_cast < unsigned long > ( status );

Replies:
Re: Problems within epicsTime.cpp Andrew Johnson
RE: Problems within epicsTime.cpp Denison, PN (Peter)
References:
Problems within epicsTime.cpp Denison, PN (Peter)
Re: Problems within epicsTime.cpp Kay-Uwe Kasemir

Navigate by Date:
Prev: Re: Problems within epicsTime.cpp Kay-Uwe Kasemir
Next: Re: Problems within epicsTime.cpp Andrew Johnson
Index: 2002  2003  2004  2005  2006  2007  <20082009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
Navigate by Thread:
Prev: Re: Problems within epicsTime.cpp Kay-Uwe Kasemir
Next: Re: Problems within epicsTime.cpp Andrew Johnson
Index: 2002  2003  2004  2005  2006  2007  <20082009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
ANJ, 02 Feb 2012 Valid HTML 4.01! · Home · News · About · Base · Modules · Extensions · Distributions · Download ·
· Search · EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing ·