|
||||
File indexing completed on 2025-01-18 09:57:44
0001 /***********************************************************************************\ 0002 * (c) Copyright 1998-2019 CERN for the benefit of the LHCb and ATLAS collaborations * 0003 * * 0004 * This software is distributed under the terms of the Apache version 2 licence, * 0005 * copied verbatim in the file "LICENSE". * 0006 * * 0007 * In applying this licence, CERN does not waive the privileges and immunities * 0008 * granted to it by virtue of its status as an Intergovernmental Organization * 0009 * or submit itself to any jurisdiction. * 0010 \***********************************************************************************/ 0011 #ifndef GAUDIKERNEL_TIME_H 0012 #define GAUDIKERNEL_TIME_H 1 0013 0014 // Include files 0015 // for the architecture independent int64 definition (long long) 0016 #include "GaudiKernel/GaudiException.h" 0017 #include "GaudiKernel/Kernel.h" 0018 #include "GaudiKernel/StreamBuffer.h" 0019 0020 /** @class TimeException Time.h GaudiKernel/Time.h 0021 * 0022 * Exception thrown by Gaudi::Time. 0023 * 0024 * @see GaudiException 0025 * @see Gaudi::Time 0026 * 0027 * @author Marco Clemencic 0028 * @date 2005-12-14 0029 */ 0030 struct GAUDI_API TimeException : GaudiException { 0031 // Standard constructor 0032 TimeException( std::string Message = "unspecified exception", std::string Tag = "*Gaudi::Time*", 0033 StatusCode Code = StatusCode::FAILURE ) 0034 : GaudiException( std::move( Message ), std::move( Tag ), std::move( Code ) ) {} 0035 }; 0036 0037 struct tm; 0038 #ifdef WIN32 0039 typedef struct _FILETIME FILETIME; 0040 #endif 0041 0042 namespace Gaudi { 0043 0044 class Time; 0045 class TimeSpan; 0046 0047 /** @class TimeSpan Time.h GaudiKernel/Time.h 0048 * 0049 * Based on seal::TimeSpan. 0050 * 0051 0052 A difference between two #Time values. In addition to supporting 0053 normal integer artihmetic and comparisons, the span can also be 0054 converted to a number useful units. 0055 0056 @sa #Time. 0057 0058 * (Documentation taken from original SEAL class) 0059 * @author Marco Clemencic 0060 * @date 2005-12-15 0061 */ 0062 class GAUDI_API TimeSpan { 0063 friend class Time; 0064 0065 public: 0066 typedef long long ValueType; 0067 0068 /** Initialize an empty (zero) time difference. */ 0069 TimeSpan() = default; 0070 0071 TimeSpan( Time t ); 0072 TimeSpan( ValueType nsecs ); 0073 TimeSpan( ValueType secs, int nsecs ); 0074 TimeSpan( int days, int hours, int mins, int secs, int nsecs ); 0075 0076 int days() const; 0077 int hours() const; 0078 int minutes() const; 0079 ValueType seconds() const; 0080 0081 int lastHours() const; 0082 int lastMinutes() const; 0083 int lastSeconds() const; 0084 int lastNSeconds() const; 0085 0086 TimeSpan& operator+=( const TimeSpan& x ); 0087 TimeSpan& operator-=( const TimeSpan& x ); 0088 TimeSpan& operator*=( const TimeSpan& n ); 0089 TimeSpan& operator/=( const TimeSpan& n ); 0090 TimeSpan& operator%=( const TimeSpan& n ); 0091 0092 ValueType ns() const; 0093 0094 friend bool operator==( const Gaudi::TimeSpan& t1, const Gaudi::TimeSpan& t2 ) { return t1.ns() == t2.ns(); } 0095 0096 friend bool operator!=( const Gaudi::TimeSpan& t1, const Gaudi::TimeSpan& t2 ) { return t1.ns() != t2.ns(); } 0097 0098 friend bool operator<( const Gaudi::TimeSpan& t1, const Gaudi::TimeSpan& t2 ) { return t1.ns() < t2.ns(); } 0099 0100 friend bool operator<=( const Gaudi::TimeSpan& t1, const Gaudi::TimeSpan& t2 ) { return t1.ns() <= t2.ns(); } 0101 0102 friend bool operator>( const Gaudi::TimeSpan& t1, const Gaudi::TimeSpan& t2 ) { return t1.ns() > t2.ns(); } 0103 0104 friend bool operator>=( const Gaudi::TimeSpan& t1, const Gaudi::TimeSpan& t2 ) { return t1.ns() >= t2.ns(); } 0105 0106 friend Gaudi::TimeSpan operator+( const Gaudi::TimeSpan& ts1, const Gaudi::TimeSpan& ts2 ) { 0107 return Gaudi::TimeSpan( ts1.ns() + ts2.ns() ); 0108 } 0109 0110 friend Gaudi::TimeSpan operator-( const Gaudi::TimeSpan& ts1, const Gaudi::TimeSpan& ts2 ) { 0111 return Gaudi::TimeSpan( ts1.ns() - ts2.ns() ); 0112 } 0113 0114 private: 0115 ValueType m_nsecs = 0; //< The span length. 0116 }; 0117 0118 /** @class Time Time.h GaudiKernel/Time.h 0119 * 0120 * Based on seal::Time. 0121 * 0122 Calendar time in nanoseconds since 00:00:00 on January 1, 1970, 0123 Coordinated Universal Time (UTC). 0124 0125 #Time is represented internally as UTC time, but it can also be 0126 converted to the local time as necessary. Most methods take an 0127 argument flag @c local to indicate which time interpretation is 0128 desired by the client, and automatically perform the necessary 0129 adjustments. The client can also find out about the difference 0130 between UTC time and local time using the #utcoffset() method, 0131 and the time zone name with #timezone() method. Both allow the 0132 client to discover whether daylight savings is in effect. 0133 0134 The native representation of #Time is not well suited for human 0135 handling of time. #Time provides access in more convenient terms 0136 such as #year(), #month() and #day(); more are available through 0137 conversion into a #TimeSpan. #Time can also be converted to and 0138 from ISO C standard @c tm structure. Note however that unlike C's 0139 @c mktime() which always assumes @c tm in local time, #Time fully 0140 supports all conversions between local and universal time. Thus 0141 it is possible for example to #build() a UTC time directly from a 0142 @c tm. 0143 0144 #Time behaves as an integral type. Differences in time values are 0145 represented as a #TimeSpan. Usual integral arithmetic works with 0146 both types. Output works in general as any other integral type, 0147 however since the #ValueType can be a wide type, it may be poorly 0148 supported by the @c iostream; if so, including the @c LongLong.h 0149 header will help. Note that the output value will usually be very 0150 large as #Time is represented in nanoseconds, not seconds! When 0151 constructing #Time values in seconds, such as when reading in, do 0152 remember to use the two-argument constructor taking seconds and 0153 nanoseconds instead of the default single-argument one. 0154 0155 #Time can be formatted into a string using the #format() method, 0156 which uses the versatile @c strftime() function. Since the latter 0157 works on seconds at best (through a struct @c tm), the subsecond 0158 part cannot be formatted; the #nanoformat() method is provided to 0159 overcome this limitation. To combine #format() and #nanoformat() 0160 output use a suitable #StringFormat pattern. 0161 0162 #Time is linked to the system's concept of calendar time and is 0163 therefore may not be linear nor monotonic. System time can jump 0164 arbitrarily in either direction as real time clock is corrected or 0165 the system is suspended. The local time may also jump due to 0166 daylight savings. The process' ability to sample system time can 0167 be limited for reasons such as getting swapped out. #TimeInfo 0168 provides an alternative time measurement facility not linked to 0169 calendar and guaranteed to grow monotonically -- though not always 0170 linearly. Note that few systems actually provide wall-clock time 0171 in nanosecond resolution. Not all system provide an interface to 0172 get time at that resolution, let alone track it so precisely. 0173 0174 Because of the time warp issues, scheduling events using #Time is 0175 not straightforward. Application code should understand whether 0176 it is dealing with concrete or abstract calendar calculations, and 0177 how the events it schedules are linked to wall clock time. 0178 0179 For calculations on concrete calendar as perceived by people use 0180 #local() after plain #Time and #TimeSpan integer arithmetic. The 0181 method accounts for timezone and daylight savings definitions. To 0182 schedule events use #build() to derive times from #local() time to 0183 get values comparable to the system time returned by #current(). 0184 The applications should know whether events are scheduled in UTC 0185 or local time---"meeting at 9:00 on Wednesday morning" when the 0186 device switches timezones may be known to be at 9:00 in the new 0187 timezone (= locked to local time), or in the timezone where the 0188 event was created (= locked to UTC). The #build() and #split() 0189 methods allow either format to be used, the application just needs 0190 to know which one to use. It is also easy to convert between the 0191 two using #utcoffset(). 0192 0193 For calculations using an abstract calendar, without timezone or 0194 daylight savings, use #Time in its native UTC representation and 0195 integer arithmetic with #Time and #TimeSpan. Do note however that 0196 "T + 24 hours" may not be the same hour the next day in the local 0197 calendar time -- timezone changes and daylight savings make a 0198 difference. This may require the application to accept as user 0199 input exception rules to its usual calendar calculations. 0200 0201 To schedule events, one should choose between three choices: UTC 0202 time, local time, or delta time. For the first two cases system 0203 time should be polled regularly to see if any of the recorded 0204 events have expired. It is not a good idea to sleep until the 0205 next scheduled event, as the system time may jump during the nap; 0206 instead sleep small increments, recheck the current time after 0207 each nap and trigger the events that have expired. A policy must 0208 be applied when the system time warps; this can happen both 0209 forwards and backwards with both local and UTC time (daylight 0210 savings or timezone changes for mobile devices are common local 0211 time change reasons, but the system time can be updated for any 0212 reason, e.g. when the real time clock is wrong, or if the system 0213 is suspended for a long time). Some events should be executed 0214 only once in case of time warps backwards. If the time jumps 0215 forwards, several events may need to be dealt with in one go. In 0216 either case the application should guard against major time 0217 changes: long system suspends, moving mobile devices and major 0218 time updates may result in a large number of "missed" events. One 0219 possibility is to provide a user-configurable "excessive time 0220 drift limit" (e.g. N hours): if time changes by more than that, 0221 missed events are not triggered. 0222 0223 For the final case of using delta times, sort upcoming events by 0224 their deltas from the previous event---not by the time they are 0225 anticipated to occur. Capture current time before and after the 0226 sleep and pull events off the queue based on the difference (the 0227 sleep time may exceed the requested time). Either guard against 0228 long time warps like suspends or schedule timer events cautiously. 0229 Using #TimeInfo as schedule base solves such issues simply. To 0230 cope with backward system time jumps when using #Time as schedule 0231 base, assume that sleeps always last at least the requested time; 0232 if the time delta over the nap is less than the requested, assume 0233 time warp (this is not foolproof against interrupted system calls 0234 but works for many event scheduling situations). 0235 0236 @sa #TimeInfo for monotonic time not related to the calendar. 0237 * (Documentation taken from original SEAL class) 0238 * @author Marco Clemencic 0239 * @date 2005-12-15 0240 */ 0241 class GAUDI_API Time { 0242 friend class TimeSpan; 0243 0244 public: 0245 typedef long long ValueType; 0246 0247 /** Symbolic names for months */ 0248 enum Months { 0249 January = 0, 0250 February = 1, 0251 March = 2, 0252 April = 3, 0253 May = 4, 0254 June = 5, 0255 July = 6, 0256 August = 7, 0257 September = 8, 0258 October = 9, 0259 November = 10, 0260 December = 11 0261 }; 0262 0263 /** Seconds in 24 hours. */ 0264 static const int SECS_PER_DAY = 86400; 0265 0266 /** Seconds in one hour hour. */ 0267 static const int SECS_PER_HOUR = 3600; 0268 0269 /** Nanoseconds in one second. */ 0270 static const ValueType SEC_NSECS = 1000000000; 0271 0272 /** Initialize an empty (zero) time value. */ 0273 Time() = default; 0274 0275 Time( TimeSpan ts ); 0276 Time( ValueType nsecs ); 0277 Time( ValueType secs, int nsecs ); 0278 Time( int year, int month, int day, int hour, int min, int sec, ValueType nsecs, bool local = true ); 0279 // implicit copy constructor 0280 // implicit assignment operator 0281 // implicit destructor 0282 0283 /// Returns the minimum time. 0284 static Time epoch(); 0285 /// Returns the maximum time. 0286 static Time max(); 0287 /// Returns the current time. 0288 static Time current(); 0289 #ifdef WIN32 0290 static Time from( const FILETIME* systime ); 0291 #endif 0292 static Time build( bool local, const tm& base, TimeSpan diff = 0 ); 0293 0294 tm split( bool local, int* nsecpart = 0 ) const; 0295 tm utc( int* nsecpart = 0 ) const; 0296 tm local( int* nsecpart = 0 ) const; 0297 0298 int year( bool local ) const; 0299 int month( bool local ) const; 0300 int day( bool local ) const; 0301 int hour( bool local ) const; 0302 int minute( bool local ) const; 0303 int second( bool local ) const; 0304 int nsecond() const; 0305 int weekday( bool local ) const; 0306 bool isdst( bool local ) const; 0307 0308 ValueType utcoffset( int* daylight = 0 ) const; 0309 const char* timezone( int* daylight = 0 ) const; 0310 0311 Time& operator+=( const TimeSpan& x ); 0312 Time& operator-=( const TimeSpan& x ); 0313 0314 ValueType ns() const; 0315 0316 std::string format( bool local, std::string spec = "%c" ) const; 0317 std::string nanoformat( size_t minwidth = 1, size_t maxwidth = 9 ) const; 0318 0319 static bool isLeap( int year ); 0320 0321 // Conversion helpers 0322 static unsigned toDosDate( Time time ); 0323 static Time fromDosDate( unsigned dosDate ); 0324 0325 friend bool operator==( const Gaudi::Time& t1, const Gaudi::Time& t2 ) { return t1.ns() == t2.ns(); } 0326 0327 friend bool operator!=( const Gaudi::Time& t1, const Gaudi::Time& t2 ) { return t1.ns() != t2.ns(); } 0328 0329 friend bool operator<( const Gaudi::Time& t1, const Gaudi::Time& t2 ) { return t1.ns() < t2.ns(); } 0330 0331 friend bool operator<=( const Gaudi::Time& t1, const Gaudi::Time& t2 ) { return t1.ns() <= t2.ns(); } 0332 0333 friend bool operator>( const Gaudi::Time& t1, const Gaudi::Time& t2 ) { return t1.ns() > t2.ns(); } 0334 0335 friend bool operator>=( const Gaudi::Time& t1, const Gaudi::Time& t2 ) { return t1.ns() >= t2.ns(); } 0336 0337 private: 0338 ValueType m_nsecs = 0; //< Time value as nsecs from #epoch(). 0339 0340 // Taking string_view means there will never be any dynamic allocation if cond == true 0341 inline void TimeAssert( bool cond, std::string_view msg = "time assertion failed" ) const { 0342 if ( !cond ) throw TimeException( std::string{ msg } ); 0343 } 0344 }; 0345 } // namespace Gaudi 0346 0347 #include "GaudiKernel/Time.icpp" 0348 0349 #endif // GAUDIKERNEL_TIME_H
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |