|
Gaudi Framework, version v21r11 |
| Home | Generated: 30 Sep 2010 |
#include <GaudiKernel/Time.h>
Public Types | |
| enum | Months { January = 0, February = 1, March = 2, April = 3, May = 4, June = 5, July = 6, August = 7, September = 8, October = 9, November = 10, December = 11 } |
| Symbolic names for months. More... | |
| typedef longlong | ValueType |
Public Member Functions | |
| Time (void) | |
| Initialize an empty (zero) time value. | |
| Time (TimeSpan ts) | |
| Initialize time to ts nanoseconds since 00:00:00 on January 1, 1970 in UTC. | |
| Time (ValueType nsecs) | |
| Initialize time to nsecs nanoseconds since 00:00:00 on January 1, 1970 in UTC. | |
| Time (ValueType secs, int nsecs) | |
| Initialize time to secs (seconds) and nsecs (nanoseconds) summed since 00:00:00 on January 1, 1970 in UTC. | |
| Time (int year, int month, int day, int hour, int min, int sec, ValueType nsecs, bool local=true) | |
| 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 local is true). | |
| tm | utc (int *nsecpart=0) const |
| Break up the time to the standard library representation, keeping it in UTC. | |
| tm | local (int *nsecpart=0) const |
| Break up the time to the standard library representation, converting it first to local time. | |
| int | year (bool local) const |
| Get the year. | |
| int | month (bool local) const |
| Get the month, numbered [0,11]. | |
| int | day (bool local) const |
| Get the day of month, numbered [1,31]. | |
| int | hour (bool local) const |
| Get the hour, numbered [0, 23]. | |
| int | minute (bool local) const |
| Get the minute, numbered [0, 59]. | |
| int | second (bool local) const |
| Get the seconds, numbered [0,61] (allowing one or two leap seconds, years with leap seconds can have the time Dec 31, 23:59:60 (or :61). | |
| int | nsecond (void) const |
| Get the nanoseconds. | |
| int | weekday (bool local) const |
| Get the day of week, numbered [0,6] and starting from Sunday. | |
| bool | isdst (bool local) const |
| Check whether daylight savings is in effect. | |
| 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 time (= nanoseconds east of UTC). | |
| const char * | timezone (int *daylight=0) const |
| Return the local timezone name that applies at this time value. | |
| Time & | operator+= (const TimeSpan &x) |
| Add the specified amount to the time. | |
| Time & | operator-= (const TimeSpan &x) |
| Subtract the specified amount from the time. | |
| ValueType | ns (void) const |
| Return the time as nanoseconds since 00:00:00 on January 1, 1970 in UTC. | |
| std::string | format (bool local, const std::string &spec) const |
Format the time using strftime. | |
| std::string | nanoformat (int minwidth=1, int maxwidth=9) const |
| Format the nanosecond fractional part of the time as a string. | |
Static Public Member Functions | |
| static Time | epoch (void) |
| Returns the minimum time. | |
| static Time | max (void) |
| Returns the maximum time. | |
| static Time | current (void) |
| Returns the current time. | |
| static Time | build (bool local, const tm &base, TimeSpan diff=0) |
| Construct a time from local time base and a delta diff. | |
| static bool | isLeap (int year) |
| Check if the year is a leap-year. | |
| static unsigned | toDosDate (Time time) |
| Convert the Time t into a MS-DOS date format. | |
| static Time | fromDosDate (unsigned dosDate) |
| Convert the MS-DOS date dosDate into a Time. | |
Static Public Attributes | |
| static const int | SECS_PER_DAY = 86400 |
| Seconds in 24 hours. | |
| static const int | SECS_PER_HOUR = 3600 |
| Seconds in one hour hour. | |
| static const ValueType | SEC_NSECS = 1000000000 |
| Nanoseconds in one second. | |
Private Member Functions | |
| void | TimeAssert (bool cond, const std::string &msg="time assertion failed") const |
Private Attributes | |
| ValueType | m_nsecs |
Friends | |
| class | TimeSpan |
Calendar time in nanoseconds since 00:00:00 on January 1, 1970, Coordinated Universal Time (UTC).
Time is represented internally as UTC time, but it can also be converted to the local time as necessary. Most methods take an argument flag local to indicate which time interpretation is desired by the client, and automatically perform the necessary adjustments. The client can also find out about the difference between UTC time and local time using the utcoffset() method, and the time zone name with timezone() method. Both allow the client to discover whether daylight savings is in effect.
The native representation of Time is not well suited for human handling of time. Time provides access in more convenient terms such as year(), month() and day(); more are available through conversion into a TimeSpan. Time can also be converted to and from ISO C standard tm structure. Note however that unlike C's mktime() which always assumes tm in local time, Time fully supports all conversions between local and universal time. Thus it is possible for example to build() a UTC time directly from a tm.
Time behaves as an integral type. Differences in time values are represented as a TimeSpan. Usual integral arithmetic works with both types. Output works in general as any other integral type, however since the ValueType can be a wide type, it may be poorly supported by the iostream; if so, including the LongLong.h header will help. Note that the output value will usually be very large as Time is represented in nanoseconds, not seconds! When constructing Time values in seconds, such as when reading in, do remember to use the two-argument constructor taking seconds and nanoseconds instead of the default single-argument one.
Time can be formatted into a string using the format() method, which uses the versatile strftime() function. Since the latter works on seconds at best (through a struct tm), the subsecond part cannot be formatted; the nanoformat() method is provided to overcome this limitation. To combine format() and nanoformat() output use a suitable StringFormat pattern.
Time is linked to the system's concept of calendar time and is therefore may not be linear nor monotonic. System time can jump arbitrarily in either direction as real time clock is corrected or the system is suspended. The local time may also jump due to daylight savings. The process' ability to sample system time can be limited for reasons such as getting swapped out. TimeInfo provides an alternative time measurement facility not linked to calendar and guaranteed to grow monotonically -- though not always linearly. Note that few systems actually provide wall-clock time in nanosecond resolution. Not all system provide an interface to get time at that resolution, let alone track it so precisely.
Because of the time warp issues, scheduling events using Time is not straightforward. Application code should understand whether it is dealing with concrete or abstract calendar calculations, and how the events it schedules are linked to wall clock time.
For calculations on concrete calendar as perceived by people use local() after plain Time and TimeSpan integer arithmetic. The method accounts for timezone and daylight savings definitions. To schedule events use build() to derive times from local() time to get values comparable to the system time returned by current(). The applications should know whether events are scheduled in UTC or local time---"meeting at 9:00 on Wednesday morning" when the device switches timezones may be known to be at 9:00 in the new timezone (= locked to local time), or in the timezone where the event was created (= locked to UTC). The build() and split() methods allow either format to be used, the application just needs to know which one to use. It is also easy to convert between the two using utcoffset().
For calculations using an abstract calendar, without timezone or daylight savings, use Time in its native UTC representation and integer arithmetic with Time and TimeSpan. Do note however that "T + 24 hours" may not be the same hour the next day in the local calendar time -- timezone changes and daylight savings make a difference. This may require the application to accept as user input exception rules to its usual calendar calculations.
To schedule events, one should choose between three choices: UTC time, local time, or delta time. For the first two cases system time should be polled regularly to see if any of the recorded events have expired. It is not a good idea to sleep until the next scheduled event, as the system time may jump during the nap; instead sleep small increments, recheck the current time after each nap and trigger the events that have expired. A policy must be applied when the system time warps; this can happen both forwards and backwards with both local and UTC time (daylight savings or timezone changes for mobile devices are common local time change reasons, but the system time can be updated for any reason, e.g. when the real time clock is wrong, or if the system is suspended for a long time). Some events should be executed only once in case of time warps backwards. If the time jumps forwards, several events may need to be dealt with in one go. In either case the application should guard against major time changes: long system suspends, moving mobile devices and major time updates may result in a large number of "missed" events. One possibility is to provide a user-configurable "excessive time drift limit" (e.g. N hours): if time changes by more than that, missed events are not triggered.
For the final case of using delta times, sort upcoming events by their deltas from the previous event---not by the time they are anticipated to occur. Capture current time before and after the sleep and pull events off the queue based on the difference (the sleep time may exceed the requested time). Either guard against long time warps like suspends or schedule timer events cautiously. Using TimeInfo as schedule base solves such issues simply. To cope with backward system time jumps when using Time as schedule base, assume that sleeps always last at least the requested time; if the time delta over the nap is less than the requested, assume time warp (this is not foolproof against interrupted system calls but works for many event scheduling situations).
Definition at line 214 of file Time.h.
| enum Gaudi::Time::Months |
Symbolic names for months.
Definition at line 220 of file Time.h.
00220 { 00221 January = 0, 00222 February = 1, 00223 March = 2, 00224 April = 3, 00225 May = 4, 00226 June = 5, 00227 July = 6, 00228 August = 7, 00229 September = 8, 00230 October = 9, 00231 November = 10, 00232 December = 11 00233 };
| Gaudi::Time::Time | ( | void | ) | [inline] |
| Gaudi::Time::Time | ( | TimeSpan | ts | ) | [inline] |
Initialize time to ts nanoseconds since 00:00:00 on January 1, 1970 in UTC.
Definition at line 20 of file Time.icpp.
00020 : m_nsecs(ts.m_nsecs) { 00021 TimeAssert( m_nsecs >= 0, "cannot create a negative time"); 00022 }
| Gaudi::Time::Time | ( | ValueType | nsecs | ) | [inline] |
Initialize time to nsecs nanoseconds since 00:00:00 on January 1, 1970 in UTC.
Definition at line 14 of file Time.icpp.
00014 : m_nsecs(nsecs) { 00015 TimeAssert( m_nsecs >= 0, "cannot create a negative time"); 00016 }
| Gaudi::Time::Time | ( | ValueType | secs, | |
| int | nsecs | |||
| ) | [inline] |
Initialize time to secs (seconds) and nsecs (nanoseconds) summed since 00:00:00 on January 1, 1970 in UTC.
Definition at line 26 of file Time.icpp.
00027 : m_nsecs(secs * Time::SEC_NSECS + nsecs) { 00028 TimeAssert( m_nsecs >= 0, "cannot create a negative time"); 00029 }
| Time::Time | ( | int | year, | |
| int | month, | |||
| int | day, | |||
| int | hour, | |||
| int | min, | |||
| int | sec, | |||
| ValueType | nsecs, | |||
| bool | local = true | |||
| ) |
Definition at line 78 of file Time.cpp.
00081 { 00082 tm val; 00083 memset (&val, sizeof (val), 0); 00084 val.tm_sec = sec; 00085 val.tm_min = min; 00086 val.tm_hour = hour; 00087 val.tm_mday = day; 00088 val.tm_mon = month; 00089 val.tm_year = year > 1900 ? year - 1900 : year; 00090 val.tm_isdst = -1; // FIXME? 00091 00092 m_nsecs = build (local, val, nsecs).m_nsecs; 00093 }
| Time Gaudi::Time::epoch | ( | void | ) | [inline, static] |
| Time Gaudi::Time::max | ( | void | ) | [inline, static] |
| Time Time::current | ( | void | ) | [static] |
Returns the current time.
Return the current system time.
Definition at line 111 of file Time.cpp.
00111 { 00112 #ifdef WIN32 00113 FILETIME ftime; 00114 GetSystemTimeAsFileTime (&ftime); 00115 return from (&ftime); 00116 #else 00117 timeval tv; 00118 if (gettimeofday (&tv, 0) != 0) { 00119 char buf[256]; 00120 std::ostringstream tag,msg; 00121 tag << "errno=" << errno; 00122 if( strerror_r(errno, buf, 256) == 0 ) { 00123 msg << buf; 00124 } else { 00125 msg << "Unknown error retriving current time"; 00126 } 00127 throw GaudiException(msg.str(),tag.str(),StatusCode::FAILURE); 00128 } 00129 return Time (tv.tv_sec, tv.tv_usec * 1000); 00130 #endif 00131 }
| tm Time::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 local is true).
If nsecpart is non-null, it is set to the nanosecond part that cannot be stored into tm.
Definition at line 143 of file Time.cpp.
00143 { 00144 if (nsecpart) 00145 *nsecpart = (int)(m_nsecs % SEC_NSECS); 00146 00147 time_t val = (time_t)(m_nsecs / SEC_NSECS); 00148 return *(local ? localtime (&val) : gmtime (&val)); 00149 }
| tm Time::utc | ( | int * | nsecpart = 0 |
) | const |
| tm Time::local | ( | int * | nsecpart = 0 |
) | const |
| int Time::year | ( | bool | local | ) | const |
| int Time::month | ( | bool | local | ) | const |
| int Time::day | ( | bool | local | ) | const |
| int Time::hour | ( | bool | local | ) | const |
| int Time::minute | ( | bool | local | ) | const |
| int Time::second | ( | bool | local | ) | const |
| int Time::nsecond | ( | void | ) | const |
| int Time::weekday | ( | bool | local | ) | const |
| bool Time::isdst | ( | bool | local | ) | const |
| Time::ValueType Time::utcoffset | ( | int * | daylight = 0 |
) | const |
Return the number of nanoseconds that needs to be added to UTC to translate this time to the local time (= nanoseconds east of UTC).
This accounts for the time zone and daylight savings settings of the local time as of the current value. If daylight is non-null, it is set to indicate daylight savings status (that is, tm.tm_isdst for the effective local time).
Definition at line 222 of file Time.cpp.
00222 { 00223 ValueType n = 0; 00224 00225 #ifndef WIN32 00226 tm localtm = local (); 00227 n = localtm.tm_gmtoff; 00228 if (daylight) *daylight = localtm.tm_isdst; 00229 #else 00230 // Adapted from WINE. 00231 time_t utctime = (time_t)(m_nsecs / SEC_NSECS); 00232 tm localtm = *localtime (&utctime); 00233 int savedaylight = localtm.tm_isdst; 00234 tm gmt = *gmtime (&utctime); 00235 00236 gmt.tm_isdst = savedaylight; 00237 n = utctime - mktime (&gmt); 00238 00239 if (daylight) *daylight = savedaylight; 00240 #endif 00241 return n * SEC_NSECS; 00242 }
| const char * Time::timezone | ( | int * | daylight = 0 |
) | const |
Return the local timezone name that applies at this time value.
On some platforms returns the most recent timezone name (dst or non-dst one depending on the time value), not the one that applies at the time value.
Definition at line 248 of file Time.cpp.
00248 { 00249 tm localtm = local (); 00250 if (daylight) *daylight = localtm.tm_isdst; 00251 // extern "C" { extern char *tzname [2]; } 00252 return tzname [localtm.tm_isdst > 0 ? 1 : 0]; 00253 }
Add the specified amount to the time.
Note that Time is always expressed in UTC.
Definition at line 39 of file Time.icpp.
00039 { 00040 TimeAssert( m_nsecs >= -x.m_nsecs, "time operation lead to negative time"); 00041 m_nsecs += x.m_nsecs; 00042 return *this; 00043 }
Subtract the specified amount from the time.
Note that Time is always expressed in UTC.
Definition at line 47 of file Time.icpp.
00047 { 00048 TimeAssert( m_nsecs >= x.m_nsecs, "time operation lead to negative time"); 00049 m_nsecs -= x.m_nsecs; 00050 return *this; 00051 }
| Time::ValueType Gaudi::Time::ns | ( | void | ) | const [inline] |
| std::string Time::format | ( | bool | local, | |
| const std::string & | spec | |||
| ) | const |
Format the time using strftime.
Definition at line 256 of file Time.cpp.
00256 { 00257 // FIXME: This doesn't account for nsecs part! 00258 std::string result; 00259 tm time = split (local); 00260 int length = 0; 00261 00262 do 00263 { 00264 // Guess how much we'll expand. If we go wrong, we'll expand again. 00265 result.resize (result.size() ? result.size()*2 : spec.size()*2, 0); 00266 length = ::strftime (&result[0], result.size(), spec.c_str(), &time); 00267 } while (! length); 00268 00269 result.resize (length); 00270 return result; 00271 }
| std::string Time::nanoformat | ( | int | minwidth = 1, |
|
| int | maxwidth = 9 | |||
| ) | const |
Format the nanosecond fractional part of the time as a string.
The arguments control the representation of the resulting value. The nanosecond part is printed as fixed nine-character-wide number and then excess zeroes are stripped off at the right end. Use minwidth to force a specific number number of them to be left intact: the resulting number will have at least that many digits. Use maxwidth to truncate the value: the resulting number will have at most that many digits. Both minwidth and maxwidth must be between one and nine inclusive and minwidth must be less or equal to maxwidth.
Definition at line 283 of file Time.cpp.
00283 { 00284 TimeAssert( (minwidth >= 1) && (minwidth <= maxwidth) && (maxwidth <= 9), 00285 "nanoformat options do not satisfy: 1 <= minwidth <= maxwidth <= 9"); 00286 00287 // Calculate the nanosecond fraction. This will be < 1000000000. 00288 int value = (int)(m_nsecs % SEC_NSECS); 00289 00290 // Calculate modulus by which we truncate value. If maxwidth is 00291 // say 3, we want to mask of the last 6 digits. 00292 int modulus = 1; 00293 for (int i = 0; i < 9 - maxwidth; ++i) 00294 modulus *= 10; 00295 00296 // Round value by the desired modulus. 00297 int rem = value % modulus; 00298 value -= rem; 00299 if (rem > modulus / 2) 00300 value += modulus; 00301 00302 // Format it, then strip off digits from the right as long as 00303 // we zeroes. The above guarantees enough zeroes on right to 00304 // satisfy maxwidth so we need to concern ourselves only about 00305 // minwidth. 00306 char buf [10]; 00307 char *p = buf + 8; 00308 sprintf (buf, "%09d", value); 00309 while (p > buf + minwidth - 1 && *p == '0') 00310 *p-- = '\0'; 00311 00312 return buf; 00313 }
| bool Gaudi::Time::isLeap | ( | int | year | ) | [inline, static] |
| unsigned Time::toDosDate | ( | Time | time | ) | [static] |
Convert the Time t into a MS-DOS date format.
Definition at line 317 of file Time.cpp.
00317 { 00318 // Use local time since DOS does too. 00319 struct tm localtm = time.local (); 00320 00321 unsigned mday = localtm.tm_mday; 00322 unsigned mon = localtm.tm_mon + 1; 00323 unsigned year = (localtm.tm_year > 80 ? localtm.tm_year - 80 : 0); 00324 unsigned sec = localtm.tm_sec / 2; 00325 unsigned min = localtm.tm_min; 00326 unsigned hour = localtm.tm_hour; 00327 return (mday << 16 | mon << 21 | year << 25 00328 | sec | min << 5 | hour << 11); 00329 }
| Time Time::fromDosDate | ( | unsigned | dosDate | ) | [static] |
Convert the MS-DOS date dosDate into a Time.
Definition at line 332 of file Time.cpp.
00332 { 00333 // DOS times are generally local; treat it as UTC. This avoids 00334 // any round-trip conversion and leaves only a presentation as an 00335 // issue. Since not much can be known about the origin of the DOS 00336 // times, it's generally best to present them as such (= in UTC). 00337 struct tm localtm; 00338 memset (&localtm, 0, sizeof (localtm)); 00339 localtm.tm_mday = (dosDate >> 16) & 0x1f; 00340 localtm.tm_mon = ((dosDate >> 21) & 0xf) - 1; 00341 localtm.tm_year = ((dosDate >> 25) & 0x7f) + 80; 00342 localtm.tm_hour = (dosDate >> 11) & 0x1f; 00343 localtm.tm_min = (dosDate >> 5) & 0x3f; 00344 localtm.tm_sec = (dosDate & 0x1f) * 2; 00345 localtm.tm_isdst = -1; 00346 00347 return Time (mktime (&localtm), 0); 00348 }
| void Gaudi::Time::TimeAssert | ( | bool | cond, | |
| const std::string & | msg = "time assertion failed" | |||
| ) | const [inline, private] |
const int Gaudi::Time::SECS_PER_DAY = 86400 [static] |
const int Gaudi::Time::SECS_PER_HOUR = 3600 [static] |
const ValueType Gaudi::Time::SEC_NSECS = 1000000000 [static] |