All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
Time.cpp
Go to the documentation of this file.
1 // $Id: Time.cpp,v 1.1 2006/01/26 09:24:03 hmd Exp $
2 // Include files
3 #include "GaudiKernel/Time.h"
4 
5 #include "GaudiKernel/time_r.h"
6 
7 #include <iostream>
8 #include <cstdio>
9 #include <ctime>
10 #include <cerrno>
11 #include <cstring>
12 
13 // local
14 using namespace Gaudi;
15 
16 // architecture dependent includes
17 #ifdef WIN32
18 
19 // this turns off a lot of useless Win stuff which conflicts with Gaudi. (found empirically)
20 #define NOATOM
21 #define NOGDI
22 #define NOGDICAPMASKS
23 #define NOMETAFILE
24 #define NOMINMAX
25 #define NOMSG
26 #define NOOPENFILE
27 #define NORASTEROPS
28 #define NOSCROLL
29 #define NOSOUND
30 #define NOSYSMETRICS
31 #define NOTEXTMETRIC
32 #define NOWH
33 #define NOCOMM
34 #define NOKANJI
35 #define NOCRYPT
36 #define NOMCX
37 
38 #include <windows.h>
39 
40 #else
41 // Linux
42 
43 #include <sys/time.h>
44 
45 #endif
46 
47 //-----------------------------------------------------------------------------
48 // Implementation file for class : Gaudi::Time
49 // Based on seal::Time
50 // 2005-12-15 : Marco Clemencic
51 //-----------------------------------------------------------------------------
52 
53 #ifdef WIN32
54 
63 //# define SECS_1601_TO_1970 ((369 * 365 + 89) * SECS_PER_DAY)
64 # define SECS_1601_TO_1970 ((369 * 365 + 89) * 86400ui64)
65 #endif
66 
67 #ifdef WIN32
68 static time_t timegm (struct tm *t) {
69  // This code is adapted from wine, samba
70  time_t t1 = mktime (t);
71  struct tm gmt;
72  gmtime_s(&gmt, &t1);
73  time_t t2 = mktime(&gmt);
74  return t1 + (t1 - t2);
75 }
76 #endif
77 
78 //=============================================================================
79 // Standard constructor, initializes variables
80 //=============================================================================
81 Time::Time( int year, int month, int day,
82  int hour, int min, int sec,
83  ValueType nsecs,
84  bool local /* = true */ ) {
85  tm val;
86  memset (&val, 0, sizeof (val));
87  val.tm_sec = sec;
88  val.tm_min = min;
89  val.tm_hour = hour;
90  val.tm_mday = day;
91  val.tm_mon = month;
92  val.tm_year = year > 1900 ? year - 1900 : year;
93  val.tm_isdst = -1; // FIXME?
94 
95  m_nsecs = build (local, val, nsecs).m_nsecs;
96 }
97 
98 #ifdef WIN32
99 
101 Time Time::from (const FILETIME *systime) {
102  ValueType t = ((ValueType) systime->dwHighDateTime << 32)
103  + (ValueType) systime->dwLowDateTime;
104 
105  if (t)
106  // Subtract bias (1970--1601 in 100ns), then convert to nanoseconds.
107  t = (t - SECS_1601_TO_1970 * (SEC_NSECS/100)) * 100;
108 
109  return Time (t);
110 }
111 #endif
112 
115 #ifdef WIN32
116  FILETIME ftime;
117  GetSystemTimeAsFileTime (&ftime);
118  return from (&ftime);
119 #else
120  timeval tv;
121  if (gettimeofday (&tv, 0) != 0) {
122  char buf[256];
123  std::ostringstream tag,msg;
124  tag << "errno=" << errno;
125  if( strerror_r(errno, buf, 256) == 0 ) {
126  msg << buf;
127  } else {
128  msg << "Unknown error retrieving current time";
129  }
130  throw GaudiException(msg.str(),tag.str(),StatusCode::FAILURE);
131  }
132  return Time (tv.tv_sec, tv.tv_usec * 1000);
133 #endif
134 }
135 
137 Time Time::build (bool local, const tm &base, TimeSpan diff /* = 0 */) {
138  tm tmp (base);
139  return Time (local ? mktime(&tmp) : timegm(&tmp), 0) + diff;
140 }
141 
146 tm Time::split (bool local, int *nsecpart /* = 0 */) const {
147  if (nsecpart)
148  *nsecpart = (int)(m_nsecs % SEC_NSECS);
149 
150  time_t val = (time_t)(m_nsecs / SEC_NSECS);
151 
152  tm retval;
153  if (local)
154  localtime_r(&val, &retval);
155  else
156  gmtime_r(&val, &retval);
157 
158  return retval;
159 }
160 
164 tm Time::utc (int *nsecpart /* = 0 */) const {
165  return split (false, nsecpart);
166 }
167 
171 tm Time::local (int *nsecpart /* = 0 */) const {
172  return split (true, nsecpart);
173 }
174 
176 int Time::year (bool local) const {
177  return split (local).tm_year + 1900;
178 }
179 
181 int Time::month (bool local) const {
182  return split (local).tm_mon;
183 }
184 
186 int Time::day (bool local) const {
187  return split (local).tm_mday;
188 }
189 
191 int Time::hour (bool local) const {
192  return split (local).tm_hour;
193 }
194 
196 int Time::minute (bool local) const {
197  return split (local).tm_min;
198 }
199 
203 int Time::second (bool local) const {
204  return split (local).tm_sec;
205 }
206 
210 int Time::nsecond (void) const {
211  return (int)(m_nsecs % SEC_NSECS);
212 }
213 
215 int Time::weekday (bool local) const {
216  return split (local).tm_wday;
217 }
218 
222 bool Time::isdst (bool local) const {
223  return split (local).tm_isdst > 0;
224 }
225 
232 Time::ValueType Time::utcoffset (int *daylight /* = 0 */) const {
233  ValueType n = 0;
234 
235 #ifndef WIN32
236  tm localtm = local ();
237  n = localtm.tm_gmtoff;
238  if (daylight) *daylight = localtm.tm_isdst;
239 #else
240  // Adapted from WINE.
241  time_t utctime = (time_t)(m_nsecs / SEC_NSECS);
242  tm localtm;
243  localtime_s(&localtm, &utctime);
244  int savedaylight = localtm.tm_isdst;
245  tm gmt;
246  gmtime_s(&gmt, &utctime);
247 
248  gmt.tm_isdst = savedaylight;
249  n = utctime - mktime (&gmt);
250 
251  if (daylight) *daylight = savedaylight;
252 #endif
253  return n * SEC_NSECS;
254 }
255 
256 #ifdef WIN32
257 // disable warning
258 // C4996: 'tzname': This function or variable may be unsafe.
259 #pragma warning(push)
260 #pragma warning(disable:4996)
261 #endif
262 
266 const char * Time::timezone (int *daylight /* = 0 */) const {
267  tm localtm = local ();
268  if (daylight) *daylight = localtm.tm_isdst;
269  // extern "C" { extern char *tzname [2]; }
270  return tzname [localtm.tm_isdst > 0 ? 1 : 0];
271 }
272 #ifdef WIN32
273 #pragma warning(pop)
274 #endif
275 
280 std::string Time::format (bool local, std::string spec) const {
282  std::string result;
283  tm time = split (local);
284  std::string::size_type length = 0;
285 
286  // handle the special case of "%f"
287  std::string::size_type pos = spec.find("%f");
288  if (std::string::npos != pos) {
289  // Get the milliseconds string
290  std::string ms = nanoformat(3,3);
291  // Replace all the occurrences of '%f' (if not preceded by '%')
292  while (std::string::npos != pos) {
293  if (pos != 0 && spec[pos-1] != '%') {
294  spec.replace(pos, 2, ms);
295  }
296  pos = spec.find("%f", pos + 1); // search for the next occurrence
297  }
298  }
299  const int MIN_BUF_SIZE = 128;
300  do
301  {
302  // Guess how much we'll expand. If we go wrong, we'll expand again. (with a minimum)
303  result.resize(std::max<std::string::size_type>(result.size()*2,
304  std::max<std::string::size_type>(spec.size()*2, MIN_BUF_SIZE))
305  , 0);
306  length = ::strftime (&result[0], result.size(), spec.c_str(), &time);
307  } while (! length);
308 
309  result.resize (length);
310  return result;
311 }
312 
323 std::string Time::nanoformat (size_t minwidth /* = 1 */, size_t maxwidth /* = 9 */) const {
324  TimeAssert( (minwidth >= 1) && (minwidth <= maxwidth) && (maxwidth <= 9),
325  "nanoformat options do not satisfy: 1 <= minwidth <= maxwidth <= 9");
326 
327  // Calculate the nanosecond fraction. This will be < 1000000000.
328  int value = (int)(m_nsecs % SEC_NSECS);
329 
330  std::ostringstream buf;
331  buf.fill('0');
332  buf.width(9);
333  buf << value;
334  std::string out = buf.str();
335  // Find the last non-0 char before maxwidth, but after minwidth
336  // (Note: -1 and +1 are to account for difference between position and size.
337  // moreover, npos + 1 == 0, so it is correct to say that 'not found' means size of 0)
338  size_t len = out.find_last_not_of('0', maxwidth - 1) + 1;
339  // Truncate the output string to at least minwidth chars
340  out.resize(std::max(len, minwidth));
341  return out;
342 }
343 
345 
346 unsigned Time::toDosDate (Time time) {
347  // Use local time since DOS does too.
348  struct tm localtm = time.local ();
349 
350  unsigned mday = localtm.tm_mday;
351  unsigned mon = localtm.tm_mon + 1;
352  unsigned year = (localtm.tm_year > 80 ? localtm.tm_year - 80 : 0);
353  unsigned sec = localtm.tm_sec / 2;
354  unsigned min = localtm.tm_min;
355  unsigned hour = localtm.tm_hour;
356  return (mday << 16 | mon << 21 | year << 25
357  | sec | min << 5 | hour << 11);
358 }
359 
361 Time Time::fromDosDate (unsigned dosDate) {
362  // DOS times are generally local; treat it as UTC. This avoids
363  // any round-trip conversion and leaves only a presentation as an
364  // issue. Since not much can be known about the origin of the DOS
365  // times, it's generally best to present them as such (= in UTC).
366  struct tm localtm;
367  memset (&localtm, 0, sizeof (localtm));
368  localtm.tm_mday = (dosDate >> 16) & 0x1f;
369  localtm.tm_mon = ((dosDate >> 21) & 0xf) - 1;
370  localtm.tm_year = ((dosDate >> 25) & 0x7f) + 80;
371  localtm.tm_hour = (dosDate >> 11) & 0x1f;
372  localtm.tm_min = (dosDate >> 5) & 0x3f;
373  localtm.tm_sec = (dosDate & 0x1f) * 2;
374  localtm.tm_isdst = -1;
375 
376  return Time (mktime (&localtm), 0);
377 }
378 
379 //=============================================================================
longlong ValueType
Definition: Time.h:217
int hour(bool local) const
Get the hour, numbered [0, 23].
Definition: Time.cpp:191
const char * timezone(int *daylight=0) const
Return the local timezone name that applies at this time value.
Definition: Time.cpp:266
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:146
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:137
Define general base for Gaudi exception.
int day(bool local) const
Get the day of month, numbered [1,31].
Definition: Time.cpp:186
static unsigned toDosDate(Time time)
Convert the Time t into a MS-DOS date format.
Definition: Time.cpp:346
int month(bool local) const
Get the month, numbered [0,11].
Definition: Time.cpp:181
static Time current(void)
Returns the current time.
Definition: Time.cpp:114
tm utc(int *nsecpart=0) const
Break up the time to the standard library representation, keeping it in UTC.
Definition: Time.cpp:164
bool isdst(bool local) const
Check whether daylight savings is in effect.
Definition: Time.cpp:222
void TimeAssert(bool cond, const std::string &msg="time assertion failed") const
Definition: Time.h:299
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:203
tm local(int *nsecpart=0) const
Break up the time to the standard library representation, converting it first to local time...
Definition: Time.cpp:171
static const ValueType SEC_NSECS
Nanoseconds in one second.
Definition: Time.h:242
Based on seal::Time.
Definition: Time.h:214
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:232
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:323
static Time fromDosDate(unsigned dosDate)
Convert the MS-DOS date dosDate into a Time.
Definition: Time.cpp:361
#define min(a, b)
ValueType m_nsecs
Definition: Time.h:297
Time(void)
Initialize an empty (zero) time value.
Definition: Time.icpp:10
int weekday(bool local) const
Get the day of week, numbered [0,6] and starting from Sunday.
Definition: Time.cpp:215
int nsecond(void) const
Get the nanoseconds.
Definition: Time.cpp:210
This is a number of static methods for bootstrapping the Gaudi framework.
Definition: Bootstrap.h:14
int year(bool local) const
Get the year.
Definition: Time.cpp:176
Based on seal::TimeSpan.
Definition: Time.h:57
std::string format(bool local, std::string spec="%c") const
Format the time using strftime.
Definition: Time.cpp:280
int minute(bool local) const
Get the minute, numbered [0, 59].
Definition: Time.cpp:196