Back to home page

EIC code displayed by LXR

 
 

    


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