The Gaudi Framework  master (b9786168)
Loading...
Searching...
No Matches
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 <sys/time.h>
17
18using namespace Gaudi;
19
20//-----------------------------------------------------------------------------
21// Implementation file for class : Gaudi::Time
22// Based on seal::Time
23// 2005-12-15 : Marco Clemencic
24//-----------------------------------------------------------------------------
25
26Time::Time( int year, int month, int day, int hour, int min, int sec, ValueType nsecs, bool local /* = true */ ) {
27 tm val;
28 memset( &val, 0, sizeof( val ) );
29 val.tm_sec = sec;
30 val.tm_min = min;
31 val.tm_hour = hour;
32 val.tm_mday = day;
33 val.tm_mon = month;
34 val.tm_year = year > 1900 ? year - 1900 : year;
35 val.tm_isdst = -1; // FIXME?
36
37 m_nsecs = build( local, val, nsecs ).m_nsecs;
38}
39
42 timeval tv;
43 if ( gettimeofday( &tv, nullptr ) != 0 ) {
44 char buf[256];
45 std::ostringstream tag, msg;
46 tag << "errno=" << errno;
47 if ( strerror_r( errno, buf, 256 ) == 0 ) {
48 msg << buf;
49 } else {
50 msg << "Unknown error retrieving current time";
51 }
52 throw GaudiException( msg.str(), tag.str(), StatusCode::FAILURE );
53 }
54 return Time( tv.tv_sec, tv.tv_usec * 1000 );
55}
56
58Time Time::build( bool local, const tm& base, TimeSpan diff /* = 0 */ ) {
59 tm tmp( base );
60 return Time( local ? mktime( &tmp ) : timegm( &tmp ), 0 ) + diff;
61}
62
67tm Time::split( bool local, int* nsecpart /* = 0 */ ) const {
68 if ( nsecpart ) *nsecpart = (int)( m_nsecs % SEC_NSECS );
69
70 time_t val = (time_t)( m_nsecs / SEC_NSECS );
71
72 tm retval;
73 if ( local )
74 localtime_r( &val, &retval );
75 else
76 gmtime_r( &val, &retval );
77
78 return retval;
79}
80
84tm Time::utc( int* nsecpart /* = 0 */ ) const { return split( false, nsecpart ); }
85
89tm Time::local( int* nsecpart /* = 0 */ ) const { return split( true, nsecpart ); }
90
92int Time::year( bool local ) const { return split( local ).tm_year + 1900; }
93
95int Time::month( bool local ) const { return split( local ).tm_mon; }
96
98int Time::day( bool local ) const { return split( local ).tm_mday; }
99
101int Time::hour( bool local ) const { return split( local ).tm_hour; }
102
104int Time::minute( bool local ) const { return split( local ).tm_min; }
105
109int Time::second( bool local ) const { return split( local ).tm_sec; }
110
114int Time::nsecond( void ) const { return (int)( m_nsecs % SEC_NSECS ); }
115
117int Time::weekday( bool local ) const { return split( local ).tm_wday; }
118
122bool Time::isdst( bool local ) const { return split( local ).tm_isdst > 0; }
123
130Time::ValueType Time::utcoffset( int* daylight /* = 0 */ ) const {
131 ValueType n = 0;
132
133 tm localtm = local();
134 n = localtm.tm_gmtoff;
135 if ( daylight ) *daylight = localtm.tm_isdst;
136
137 return n * SEC_NSECS;
138}
139
144const char* Time::timezone( int* daylight /* = 0 */ ) const {
145 tm localtm = local();
146 if ( daylight ) *daylight = localtm.tm_isdst;
147 // extern "C" { extern char *tzname [2]; }
148 return tzname[localtm.tm_isdst > 0 ? 1 : 0];
149}
150
155std::string Time::format( bool local, std::string spec ) const {
157 std::string result;
158 tm time = split( local );
159 std::string::size_type length = 0;
160
161 // handle the special case of "%f"
162 std::string::size_type pos = spec.find( "%f" );
163 if ( std::string::npos != pos ) {
164 // Get the milliseconds string
165 std::string ms = nanoformat( 3, 3 );
166 // Replace all the occurrences of '%f' (if not preceded by '%')
167 while ( std::string::npos != pos ) {
168 if ( pos != 0 && spec[pos - 1] != '%' ) { spec.replace( pos, 2, ms ); }
169 pos = spec.find( "%f", pos + 1 ); // search for the next occurrence
170 }
171 }
172 const std::size_t MIN_BUF_SIZE = 128;
173 do {
174 // Guess how much we'll expand. If we go wrong, we'll expand again. (with a minimum)
175 result.resize( std::max( result.size() * 2, std::max( spec.size() * 2, MIN_BUF_SIZE ) ), 0 );
176 length = ::strftime( &result[0], result.size(), spec.c_str(), &time );
177 } while ( !length );
178
179 result.resize( length );
180 return result;
181}
182
193std::string Time::nanoformat( size_t minwidth /* = 1 */, size_t maxwidth /* = 9 */ ) const {
194 TimeAssert( ( minwidth >= 1 ) && ( minwidth <= maxwidth ) && ( maxwidth <= 9 ),
195 "nanoformat options do not satisfy: 1 <= minwidth <= maxwidth <= 9" );
196
197 // Calculate the nanosecond fraction. This will be < 1000000000.
198 int value = (int)( m_nsecs % SEC_NSECS );
199
200 std::ostringstream buf;
201 (void)buf.fill( '0' );
202 buf.width( 9 );
203 buf << value;
204 std::string out = buf.str();
205 // Find the last non-0 char before maxwidth, but after minwidth
206 // (Note: -1 and +1 are to account for difference between position and size.
207 // moreover, npos + 1 == 0, so it is correct to say that 'not found' means size of 0)
208 size_t len = out.find_last_not_of( '0', maxwidth - 1 ) + 1;
209 // Truncate the output string to at least minwidth chars
210 out.resize( std::max( len, minwidth ) );
211 return out;
212}
213
215unsigned Time::toDosDate( Time time ) {
216 // Use local time since DOS does too.
217 struct tm localtm = time.local();
218
219 unsigned mday = localtm.tm_mday;
220 unsigned mon = localtm.tm_mon + 1;
221 unsigned year = ( localtm.tm_year > 80 ? localtm.tm_year - 80 : 0 );
222 unsigned sec = localtm.tm_sec / 2;
223 unsigned min = localtm.tm_min;
224 unsigned hour = localtm.tm_hour;
225 return ( mday << 16 | mon << 21 | year << 25 | sec | min << 5 | hour << 11 );
226}
227
229Time Time::fromDosDate( unsigned dosDate ) {
230 // DOS times are generally local; treat it as UTC. This avoids
231 // any round-trip conversion and leaves only a presentation as an
232 // issue. Since not much can be known about the origin of the DOS
233 // times, it's generally best to present them as such (= in UTC).
234 struct tm localtm;
235 memset( &localtm, 0, sizeof( localtm ) );
236 localtm.tm_mday = ( dosDate >> 16 ) & 0x1f;
237 localtm.tm_mon = ( ( dosDate >> 21 ) & 0xf ) - 1;
238 localtm.tm_year = ( ( dosDate >> 25 ) & 0x7f ) + 80;
239 localtm.tm_hour = ( dosDate >> 11 ) & 0x1f;
240 localtm.tm_min = ( dosDate >> 5 ) & 0x3f;
241 localtm.tm_sec = ( dosDate & 0x1f ) * 2;
242 localtm.tm_isdst = -1;
243
244 return Time( mktime( &localtm ), 0 );
245}
tm local(int *nsecpart=0) const
Break up the time to the standard library representation, converting it first to local time.
Definition Time.cpp:89
int hour(bool local) const
Get the hour, numbered [0, 23].
Definition Time.cpp:101
std::string nanoformat(std::size_t minwidth=1, std::size_t maxwidth=9) const
Format the nanosecond fractional part of the time as a string.
Definition Time.cpp:193
std::int64_t ValueType
Definition Time.h:236
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:58
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:109
friend class TimeSpan
Definition Time.h:233
int month(bool local) const
Get the month, numbered [0,11].
Definition Time.cpp:95
const char * timezone(int *daylight=0) const
Return the local timezone name that applies at this time value.
Definition Time.cpp:144
int weekday(bool local) const
Get the day of week, numbered [0,6] and starting from Sunday.
Definition Time.cpp:117
int nsecond() const
Get the nanoseconds.
Definition Time.cpp:114
std::string format(bool local, std::string spec="%c") const
Format the time using strftime.
Definition Time.cpp:155
int minute(bool local) const
Get the minute, numbered [0, 59].
Definition Time.cpp:104
static Time fromDosDate(unsigned dosDate)
Convert the MS-DOS date dosDate into a Time.
Definition Time.cpp:229
bool isdst(bool local) const
Check whether daylight savings is in effect.
Definition Time.cpp:122
Time()=default
Initialize an empty (zero) time value.
int year(bool local) const
Get the year.
Definition Time.cpp:92
tm utc(int *nsecpart=0) const
Break up the time to the standard library representation, keeping it in UTC.
Definition Time.cpp:84
ValueType m_nsecs
Definition Time.h:317
static Time current()
Returns the current time.
Definition Time.cpp:41
int day(bool local) const
Get the day of month, numbered [1,31].
Definition Time.cpp:98
static constexpr ValueType SEC_NSECS
Nanoseconds in one second.
Definition Time.h:261
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:130
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:67
void TimeAssert(bool cond, std::string_view msg="time assertion failed") const
Definition Time.h:320
static unsigned toDosDate(Time time)
Convert the Time t into a MS-DOS date format.
Definition Time.cpp:215
Define general base for Gaudi exception.
constexpr static const auto FAILURE
Definition StatusCode.h:100
This file provides a Grammar for the type Gaudi::Accumulators::Axis It allows to use that type from p...
Definition __init__.py:1