00001 #ifndef BDBTIME_HH 00002 #define BDBTIME_HH 00003 00004 //----------------------------------------------------------------------------- 00005 // 00006 // File and Version Information: 00007 // $Id: BdbTime.hh,v 1.21 2004/08/06 05:48:02 bartoldu Exp $ 00008 // 00009 // Description: 00010 // Class BdbTime. 00011 // This is a persistent time class. 00012 // 00013 // Environment: 00014 // Software developed for the BaBar Detector at the SLAC B-Factory. 00015 // 00016 // Author List: 00017 // J. Ohnemus Original Author 00018 // Gregory Dubois-Felsmann Rogue Wave migration, 2002/2003 00019 // 00020 // Copyright Information: 00021 // Copyright (C) 1994, 1995 Lawrence Berkeley Laboratory 00022 // Copyright (c) 2002, 2003 California Institute of Technology 00023 // 00024 //----------------------------------------------------------------------------- 00025 00026 //----------------- 00027 // BaBar Headers -- 00028 //----------------- 00029 #include "BaBar/BaBarODMGTypes.h" 00030 00031 //----------------- 00032 // C/C++ Headers -- 00033 //----------------- 00034 #include <time.h> 00035 #include <iostream> 00036 #include <string> 00037 00038 //------------------------------- 00039 // Collaborating Class Headers -- 00040 //------------------------------- 00041 #include "BdbTime/BdbDuration.hh" 00042 #include "BdbTime/BdbTimeConst.hh" 00043 00044 //------------------------------------ 00045 // Collaborating Class Declarations -- 00046 //------------------------------------ 00047 00048 // --------------------- 00049 // -- Class Interface -- 00050 // --------------------- 00051 00052 class BdbTime { 00053 00054 public: 00055 00056 enum Zone { Local, UTC }; 00057 00058 // Constructors 00059 00060 /** 00061 * (Deprecated) 00062 * Constructs with the current time, to the nearest second. This 00063 * constructor is deprecated and may be removed in a future release. 00064 * The static function BdbTime::now() should be used in preference 00065 * to this in all new code, if the current time is really required. 00066 * 00067 * For some reason, the original implementation did not set the _gmtNsec 00068 * member, perhaps because it was not easy to get it synchronized with 00069 * the Rogue Wave "now()" function's return value. Now that we use 00070 * clock_gettime() directly, this could be fixed. 00071 * 00072 * However, we have decided not to do this at this time, in order not 00073 * to change the behavior of existing programs. 00074 * 00075 * BdbTime::now() preserves the full significance available from 00076 * clock_gettime(). 00077 * 00078 * Please note that this constructor involves a system call and is 00079 * expensive! Do not default-construct BdbTimes unless you really need 00080 * the current time value. If you are just declaring a time variable 00081 * to fill in later, BdbTime(0) is a more performant choice. 00082 */ 00083 BdbTime( ); 00084 00085 /** Copy constructor. */ 00086 BdbTime( const BdbTime& t ); 00087 00088 /** 00089 * Constructs a time from an unsigned number of seconds since the 00090 * BdbTime epoch of 1901. NB: this is not the Unix epoch of 1970! 00091 */ 00092 explicit BdbTime( d_ULong sec_since_1901, d_ULong nsec = 0 ); 00093 00094 /** 00095 * Constructs a time from a broken-down list of components of a date 00096 * and time. 00097 * 00098 * This uses definitions inherited from the old RogueWave implementation 00099 * of BdbTime. Thus "year" is the calendar year C.E. (e.g., 2003), and 00100 * "month" is the month in the range {1..12}. Note that these differ 00101 * from the POSIX broken-down time (struct tm) definitions, where 00102 * 2003 C.E. is represented as 103, and the month is in the range {0..11}. 00103 */ 00104 BdbTime( d_ULong year, 00105 d_ULong month, 00106 d_ULong day, 00107 d_ULong hour, 00108 d_ULong minute, 00109 d_ULong second, 00110 d_ULong nanosecond = 0, 00111 Zone zone = UTC ); 00112 00113 /** 00114 * (Deprecated - use parseTime()) 00115 * Constructs a BdbTime from a string date and a string time. 00116 * 00117 * The use of this constructor is strongly discouraged, as it does not 00118 * have a means of reliably reporting parsing errors (BaBar does not 00119 * use C++ exceptions). Use BdbTime::parseTime() instead (which this 00120 * is implemented over). 00121 */ 00122 BdbTime( const std::string& date, const std::string& time, Zone zone = UTC ); 00123 00124 /** 00125 * (Deprecated - use parseTime()) 00126 * Constructs a BdbTime from a single date-time string, in which the 00127 * date and time must be given separated by whitespace. Otherwise 00128 * identical to the above constructor. 00129 * 00130 * The use of this constructor is strongly discouraged, as it does not 00131 * have a means of reliably reporting parsing errors (BaBar does not 00132 * use C++ exceptions). Use BdbTime::parseTime() instead (which this 00133 * is implemented over). 00134 */ 00135 explicit BdbTime( const std::string&, Zone zone = UTC ); 00136 00137 /** 00138 * Constructs from POSIX high-resolution time, as might be 00139 * obtained from clock_gettime. 00140 */ 00141 BdbTime( const struct timespec& ts ); 00142 00143 /** 00144 * Constructs from POSIX "broken-down time". 00145 * @param stm Cannot be const because it is internally provided to 00146 * POSIX mktime(), which normalizes it -- see man mktime. 00147 */ 00148 BdbTime( struct tm& stm, Zone zone = UTC ); 00149 00150 /** 00151 * The destructor is non-virtual in order to keep this representational 00152 * class small and suitable for processing with value semantics. 00153 * Classes with non-empty destructors should not be constructed with 00154 * non-private inheritance from BdbTime. 00155 */ 00156 ~BdbTime( ) { } 00157 00158 00159 // Assignment operator 00160 BdbTime& operator=( const BdbTime& t ); 00161 00162 // Calculational operators 00163 00164 /** 00165 * Calculates the absolute value of the difference between two times. 00166 * NB: BdbDuration is an inherently unsigned quantity! This is 00167 * in essence because reasonably foreseeable time differences are 00168 * larger in seconds than 2^31 and so can't be represented as a 00169 * signed 32 bit integer. 00170 */ 00171 BdbDuration operator-( const BdbTime& t ) const; 00172 00173 BdbTime& operator+=( const BdbDuration& d ); 00174 BdbTime operator+( const BdbDuration& d ) const; 00175 00176 BdbTime& operator-=( const BdbDuration& d ); 00177 BdbTime operator-( const BdbDuration& d ) const; 00178 00179 // Comparison operators 00180 bool operator==( const BdbTime& t ) const 00181 { 00182 return ( _gmtSec == t._gmtSec && _gmtNsec == t._gmtNsec ); 00183 } 00184 00185 bool operator!=( const BdbTime& t ) const 00186 { 00187 return !( *this == t ); 00188 } 00189 00190 bool operator<( const BdbTime& t ) const 00191 { 00192 return ( _gmtSec < t._gmtSec ) || 00193 ( _gmtSec == t._gmtSec && _gmtNsec < t._gmtNsec ); 00194 } 00195 00196 bool operator<=( const BdbTime& t ) const 00197 { 00198 return ( _gmtSec < t._gmtSec ) || 00199 ( _gmtSec == t._gmtSec && _gmtNsec <= t._gmtNsec ); 00200 } 00201 00202 bool operator>( const BdbTime& t ) const 00203 { 00204 return !( *this <= t ); 00205 } 00206 00207 bool operator>=( const BdbTime& t ) const 00208 { 00209 return !( *this < t ); 00210 } 00211 00212 // Selectors 00213 d_ULong getGmtSec( ) const { return _gmtSec; } 00214 d_ULong getGmtNsec( ) const { return _gmtNsec; } 00215 00216 /** 00217 * Extracts the value of the BdbTime as a POSIX.1b "struct timespec". 00218 * Returns 0 on success in analogy with POSIX.1b clock_gettime(). 00219 * WARNING: Must and will fail for valid BdbTime values that are more 00220 * than 2^31-1 seconds before the beginning of the POSIX 1970 epoch, 00221 * i.e., before around 1901.12.13 20:45:53 UTC. 00222 * 00223 * There are such times in the conditions database from early 00224 * SP production, before all times were renormalized into 1997+ space. 00225 */ 00226 int timeSpec( struct timespec* ts ) const; 00227 00228 /** 00229 * Extracts the value of the BdbTime as a POSIX "struct tm" broken-down 00230 * time. This requires the use of a time zone. In analogy with the 00231 * POSIX.1b gmtime_r() function, a pointer to a "struct tm" to receive 00232 * the data must be supplied -- so this function is thread-safe(*). 00233 * Following this analogy, the function returns the supplied pointer 00234 * on success, and 0 on failure. 00235 * 00236 * This function should work for all times in the BdbTime range. 00237 */ 00238 struct tm* tm( struct tm* stm, Zone zone ) const; 00239 00240 /** 00241 * Creates a string from the value of the BdbTime, based on a 00242 * specified format specification, as for POSIX strftime(), and on 00243 * a time zone. Note that this function does not provide a way 00244 * to embed the "nanoseconds" part of the BdbTime, since this is 00245 * not possible to express in a form recognized by strftime. 00246 * 00247 * The "%N" format specified does not appear to be used in the POSIX 00248 * definition of strftime. It's possible it could be hijacked in a 00249 * future upgrade. FIXME 00250 * 00251 * This function should work for all times in the BdbTime range. 00252 */ 00253 std::string asString( const char* fmt, Zone zone ) const; 00254 00255 // Friends 00256 friend BdbTime operator+( const BdbDuration& d, const BdbTime& t ); 00257 friend std::ostream& operator<<( std::ostream& os, const BdbTime& t ); 00258 00259 private: 00260 00261 void renormalizeNanoseconds( ); 00262 00263 // Data members 00264 d_ULong _gmtSec; // number of seconds since 00:00:00 Jan. 1, 1901 UTC 00265 d_ULong _gmtNsec; // number of nanoseconds 00266 00267 public: 00268 // static interfaces: 00269 00270 /** 00271 * Constructs and returns a BdbTime representing the current time. 00272 * This interface, unlike the deprecated default constructor, returns 00273 * a BdbTime set to the full resolution available from clock_gettime(). 00274 * Note that this may vary between platforms and even operating 00275 * system versions. 00276 */ 00277 static BdbTime now(); 00278 00279 /** 00280 * Determines whether a string representing a date and a string 00281 * representing a time can be converted successfully to a date/time 00282 * in BdbTime format, i.e., in the unsigned 1901 epoch. 00283 * 00284 * Note that 1901.01.01 00:00:00 UTC is not a valid time; 00:00:01 00285 * is the first valid time. 00286 * 00287 * Date is parsed using strptime formats "%D" and "%d%b%Y", controlled 00288 * by BdbTimeInput, with the first one that succeeds taking precedence. 00289 * Time is parsed with formats "%T" and "%R". These are quite a 00290 * restricted set compared to those originally accepted by the 00291 * Rogue Wave implementation first used here. 00292 * 00293 * By default times are interpreted as UTC (a logical alternative might 00294 * be the local time zone. If an invalid date or time string is supplied, 00295 * the BdbTime time will be set to -Infinity. If the date string is set to 00296 * "+Infinity" or "-Infinity", the time string will be ignored and the 00297 * BdbTime will be set to the corresponding value. 00298 * 00299 * @param time Returned time value; modified only if parsing is successful. 00300 * @return Flag indicating whether parsing was successful. 00301 */ 00302 static bool parseTime( const std::string& sdate, const std::string& stime, 00303 Zone zone, 00304 BdbTime& time ); 00305 00306 /** 00307 * Determines whether a string representing a date and time can be 00308 * converted successfully to a date/time in BdbTime format, i.e., in 00309 * the unsigned 1901 epoch. 00310 * 00311 * Equivalent to a call to parseTime( const std::string& sdate, 00312 * const std::string& stime, Zone zone, BdbTime& time ) 00313 * with the date and time set from the first and second whitespace- 00314 * delimited tokens in the sdatetime string and subsequent text ignored. 00315 * 00316 * This is a less precise parsing method than the above. 00317 * 00318 * @param time Returned time value; modified only if parsing is successful. 00319 * @return Flag indicating whether parsing was successful. 00320 */ 00321 static bool parseTime( const std::string& sdatetime, 00322 Zone zone, 00323 BdbTime& time ); 00324 00325 // Static members 00326 static const BdbTime minusInfinity; 00327 static const BdbTime plusInfinity; 00328 00329 }; 00330 00331 00332 inline void 00333 BdbTime::renormalizeNanoseconds( ) 00334 { 00335 if ( _gmtNsec >= BdbTimeConst::nsecInASec ) { 00336 // carry nanoseconds over into seconds 00337 d_ULong extraSec = _gmtNsec / BdbTimeConst::nsecInASec; 00338 d_ULong remainNsec = _gmtNsec % BdbTimeConst::nsecInASec; 00339 _gmtSec += extraSec; 00340 _gmtNsec = remainNsec; 00341 } 00342 } 00343 00344 #endif
1.3-rc3