The Gaudi Framework  master (d98a2936)
Time.cpp
Go to the documentation of this file.
1 /***********************************************************************************\
2 * (c) Copyright 1998-2025 CERN for the benefit of the LHCb and ATLAS collaborations *
3 * *
4 * This software is distributed under the terms of the Apache version 2 licence, *
5 * copied verbatim in the file "LICENSE". *
6 * *
7 * In applying this licence, CERN does not waive the privileges and immunities *
8 * granted to it by virtue of its status as an Intergovernmental Organization *
9 * or submit itself to any jurisdiction. *
10 \***********************************************************************************/
11 #include <GaudiKernel/Time.h>
12 #include <cerrno>
13 #include <cstdio>
14 #include <cstring>
15 #include <ctime>
16 #include <iostream>
17 
18 using namespace Gaudi;
19 
20 #include <sys/time.h>
21 
22 //-----------------------------------------------------------------------------
23 // Implementation file for class : Gaudi::Time
24 // Based on seal::Time
25 // 2005-12-15 : Marco Clemencic
26 //-----------------------------------------------------------------------------
27 
28 Time::Time( int year, int month, int day, int hour, int min, int sec, ValueType nsecs, bool local /* = true */ ) {
29  tm val;
30  memset( &val, 0, sizeof( val ) );
31  val.tm_sec = sec;
32  val.tm_min = min;
33  val.tm_hour = hour;
34  val.tm_mday = day;
35  val.tm_mon = month;
36  val.tm_year = year > 1900 ? year - 1900 : year;
37  val.tm_isdst = -1; // FIXME?
38 
39  m_nsecs = build( local, val, nsecs ).m_nsecs;
40 }
41 
44  timeval tv;
45  if ( gettimeofday( &tv, nullptr ) != 0 ) {
46  char buf[256];
47  std::ostringstream tag, msg;
48  tag << "errno=" << errno;
49  if ( strerror_r( errno, buf, 256 ) == 0 ) {
50  msg << buf;
51  } else {
52  msg << "Unknown error retrieving current time";
53  }
54  throw GaudiException( msg.str(), tag.str(), StatusCode::FAILURE );
55  }
56  return Time( tv.tv_sec, tv.tv_usec * 1000 );
57 }
58 
60 Time Time::build( bool local, const tm& base, TimeSpan diff /* = 0 */ ) {
61  tm tmp( base );
62  return Time( local ? mktime( &tmp ) : timegm( &tmp ), 0 ) + diff;
63 }
64 
69 tm Time::split( bool local, int* nsecpart /* = 0 */ ) const {
70  if ( nsecpart ) *nsecpart = (int)( m_nsecs % SEC_NSECS );
71 
72  time_t val = (time_t)( m_nsecs / SEC_NSECS );
73 
74  tm retval;
75  if ( local )
76  localtime_r( &val, &retval );
77  else
78  gmtime_r( &val, &retval );
79 
80  return retval;
81 }
82 
86 tm Time::utc( int* nsecpart /* = 0 */ ) const { return split( false, nsecpart ); }
87 
91 tm Time::local( int* nsecpart /* = 0 */ ) const { return split( true, nsecpart ); }
92 
94 int Time::year( bool local ) const { return split( local ).tm_year + 1900; }
95 
97 int Time::month( bool local ) const { return split( local ).tm_mon; }
98 
100 int Time::day( bool local ) const { return split( local ).tm_mday; }
101 
103 int Time::hour( bool local ) const { return split( local ).tm_hour; }
104 
106 int Time::minute( bool local ) const { return split( local ).tm_min; }
107 
111 int Time::second( bool local ) const { return split( local ).tm_sec; }
112 
116 int Time::nsecond( void ) const { return (int)( m_nsecs % SEC_NSECS ); }
117 
119 int Time::weekday( bool local ) const { return split( local ).tm_wday; }
120 
124 bool Time::isdst( bool local ) const { return split( local ).tm_isdst > 0; }
125 
132 Time::ValueType Time::utcoffset( int* daylight /* = 0 */ ) const {
133  ValueType n = 0;
134 
135  tm localtm = local();
136  n = localtm.tm_gmtoff;
137  if ( daylight ) *daylight = localtm.tm_isdst;
138 
139  return n * SEC_NSECS;
140 }
141 
146 const char* Time::timezone( int* daylight /* = 0 */ ) const {
147  tm localtm = local();
148  if ( daylight ) *daylight = localtm.tm_isdst;
149  // extern "C" { extern char *tzname [2]; }
150  return tzname[localtm.tm_isdst > 0 ? 1 : 0];
151 }
152 
157 std::string Time::format( bool local, std::string spec ) const {
159  std::string result;
160  tm time = split( local );
161  std::string::size_type length = 0;
162 
163  // handle the special case of "%f"
164  std::string::size_type pos = spec.find( "%f" );
165  if ( std::string::npos != pos ) {
166  // Get the milliseconds string
167  std::string ms = nanoformat( 3, 3 );
168  // Replace all the occurrences of '%f' (if not preceded by '%')
169  while ( std::string::npos != pos ) {
170  if ( pos != 0 && spec[pos - 1] != '%' ) { spec.replace( pos, 2, ms ); }
171  pos = spec.find( "%f", pos + 1 ); // search for the next occurrence
172  }
173  }
174  const int MIN_BUF_SIZE = 128;
175  do {
176  // Guess how much we'll expand. If we go wrong, we'll expand again. (with a minimum)
177  result.resize( std::max<std::string::size_type>(
178  result.size() * 2, std::max<std::string::size_type>( spec.size() * 2, MIN_BUF_SIZE ) ),
179  0 );
180  length = ::strftime( &result[0], result.size(), spec.c_str(), &time );
181  } while ( !length );
182 
183  result.resize( length );
184  return result;
185 }
186 
197 std::string Time::nanoformat( size_t minwidth /* = 1 */, size_t maxwidth /* = 9 */ ) const {
198  TimeAssert( ( minwidth >= 1 ) && ( minwidth <= maxwidth ) && ( maxwidth <= 9 ),
199  "nanoformat options do not satisfy: 1 <= minwidth <= maxwidth <= 9" );
200 
201  // Calculate the nanosecond fraction. This will be < 1000000000.
202  int value = (int)( m_nsecs % SEC_NSECS );
203 
204  std::ostringstream buf;
205  (void)buf.fill( '0' );
206  buf.width( 9 );
207  buf << value;
208  std::string out = buf.str();
209  // Find the last non-0 char before maxwidth, but after minwidth
210  // (Note: -1 and +1 are to account for difference between position and size.
211  // moreover, npos + 1 == 0, so it is correct to say that 'not found' means size of 0)
212  size_t len = out.find_last_not_of( '0', maxwidth - 1 ) + 1;
213  // Truncate the output string to at least minwidth chars
214  out.resize( std::max( len, minwidth ) );
215  return out;
216 }
217 
219 unsigned Time::toDosDate( Time time ) {
220  // Use local time since DOS does too.
221  struct tm localtm = time.local();
222 
223  unsigned mday = localtm.tm_mday;
224  unsigned mon = localtm.tm_mon + 1;
225  unsigned year = ( localtm.tm_year > 80 ? localtm.tm_year - 80 : 0 );
226  unsigned sec = localtm.tm_sec / 2;
227  unsigned min = localtm.tm_min;
228  unsigned hour = localtm.tm_hour;
229  return ( mday << 16 | mon << 21 | year << 25 | sec | min << 5 | hour << 11 );
230 }
231 
233 Time Time::fromDosDate( unsigned dosDate ) {
234  // DOS times are generally local; treat it as UTC. This avoids
235  // any round-trip conversion and leaves only a presentation as an
236  // issue. Since not much can be known about the origin of the DOS
237  // times, it's generally best to present them as such (= in UTC).
238  struct tm localtm;
239  memset( &localtm, 0, sizeof( localtm ) );
240  localtm.tm_mday = ( dosDate >> 16 ) & 0x1f;
241  localtm.tm_mon = ( ( dosDate >> 21 ) & 0xf ) - 1;
242  localtm.tm_year = ( ( dosDate >> 25 ) & 0x7f ) + 80;
243  localtm.tm_hour = ( dosDate >> 11 ) & 0x1f;
244  localtm.tm_min = ( dosDate >> 5 ) & 0x3f;
245  localtm.tm_sec = ( dosDate & 0x1f ) * 2;
246  localtm.tm_isdst = -1;
247 
248  return Time( mktime( &localtm ), 0 );
249 }
Gaudi::Time::isdst
bool isdst(bool local) const
Check whether daylight savings is in effect.
Definition: Time.cpp:124
Gaudi::Time::year
int year(bool local) const
Get the year.
Definition: Time.cpp:94
Gaudi::Time::second
int second(bool local) const
Get the seconds, numbered [0,61] (allowing one or two leap seconds, years with leap seconds can have ...
Definition: Time.cpp:111
GaudiException
Definition: GaudiException.h:29
GaudiMP.FdsRegistry.msg
msg
Definition: FdsRegistry.py:19
Gaudi::Time::Time
Time()=default
Initialize an empty (zero) time value.
Gaudi::Time::nanoformat
std::string nanoformat(size_t minwidth=1, size_t maxwidth=9) const
Format the nanosecond fractional part of the time as a string.
Definition: Time.cpp:197
Gaudi::Time::timezone
const char * timezone(int *daylight=0) const
Return the local timezone name that applies at this time value.
Definition: Time.cpp:146
Gaudi::Time::m_nsecs
ValueType m_nsecs
Definition: Time.h:330
Gaudi::Time::utcoffset
ValueType utcoffset(int *daylight=0) const
Return the number of nanoseconds that needs to be added to UTC to translate this time to the local ti...
Definition: Time.cpp:132
Gaudi::Time
Definition: Time.h:235
Gaudi::Units::ms
constexpr double ms
Definition: SystemOfUnits.h:153
Gaudi::TimeSpan
Definition: Time.h:56
Gaudi::Time::minute
int minute(bool local) const
Get the minute, numbered [0, 59].
Definition: Time.cpp:106
Gaudi::Time::format
std::string format(bool local, std::string spec="%c") const
Format the time using strftime.
Definition: Time.cpp:157
Gaudi::Time::toDosDate
static unsigned toDosDate(Time time)
Convert the Time t into a MS-DOS date format.
Definition: Time.cpp:219
Gaudi::Time::split
tm split(bool local, int *nsecpart=0) const
Break up the time to the standard representation, either in UTC (if local is false) or local time (if...
Definition: Time.cpp:69
Gaudi::Time::ValueType
long long ValueType
Definition: Time.h:239
Gaudi::Time::hour
int hour(bool local) const
Get the hour, numbered [0, 23].
Definition: Time.cpp:103
Gaudi::Time::weekday
int weekday(bool local) const
Get the day of week, numbered [0,6] and starting from Sunday.
Definition: Time.cpp:119
Gaudi
This file provides a Grammar for the type Gaudi::Accumulators::Axis It allows to use that type from p...
Definition: __init__.py:1
plotSpeedupsPyRoot.time
time
Definition: plotSpeedupsPyRoot.py:180
cpluginsvc.n
n
Definition: cpluginsvc.py:234
Time.h
Gaudi::Time::SEC_NSECS
static const ValueType SEC_NSECS
Nanoseconds in one second.
Definition: Time.h:264
Gaudi::Time::current
static Time current()
Returns the current time.
Definition: Time.cpp:43
compareRootHistos.retval
retval
Definition: compareRootHistos.py:499
Gaudi::Time::local
tm local(int *nsecpart=0) const
Break up the time to the standard library representation, converting it first to local time.
Definition: Time.cpp:91
Gaudi::Time::month
int month(bool local) const
Get the month, numbered [0,11].
Definition: Time.cpp:97
Gaudi::Time::TimeAssert
void TimeAssert(bool cond, std::string_view msg="time assertion failed") const
Definition: Time.h:333
check_ParticleID.base
base
Definition: check_ParticleID.py:24
Gaudi::Time::nsecond
int nsecond() const
Get the nanoseconds.
Definition: Time.cpp:116
Gaudi::Time::day
int day(bool local) const
Get the day of month, numbered [1,31].
Definition: Time.cpp:100
StatusCode::FAILURE
constexpr static const auto FAILURE
Definition: StatusCode.h:100
Gaudi::Time::fromDosDate
static Time fromDosDate(unsigned dosDate)
Convert the MS-DOS date dosDate into a Time.
Definition: Time.cpp:233
Gaudi::Time::utc
tm utc(int *nsecpart=0) const
Break up the time to the standard library representation, keeping it in UTC.
Definition: Time.cpp:86
Gaudi::Time::build
static Time build(bool local, const tm &base, TimeSpan diff=0)
Construct a time from local time base and a delta diff.
Definition: Time.cpp:60
Gaudi::Functional::details::out
OptOut && out
Definition: details.h:179