The Gaudi Framework  master (37c0b60a)
Time.cpp
Go to the documentation of this file.
1 /***********************************************************************************\
2 * (c) Copyright 1998-2024 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 files
12 #include <GaudiKernel/Time.h>
13 
14 #include <GaudiKernel/time_r.h>
15 
16 #include <cerrno>
17 #include <cstdio>
18 #include <cstring>
19 #include <ctime>
20 #include <iostream>
21 
22 // local
23 using namespace Gaudi;
24 
25 // architecture dependent includes
26 #ifdef WIN32
27 
28 // this turns off a lot of useless Win stuff which conflicts with Gaudi. (found empirically)
29 # define NOATOM
30 # define NOGDI
31 # define NOGDICAPMASKS
32 # define NOMETAFILE
33 # define NOMINMAX
34 # define NOMSG
35 # define NOOPENFILE
36 # define NORASTEROPS
37 # define NOSCROLL
38 # define NOSOUND
39 # define NOSYSMETRICS
40 # define NOTEXTMETRIC
41 # define NOWH
42 # define NOCOMM
43 # define NOKANJI
44 # define NOCRYPT
45 # define NOMCX
46 
47 # include <windows.h>
48 
49 #else
50 // Linux
51 
52 # include <sys/time.h>
53 
54 #endif
55 
56 //-----------------------------------------------------------------------------
57 // Implementation file for class : Gaudi::Time
58 // Based on seal::Time
59 // 2005-12-15 : Marco Clemencic
60 //-----------------------------------------------------------------------------
61 
62 #ifdef WIN32
63 
72 // # define SECS_1601_TO_1970 ((369 * 365 + 89) * SECS_PER_DAY)
73 # define SECS_1601_TO_1970 ( ( 369 * 365 + 89 ) * 86400ui64 )
74 #endif
75 
76 #ifdef WIN32
77 static time_t timegm( struct tm* t ) {
78  // This code is adapted from wine, samba
79  time_t t1 = mktime( t );
80  struct tm gmt;
81  gmtime_s( &gmt, &t1 );
82  time_t t2 = mktime( &gmt );
83  return t1 + ( t1 - t2 );
84 }
85 #endif
86 
87 //=============================================================================
88 // Standard constructor, initializes variables
89 //=============================================================================
90 Time::Time( int year, int month, int day, int hour, int min, int sec, ValueType nsecs, bool local /* = true */ ) {
91  tm val;
92  memset( &val, 0, sizeof( val ) );
93  val.tm_sec = sec;
94  val.tm_min = min;
95  val.tm_hour = hour;
96  val.tm_mday = day;
97  val.tm_mon = month;
98  val.tm_year = year > 1900 ? year - 1900 : year;
99  val.tm_isdst = -1; // FIXME?
100 
101  m_nsecs = build( local, val, nsecs ).m_nsecs;
102 }
103 
104 #ifdef WIN32
105 
107 Time Time::from( const FILETIME* systime ) {
108  ValueType t = ( (ValueType)systime->dwHighDateTime << 32 ) + (ValueType)systime->dwLowDateTime;
109 
110  if ( t )
111  // Subtract bias (1970--1601 in 100ns), then convert to nanoseconds.
112  t = ( t - SECS_1601_TO_1970 * ( SEC_NSECS / 100 ) ) * 100;
113 
114  return Time( t );
115 }
116 #endif
117 
120 #ifdef WIN32
121  FILETIME ftime;
122  GetSystemTimeAsFileTime( &ftime );
123  return from( &ftime );
124 #else
125  timeval tv;
126  if ( gettimeofday( &tv, nullptr ) != 0 ) {
127  char buf[256];
128  std::ostringstream tag, msg;
129  tag << "errno=" << errno;
130  if ( strerror_r( errno, buf, 256 ) == 0 ) {
131  msg << buf;
132  } else {
133  msg << "Unknown error retrieving current time";
134  }
135  throw GaudiException( msg.str(), tag.str(), StatusCode::FAILURE );
136  }
137  return Time( tv.tv_sec, tv.tv_usec * 1000 );
138 #endif
139 }
140 
142 Time Time::build( bool local, const tm& base, TimeSpan diff /* = 0 */ ) {
143  tm tmp( base );
144  return Time( local ? mktime( &tmp ) : timegm( &tmp ), 0 ) + diff;
145 }
146 
151 tm Time::split( bool local, int* nsecpart /* = 0 */ ) const {
152  if ( nsecpart ) *nsecpart = (int)( m_nsecs % SEC_NSECS );
153 
154  time_t val = (time_t)( m_nsecs / SEC_NSECS );
155 
156  tm retval;
157  if ( local )
158  localtime_r( &val, &retval );
159  else
160  gmtime_r( &val, &retval );
161 
162  return retval;
163 }
164 
168 tm Time::utc( int* nsecpart /* = 0 */ ) const { return split( false, nsecpart ); }
169 
173 tm Time::local( int* nsecpart /* = 0 */ ) const { return split( true, nsecpart ); }
174 
176 int Time::year( bool local ) const { return split( local ).tm_year + 1900; }
177 
179 int Time::month( bool local ) const { return split( local ).tm_mon; }
180 
182 int Time::day( bool local ) const { return split( local ).tm_mday; }
183 
185 int Time::hour( bool local ) const { return split( local ).tm_hour; }
186 
188 int Time::minute( bool local ) const { return split( local ).tm_min; }
189 
193 int Time::second( bool local ) const { return split( local ).tm_sec; }
194 
198 int Time::nsecond( void ) const { return (int)( m_nsecs % SEC_NSECS ); }
199 
201 int Time::weekday( bool local ) const { return split( local ).tm_wday; }
202 
206 bool Time::isdst( bool local ) const { return split( local ).tm_isdst > 0; }
207 
214 Time::ValueType Time::utcoffset( int* daylight /* = 0 */ ) const {
215  ValueType n = 0;
216 
217 #ifndef WIN32
218  tm localtm = local();
219  n = localtm.tm_gmtoff;
220  if ( daylight ) *daylight = localtm.tm_isdst;
221 #else
222  // Adapted from WINE.
223  time_t utctime = (time_t)( m_nsecs / SEC_NSECS );
224  tm localtm;
225  localtime_s( &localtm, &utctime );
226  int savedaylight = localtm.tm_isdst;
227  tm gmt;
228  gmtime_s( &gmt, &utctime );
229 
230  gmt.tm_isdst = savedaylight;
231  n = utctime - mktime( &gmt );
232 
233  if ( daylight ) *daylight = savedaylight;
234 #endif
235  return n * SEC_NSECS;
236 }
237 
238 #ifdef WIN32
239 // disable warning
240 // C4996: 'tzname': This function or variable may be unsafe.
241 # pragma warning( push )
242 # pragma warning( disable : 4996 )
243 #endif
244 
248 const char* Time::timezone( int* daylight /* = 0 */ ) const {
249  tm localtm = local();
250  if ( daylight ) *daylight = localtm.tm_isdst;
251  // extern "C" { extern char *tzname [2]; }
252  return tzname[localtm.tm_isdst > 0 ? 1 : 0];
253 }
254 #ifdef WIN32
255 # pragma warning( pop )
256 #endif
257 
262 std::string Time::format( bool local, std::string spec ) const {
264  std::string result;
265  tm time = split( local );
266  std::string::size_type length = 0;
267 
268  // handle the special case of "%f"
269  std::string::size_type pos = spec.find( "%f" );
270  if ( std::string::npos != pos ) {
271  // Get the milliseconds string
272  std::string ms = nanoformat( 3, 3 );
273  // Replace all the occurrences of '%f' (if not preceded by '%')
274  while ( std::string::npos != pos ) {
275  if ( pos != 0 && spec[pos - 1] != '%' ) { spec.replace( pos, 2, ms ); }
276  pos = spec.find( "%f", pos + 1 ); // search for the next occurrence
277  }
278  }
279  const int MIN_BUF_SIZE = 128;
280  do {
281  // Guess how much we'll expand. If we go wrong, we'll expand again. (with a minimum)
282  result.resize( std::max<std::string::size_type>(
283  result.size() * 2, std::max<std::string::size_type>( spec.size() * 2, MIN_BUF_SIZE ) ),
284  0 );
285  length = ::strftime( &result[0], result.size(), spec.c_str(), &time );
286  } while ( !length );
287 
288  result.resize( length );
289  return result;
290 }
291 
302 std::string Time::nanoformat( size_t minwidth /* = 1 */, size_t maxwidth /* = 9 */ ) const {
303  TimeAssert( ( minwidth >= 1 ) && ( minwidth <= maxwidth ) && ( maxwidth <= 9 ),
304  "nanoformat options do not satisfy: 1 <= minwidth <= maxwidth <= 9" );
305 
306  // Calculate the nanosecond fraction. This will be < 1000000000.
307  int value = (int)( m_nsecs % SEC_NSECS );
308 
309  std::ostringstream buf;
310  (void)buf.fill( '0' );
311  buf.width( 9 );
312  buf << value;
313  std::string out = buf.str();
314  // Find the last non-0 char before maxwidth, but after minwidth
315  // (Note: -1 and +1 are to account for difference between position and size.
316  // moreover, npos + 1 == 0, so it is correct to say that 'not found' means size of 0)
317  size_t len = out.find_last_not_of( '0', maxwidth - 1 ) + 1;
318  // Truncate the output string to at least minwidth chars
319  out.resize( std::max( len, minwidth ) );
320  return out;
321 }
322 
324 
325 unsigned Time::toDosDate( Time time ) {
326  // Use local time since DOS does too.
327  struct tm localtm = time.local();
328 
329  unsigned mday = localtm.tm_mday;
330  unsigned mon = localtm.tm_mon + 1;
331  unsigned year = ( localtm.tm_year > 80 ? localtm.tm_year - 80 : 0 );
332  unsigned sec = localtm.tm_sec / 2;
333  unsigned min = localtm.tm_min;
334  unsigned hour = localtm.tm_hour;
335  return ( mday << 16 | mon << 21 | year << 25 | sec | min << 5 | hour << 11 );
336 }
337 
339 Time Time::fromDosDate( unsigned dosDate ) {
340  // DOS times are generally local; treat it as UTC. This avoids
341  // any round-trip conversion and leaves only a presentation as an
342  // issue. Since not much can be known about the origin of the DOS
343  // times, it's generally best to present them as such (= in UTC).
344  struct tm localtm;
345  memset( &localtm, 0, sizeof( localtm ) );
346  localtm.tm_mday = ( dosDate >> 16 ) & 0x1f;
347  localtm.tm_mon = ( ( dosDate >> 21 ) & 0xf ) - 1;
348  localtm.tm_year = ( ( dosDate >> 25 ) & 0x7f ) + 80;
349  localtm.tm_hour = ( dosDate >> 11 ) & 0x1f;
350  localtm.tm_min = ( dosDate >> 5 ) & 0x3f;
351  localtm.tm_sec = ( dosDate & 0x1f ) * 2;
352  localtm.tm_isdst = -1;
353 
354  return Time( mktime( &localtm ), 0 );
355 }
356 
357 //=============================================================================
std::ostringstream::width
T width(T... args)
std::mktime
T mktime(T... args)
std::string::resize
T resize(T... args)
Gaudi::Time::isdst
bool isdst(bool local) const
Check whether daylight savings is in effect.
Definition: Time.cpp:206
std::string
STL class.
Gaudi::Time::year
int year(bool local) const
Get the year.
Definition: Time.cpp:176
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:193
std::string::find
T find(T... args)
std::string::size
T size(T... args)
GaudiException
Definition: GaudiException.h:31
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:302
Gaudi::Time::timezone
const char * timezone(int *daylight=0) const
Return the local timezone name that applies at this time value.
Definition: Time.cpp:248
Gaudi::Time::m_nsecs
ValueType m_nsecs
Definition: Time.h:338
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:214
Gaudi::Time
Definition: Time.h:241
std::ostringstream::fill
T fill(T... args)
std::string::replace
T replace(T... args)
Gaudi::Units::ms
constexpr double ms
Definition: SystemOfUnits.h:154
Gaudi::TimeSpan
Definition: Time.h:62
bug_34121.t
t
Definition: bug_34121.py:31
Gaudi::Time::minute
int minute(bool local) const
Get the minute, numbered [0, 59].
Definition: Time.cpp:188
Gaudi::Time::format
std::string format(bool local, std::string spec="%c") const
Format the time using strftime.
Definition: Time.cpp:262
Gaudi::Time::toDosDate
static unsigned toDosDate(Time time)
Convert the Time t into a MS-DOS date format.
Definition: Time.cpp:325
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:151
TemplatedAlg
Definition: TemplatedAlg.cpp:22
std::string::c_str
T c_str(T... args)
Gaudi::Time::ValueType
long long ValueType
Definition: Time.h:245
time_r.h
Gaudi::Time::hour
int hour(bool local) const
Get the hour, numbered [0, 23].
Definition: Time.cpp:185
Gaudi::Time::weekday
int weekday(bool local) const
Get the day of week, numbered [0,6] and starting from Sunday.
Definition: Time.cpp:201
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
std::ostringstream
STL class.
Time.h
Gaudi::Time::SEC_NSECS
static const ValueType SEC_NSECS
Nanoseconds in one second.
Definition: Time.h:270
Gaudi::Time::current
static Time current()
Returns the current time.
Definition: Time.cpp:119
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:173
Gaudi::Time::month
int month(bool local) const
Get the month, numbered [0,11].
Definition: Time.cpp:179
Gaudi::Time::TimeAssert
void TimeAssert(bool cond, std::string_view msg="time assertion failed") const
Definition: Time.h:341
std::ostringstream::str
T str(T... args)
check_ParticleID.base
base
Definition: check_ParticleID.py:24
t2
TemplatedAlg< double, bool > t2
Definition: TemplatedAlg.cpp:41
Gaudi::Time::nsecond
int nsecond() const
Get the nanoseconds.
Definition: Time.cpp:198
Gaudi::Time::day
int day(bool local) const
Get the day of month, numbered [1,31].
Definition: Time.cpp:182
StatusCode::FAILURE
constexpr static const auto FAILURE
Definition: StatusCode.h:101
Gaudi::Time::fromDosDate
static Time fromDosDate(unsigned dosDate)
Convert the MS-DOS date dosDate into a Time.
Definition: Time.cpp:339
std::max
T max(T... args)
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:168
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:142
PrepareBase.out
out
Definition: PrepareBase.py:20