ROOT  6.06/09
Reference Guide
TTimeStamp.cxx
Go to the documentation of this file.
1 // @(#)root/base:$Id$
2 // Author: R. Hatcher 30/9/2001
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2002, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 /** \class TTimeStamp
13 The TTimeStamp encapsulates seconds and ns since EPOCH
14 
15 This extends (and isolates) struct timespec
16 ~~~ {.cpp}
17  struct timespec
18  {
19  time_t tv_sec; // seconds
20  long tv_nsec; // nanoseconds
21  }
22  time_t seconds is relative to Jan 1, 1970 00:00:00 UTC
23 ~~~
24 No accounting of leap seconds is made.
25 
26 Due to ROOT/CINT limitations TTimeStamp does not explicitly
27 hold a timespec struct; attempting to do so means the Streamer
28 must be hand written. Instead we have chosen to simply contain
29 similar fields within the private area of this class.
30 
31 NOTE: the use of time_t (and its default implementation as a 32 int)
32  implies overflow conditions occurs somewhere around
33  `Jan 18, 19:14:07, 2038`.
34  If this experiment is still going when it becomes significant
35  someone will have to deal with it.
36 */
37 
38 #include "TTimeStamp.h"
39 #include "TMath.h"
40 #include "TString.h"
41 #include "TError.h"
42 #include "Riostream.h"
43 #ifdef R__WIN32
44 #include "Windows4Root.h"
45 #else
46 #include <unistd.h>
47 #include <sys/time.h>
48 #endif
49 #include "TVirtualMutex.h"
50 
52 
53 
54 TVirtualMutex *gTimeMutex = 0; // local mutex
55 
56 ////////////////////////////////////////////////////////////////////////////////
57 /// Write time stamp to std::ostream.
58 
59 std::ostream& operator<<(std::ostream& os, const TTimeStamp& ts)
60 {
61  if (os.good()) {
62  if (os.tie()) os.tie()->flush(); // instead of opfx
63  os << ts.AsString("c");
64  }
65  // instead of os.osfx()
66  if (os.flags() & std::ios::unitbuf) os.flush();
67  return os;
68 }
69 
70 ////////////////////////////////////////////////////////////////////////////////
71 /// Read time stamp from TBuffer.
72 
74 {
75  ts.Streamer(buf);
76  return buf;
77 }
78 
79 ////////////////////////////////////////////////////////////////////////////////
80 /// Write time stamp to TBuffer.
81 
83 {
84  ((TTimeStamp&)ts).Streamer(buf);
85  return buf;
86 }
87 
88 ////////////////////////////////////////////////////////////////////////////////
89 /// Default ctor. Create a TTimeStamp and set it to the current time
90 /// (as best possible). The nanosecond part is faked so that subsequent
91 /// calls simply add 1 to ensure that sequential calls are distinct
92 /// (and sortable).
93 
95 {
96  Set();
97 }
98 
99 ////////////////////////////////////////////////////////////////////////////////
100 /// Create a TTimeStamp and set it to the specified year, month,
101 /// day, time, hour, minute, second and nanosec.
102 /// If !isUTC then it is assumed to be the standard local time zone.
103 ///
104 /// If local time is PST then one can use
105 /// ~~~ {.cpp}
106 /// TTimeStamp(year,month,day,hour,min,sec,nsec,kFALSE,0);
107 /// ~~~
108 /// or
109 /// ~~~ {.cpp}
110 /// Int_t secOffset = 8*60*60;
111 /// TTimeStamp timeStamp(year,month,day,hour,min,sec,nsec,kTRUE,8*60*60);
112 /// ~~~
113 
115  UInt_t day, UInt_t hour,
116  UInt_t min, UInt_t sec,
117  UInt_t nsec,
118  Bool_t isUTC, Int_t secOffset)
119 {
120  Set(year, month, day, hour, min, sec, nsec, isUTC, secOffset);
121 }
122 
123 ////////////////////////////////////////////////////////////////////////////////
124 /// Create a TTimeStamp and set it to the specified date, time, nanosec.
125 /// If !isUTC then it is assumed to be the standard local time zone.
126 ///
127 /// \warning Watch out! C++ overload resolution often chooses the constructor
128 /// `TTimeStamp(UInt_t tloc, Bool_t isUTC, Int_t secOffset, Bool_t dosDate)`
129 /// instead of this one. Your best bet is to explicitly pass UInt_t values instead
130 /// of Int_t values. When calling with integer literals, pass for instance
131 /// ~~~ {.cpp}
132 /// TTimeStamp timeStamp(20150610u,80448u,0u)
133 /// ~~~
134 /// to disambiguate.
135 
137  UInt_t nsec,
138  Bool_t isUTC, Int_t secOffset)
139 {
140  Set(date, time, nsec, isUTC, secOffset);
141 }
142 
143 ////////////////////////////////////////////////////////////////////////////////
144 /// Create a TTimeStamp and set it to tloc which must be a time_t value
145 /// returned by time(). This value is the number of seconds since the EPOCH
146 /// (i.e. 00:00:00 on Jan 1m 1970). If dosDate is true then the input
147 /// is a dosDate value.
148 
149 TTimeStamp::TTimeStamp(UInt_t tloc, Bool_t isUTC, Int_t secOffset, Bool_t dosDate)
150 {
151  Set(tloc, isUTC, secOffset, dosDate);
152 }
153 
154 ////////////////////////////////////////////////////////////////////////////////
155 /// Return Greenwich mean sidereal time (GMST) in hour-angle. Return value
156 /// will always be between 0 and 24 (hours). Sidereal time is most accurately
157 /// calculated from UT1. If fSec and fNanoSec are in UTC (which they are by
158 /// default), the optional argument UT1Offset can be supplied (in
159 /// milliseconds). If UT1Offset is not supplied, conversion has maximum error
160 /// of 1s. If offset is supplied error can be reduced to us level. Values for
161 /// UT1Offset can be found in IERS Bulletin B:
162 /// ftp://ftp.iers.org/products/eop/bulletinb/format_2009/
163 /// The conversion to sidereal time used here is given by
164 /// Aoki et. al. Astron. Astrophys. 105, 359-362 (1982)
165 /// http://adsabs.harvard.edu/abs/1982A%26A...105..359A
166 
168 {
169  Double_t D = (AsJulianDate() + UT1Offset/86400000.0) - 2451545.0;
170  Double_t D_r = D - fmod(2.0*D+1.0, 2.0)/2.0;
171  Double_t T = D_r/36525.0;
172  Double_t sidereal = (24110.54841 + 8640184.812866*T + 0.093142*T*T
173  - 0.0000062*T*T*T + (D - D_r)*86400.0*1.002737909350795)/3600.0;
174  Double_t rval = fmod(sidereal, 24.0);
175  return rval < 0 ? rval + 24.0 : rval;
176 }
177 
178 ////////////////////////////////////////////////////////////////////////////////
179 /// Return Greenwich apparent sidereal time (GAST) in hour-angle. Return
180 /// value will always be between 0 and 24 (hours). Sidereal time is most
181 /// accurately calculated from UT1. If fSec and fNanoSec are in UTC (which
182 /// they are by default), the optional argument UT1Offset can be supplied (in
183 /// milliseconds). If UT1Offset is not supplied, conversion has maximum error
184 /// of 1s. If offset is supplied error can be reduced to us level. Values for
185 /// UT1Offset can be found in IERS Bulletin B:
186 /// ftp://ftp.iers.org/products/eop/bulletinb/format_2009/
187 /// Equation of the equinoxes is given by USNO:
188 /// http://aa.usno.navy.mil/faq/docs/GAST.php
189 
191 {
192  Double_t D = (AsJulianDate() + UT1Offset/86400000.0) - 2451545.0;
193  Double_t epsilon = (23.4393 - 0.0000004*D)*TMath::Pi()/180.0;
194  Double_t L = (280.47 + 0.98565*D)*TMath::Pi()/180.0;
195  Double_t Omega = (125.04 - 0.052954*D)*TMath::Pi()/180.0;
196  Double_t Deltapsi = -0.000319*TMath::Sin(Omega) - 0.000024*TMath::Sin(2.0*L);
197  Double_t eqeq = Deltapsi*TMath::Cos(epsilon);
198  Double_t rval = fmod(AsGMST(UT1Offset) + eqeq, 24.0);
199  return rval < 0 ? rval + 24.0 : rval;
200 }
201 
202 ////////////////////////////////////////////////////////////////////////////////
203 /// Return local mean sidereal time (LMST) in hour-angle, given a longitude
204 /// in degrees. Return value will always be between 0 and 24 (hours).
205 /// Sidereal time is most accurately calculated from UT1. If fSec and
206 /// fNanoSec are in UTC (which they are by default), the optional argument
207 /// UT1Offset can be supplied (in milliseconds). If UT1Offset is not
208 /// supplied, conversion has maximum error of 1s. If offset is supplied error
209 /// can be reduced to us level. Values for UT1Offset can be found in IERS
210 /// Bulletin B: ftp://ftp.iers.org/products/eop/bulletinb/format_2009/
211 
212 Double_t TTimeStamp::AsLMST(Double_t Longitude, Double_t UT1Offset) const
213 {
214  Double_t rval = fmod(AsGMST(UT1Offset) + Longitude/15.0, 24.0);
215  return rval < 0 ? rval + 24.0 : rval;
216 }
217 
218 ////////////////////////////////////////////////////////////////////////////////
219 /// Return local apparent sidereal time (LAST) in hour-angle, given a
220 /// longitude in degrees. Return value will always be between 0 and 24
221 /// (hours). Sidereal time is most accurately calculated from UT1. If fSec
222 /// and fNanoSec are in UTC (which they are by default), the optional
223 /// argument UT1Offset can be supplied (in milliseconds). If UT1Offset is not
224 /// supplied, conversion has maximum error of 1s. If offset is supplied error
225 /// can be reduced to us level. Values for UT1Offset can be found in IERS
226 /// Bulletin B: ftp://ftp.iers.org/products/eop/bulletinb/format_2009/
227 
228 Double_t TTimeStamp::AsLAST(Double_t Longitude, Double_t UT1Offset) const
229 {
230  Double_t rval = fmod(AsGAST(UT1Offset) + Longitude/15.0, 24.0);
231  return rval < 0 ? rval + 24.0 : rval;
232 }
233 
234 ////////////////////////////////////////////////////////////////////////////////
235 /// Return the date & time as a string.
236 ///
237 /// Result is pointer to a statically allocated string.
238 /// User should copy this into their own buffer before calling
239 /// this method again.
240 ///
241 /// Option "l" returns it in local zone format
242 /// (can be applied to default or compact format).
243 ///
244 /// Default format is RFC822 compliant:
245 /// ~~~ {.cpp}
246 /// "Mon, 02 Jan 2001 18:11:12 +0000 (GMT) +999999999 nsec"
247 /// "Mon, 02 Jan 2001 10:11:12 -0800 (PST) +999999999 nsec"
248 /// ~~~
249 ///
250 /// Option "c" compact is (almost) ISO 8601 compliant:
251 /// - "2001-01-02 18:11:12.9999999999Z"
252 /// - "2001-01-02 10:11:12.9999999999-0800" if PST
253 /// * uses "-" as date separator as specified in ISO 8601
254 /// * uses "." rather than preferred "," for decimal separator
255 /// * -HHMM is the difference between local and UTC (if behind, + if ahead).
256 ///
257 /// The "-HHMM" is replaced with "Z" if given as UTC.
258 /// To be strictly conforming it should use "T" instead of the
259 /// blank separating the date and time.
260 ///
261 /// Option "2" returns as {sec,nsec} integers.
262 ///
263 /// Option "s" returns "2001-01-02 18:11:12" with an implied UTC,
264 /// overrides "l" option.
265 ///
266 /// Internally uses a circular list of buffers to avoid problems
267 /// using AsString multiple times in a single statement.
268 
269 const Char_t *TTimeStamp::AsString(Option_t *option) const
270 {
271  const Int_t nbuffers = 8; // # of buffers
272 
273  static Char_t formatted[nbuffers][64]; // strftime fields substituted
274  static Char_t formatted2[nbuffers][64]; // nanosec field substituted
275 
276  static Int_t ibuffer = nbuffers;
277 
278  R__LOCKGUARD2(gTimeMutex);
279 
280  ibuffer = (ibuffer+1)%nbuffers; // each call moves to next buffer
281 
282  TString opt = option;
283  opt.ToLower();
284 
285  if (opt.Contains("2")) {
286  // return string formatted as integer {sec,nsec}
287  sprintf(formatted[ibuffer], "{%d,%d}", fSec, fNanoSec);
288  return formatted[ibuffer];
289  }
290 
291 #ifdef R__LINUX
292  // under linux %z is the hour offset and %Z is the timezone name
293  const Char_t *kRFC822 = "%a, %d %b %Y %H:%M:%S %z (%Z) +#9ld nsec";
294  const Char_t *kISO8601 = "%Y-%m-%d %H:%M:%S.#9.9ld%z";
295  const Char_t *kISO8601Z = "%Y-%m-%d %H:%M:%S.#9.9ldZ";
296 #else
297  // otherwise only %Z is guaranteed to be defined
298  const Char_t *kRFC822 = "%a, %d %b %Y %H:%M:%S %Z +#9ld nsec";
299  const Char_t *kISO8601 = "%Y-%m-%d %H:%M:%S.#9.9ld%Z";
300  const Char_t *kISO8601Z = "%Y-%m-%d %H:%M:%S.#9.9ldZ";
301 #endif
302  const Char_t *kSQL = "%Y-%m-%d %H:%M:%S";
303 
304  Bool_t asLocal = opt.Contains("l");
305  Bool_t asSQL = opt.Contains("s");
306  if (asSQL) asLocal = kFALSE;
307 
308  const Char_t *format = kRFC822;
309  if (opt.Contains("c")) {
310  format = kISO8601;
311  if (!asLocal) format = kISO8601Z;
312  }
313  if (asSQL) format = kSQL;
314 
315  // get the components into a tm struct
316  time_t seconds = (time_t) fSec;
317 #ifdef _REENTRANT
318  struct tm buf;
319  struct tm *ptm = (asLocal) ? localtime_r(&seconds, &buf) : gmtime_r(&seconds, &buf);
320 #else
321  struct tm *ptm = (asLocal) ? localtime(&seconds) : gmtime(&seconds);
322 #endif
323 
324  // format all but the nsec field
325  // size_t length =
326  strftime(formatted[ibuffer], sizeof(formatted[ibuffer]), format, ptm);
327 
328  if (asSQL) return formatted[ibuffer];
329 
330  // hack in the nsec part
331  Char_t *ptr = strrchr(formatted[ibuffer], '#');
332  if (ptr) *ptr = '%'; // substitute % for #
333  sprintf(formatted2[ibuffer], formatted[ibuffer], fNanoSec);
334 
335  return formatted2[ibuffer];
336 }
337 
338 ////////////////////////////////////////////////////////////////////////////////
339 /// Copy this to ts.
340 
342 {
343  ts.fSec = fSec;
344  ts.fNanoSec = fNanoSec;
345 }
346 
347 ////////////////////////////////////////////////////////////////////////////////
348 /// Return date in form of 19971224 (i.e. 24/12/1997),
349 /// if non-zero pointers supplied for year, month, day fill those as well.
350 
352  UInt_t *year, UInt_t *month, UInt_t *day) const
353 {
354  time_t atime = fSec + secOffset;
355 #ifdef _REENTRANT
356  struct tm buf;
357  struct tm *ptm = (inUTC) ? gmtime_r(&atime, &buf) : localtime_r(&atime, &buf);
358 #else
359  struct tm *ptm = (inUTC) ? gmtime(&atime) : localtime(&atime);
360 #endif
361 
362  if (day) *day = ptm->tm_mday;
363  if (month) *month = ptm->tm_mon + 1;
364  if (year) *year = ptm->tm_year + 1900;
365 
366  return (1900+ptm->tm_year)*10000 + (1+ptm->tm_mon)*100 + ptm->tm_mday;
367 }
368 
369 ////////////////////////////////////////////////////////////////////////////////
370 /// Return time in form of 123623 (i.e. 12:36:23),
371 /// if non-zero pointers supplied for hour, min, sec fill those as well.
372 
374  UInt_t *hour, UInt_t *min, UInt_t *sec) const
375 {
376  time_t atime = fSec + secOffset;
377 #ifdef _REENTRANT
378  struct tm buf;
379  struct tm *ptm = (inUTC) ? gmtime_r(&atime, &buf) : localtime_r(&atime, &buf);
380 #else
381  struct tm *ptm = (inUTC) ? gmtime(&atime) : localtime(&atime);
382 #endif
383 
384  if (hour) *hour = ptm->tm_hour;
385  if (min) *min = ptm->tm_min;
386  if (sec) *sec = ptm->tm_sec;
387 
388  return ptm->tm_hour*10000 + ptm->tm_min*100 + ptm->tm_sec;
389 }
390 
391 ////////////////////////////////////////////////////////////////////////////////
392 /// Get the day of the year represented by this time stamp value.
393 /// Valid return values range between 1 and 366, where January 1 = 1.
394 
396 {
397  time_t atime = fSec + secOffset;
398 #ifdef _REENTRANT
399  struct tm buf;
400  struct tm *ptm = (inUTC) ? gmtime_r(&atime, &buf) : localtime_r(&atime, &buf);
401 #else
402  struct tm *ptm = (inUTC) ? gmtime(&atime) : localtime(&atime);
403 #endif
404 
405  Int_t day = ptm->tm_mday;
406  Int_t month = ptm->tm_mon + 1;
407  Int_t year = ptm->tm_year + 1900;
408 
409  return GetDayOfYear(day, month, year);
410 }
411 
412 ////////////////////////////////////////////////////////////////////////////////
413 /// Method is using Zeller's formula for calculating the day number.
414 /// Valid return values range between 1 and 7, where Monday = 1.
415 
417 {
418  time_t atime = fSec + secOffset;
419 #ifdef _REENTRANT
420  struct tm buf;
421  struct tm *ptm = (inUTC) ? gmtime_r(&atime, &buf) : localtime_r(&atime, &buf);
422 #else
423  struct tm *ptm = (inUTC) ? gmtime(&atime) : localtime(&atime);
424 #endif
425 
426  Int_t day = ptm->tm_mday;
427  Int_t month = ptm->tm_mon + 1;
428  Int_t year = ptm->tm_year + 1900;
429 
430  return GetDayOfWeek(day, month, year);
431 }
432 
433 ////////////////////////////////////////////////////////////////////////////////
434 /// Get the month of the year. Valid return values are between 1 and 12.
435 
436 Int_t TTimeStamp::GetMonth(Bool_t inUTC, Int_t secOffset) const
437 {
438  time_t atime = fSec + secOffset;
439 #ifdef _REENTRANT
440  struct tm buf;
441  struct tm *ptm = (inUTC) ? gmtime_r(&atime, &buf) : localtime_r(&atime, &buf);
442 #else
443  struct tm *ptm = (inUTC) ? gmtime(&atime) : localtime(&atime);
444 #endif
445 
446  return ptm->tm_mon + 1;
447 }
448 
449 ////////////////////////////////////////////////////////////////////////////////
450 /// Get the week of the year. Valid week values are between 1 and 53.
451 /// The return value is the year*100+week (1 Jan may be in the last
452 /// week of the previous year so the year must be returned too).
453 
454 Int_t TTimeStamp::GetWeek(Bool_t inUTC, Int_t secOffset) const
455 {
456  time_t atime = fSec + secOffset;
457 #ifdef _REENTRANT
458  struct tm buf;
459  struct tm *ptm = (inUTC) ? gmtime_r(&atime, &buf) : localtime_r(&atime, &buf);
460 #else
461  struct tm *ptm = (inUTC) ? gmtime(&atime) : localtime(&atime);
462 #endif
463 
464  Int_t day = ptm->tm_mday;
465  Int_t month = ptm->tm_mon + 1;
466  Int_t year = ptm->tm_year + 1900;
467 
468  return GetWeek(day, month, year);
469 }
470 
471 ////////////////////////////////////////////////////////////////////////////////
472 /// Is the year a leap year.
473 /// The calendar year is 365 days long, unless the year is exactly divisible
474 /// by 4, in which case an extra day is added to February to make the year
475 /// 366 days long. If the year is the last year of a century, eg. 1700, 1800,
476 /// 1900, 2000, then it is only a leap year if it is exactly divisible by
477 /// 400. Therefore, 1900 wasn't a leap year but 2000 was. The reason for
478 /// these rules is to bring the average length of the calendar year into
479 /// line with the length of the Earth's orbit around the Sun, so that the
480 /// seasons always occur during the same months each year.
481 
482 Bool_t TTimeStamp::IsLeapYear(Bool_t inUTC, Int_t secOffset) const
483 {
484  time_t atime = fSec + secOffset;
485 #ifdef _REENTRANT
486  struct tm buf;
487  struct tm *ptm = (inUTC) ? gmtime_r(&atime, &buf) : localtime_r(&atime, &buf);
488 #else
489  struct tm *ptm = (inUTC) ? gmtime(&atime) : localtime(&atime);
490 #endif
491 
492  Int_t year = ptm->tm_year + 1900;
493 
494  return IsLeapYear(year);
495 }
496 
497 ////////////////////////////////////////////////////////////////////////////////
498 /// Static method returning local (current) time zone offset from UTC.
499 /// This is the value in seconds one must add to the local time to arrive at
500 /// Coordinated Universal Time, so it is negative east of the Prime Meridian.
501 
503 {
504  // ?? should tzset (_tzset) be called?
505 #ifndef R__WIN32
506  tzset();
507 #if defined(R__WINGCC)
508  return _timezone;
509 #else
510 #if !defined(R__FBSD) && !defined(R__OBSD)
511  return timezone; // unix has extern long int
512 #else
513  time_t tp = 0;
514  time(&tp);
515 #ifdef _REENTRANT
516  struct tm buf;
517  return -localtime_r(&tp, &buf)->tm_gmtoff;
518 #else
519  return -localtime(&tp)->tm_gmtoff;
520 #endif
521 #endif
522 #endif
523 #else
524  _tzset();
525  return _timezone; // Win32 prepends "_"
526 #endif
527 }
528 
529 ////////////////////////////////////////////////////////////////////////////////
530 /// Add "offset" as a delta time.
531 
532 void TTimeStamp::Add(const TTimeStamp &offset)
533 {
534  fSec += offset.fSec;
535  fNanoSec += offset.fNanoSec;
537 }
538 
539 ////////////////////////////////////////////////////////////////////////////////
540 /// Print date and time.
541 
542 void TTimeStamp::Print(Option_t *option) const
543 {
544  printf("Date/Time = %s\n", AsString(option));
545 }
546 
547 ////////////////////////////////////////////////////////////////////////////////
548 /// Set Date/Time to current time as reported by the system.
549 /// No accounting for nanoseconds with std ANSI functions,
550 /// ns part faked so that subsequent calls simply add 1 to it
551 /// this ensures that calls within the same second come back
552 /// distinct (and sortable). Time is since Jan 1, 1970.
553 
555 {
556 #ifdef R__WIN32
557  ULARGE_INTEGER time;
558  GetSystemTimeAsFileTime((FILETIME *)&time);
559  // NT keeps time in FILETIME format which is 100ns ticks since
560  // Jan 1, 1601. TTimeStamp uses time in 100ns ticks since Jan 1, 1970,
561  // the difference is 134774 days.
562  fNanoSec = Int_t((time.QuadPart * (unsigned __int64) 100) %
563  (unsigned __int64) 1000000000);
564  time.QuadPart -=
565  (unsigned __int64) (1000*1000*10) // seconds
566  * (unsigned __int64) (60 * 60 * 24) // days
567  * (unsigned __int64) (134774); // # of days
568 
569  fSec = Int_t(time.QuadPart/(unsigned __int64) (1000*1000*10));
570 #else
571  struct timeval tp;
572  gettimeofday(&tp, 0);
573  fSec = tp.tv_sec;
574  fNanoSec = tp.tv_usec*1000;
575 #endif
576 
577  static Int_t sec = 0, nsec = 0, fake_ns = 0;
578 
579  R__LOCKGUARD2(gTimeMutex);
580 
581  if (fSec == sec && fNanoSec == nsec)
582  fNanoSec += ++fake_ns;
583  else {
584  fake_ns = 0;
585  sec = fSec;
586  nsec = fNanoSec;
587  }
588 }
589 
590 ////////////////////////////////////////////////////////////////////////////////
591 /// Set Date/Time from components.
592 ///
593 /// Month & day both use normal 1..12 and 1..31 counting,
594 /// hours, min, sec run from 0 to 23, 59, 59 respectively,
595 /// secOffset provides method for adjusting for alternative timezones
596 ///
597 /// ~~~ {.cpp}
598 /// "year" | 0 1 ... 37 | 38...69 | 70 .. 100 101 .. 137
599 /// true | 2000 2001 2037 | undefined | 1970 2000 2001 .. 2037
600 ///
601 /// "year" | 138...1969 | 1970 .. 2037 | ...
602 /// true | undefined | 1970 .. 2037 | undefined
603 /// ~~~
604 
605 void TTimeStamp::Set(Int_t year, Int_t month, Int_t day,
606  Int_t hour, Int_t min, Int_t sec,
607  Int_t nsec, Bool_t isUTC, Int_t secOffset)
608 {
609  // deal with special formats of year
610  if (year <= 37) year += 2000;
611  if (year >= 70 && year <= 137) year += 1900;
612  // tm.tm_year is years since 1900
613  if (year >= 1900) year -= 1900;
614 
615  struct tm tmstruct;
616  tmstruct.tm_year = year; // years since 1900
617  tmstruct.tm_mon = month-1; // months since Jan [0,11]
618  tmstruct.tm_mday = day; // day of the month [1,31]
619  tmstruct.tm_hour = hour; // hours since midnight [0,23]
620  tmstruct.tm_min = min; // minutes after the hour [0,59]
621  tmstruct.tm_sec = sec + secOffset; // seconds after the minute [0,59]
622  tmstruct.tm_isdst = -1; // let "mktime" determine DST setting
623 
624  const time_t bad_time_t = (time_t) -1;
625  // convert tm struct to time_t, if values are given in UTC then
626  // no standard routine exists and we'll have to use our homegrown routine,
627  // if values are given in local time then use "mktime"
628  // which also normalizes the tm struct as a byproduct
629  time_t utc_sec = (isUTC) ? MktimeFromUTC(&tmstruct) : mktime(&tmstruct);
630 
631  if (utc_sec == bad_time_t)
632  Error("TTimeStamp::Set","mktime returned -1");
633 
634  fSec = utc_sec;
635  fNanoSec = nsec;
636 
638 }
639 
640 ////////////////////////////////////////////////////////////////////////////////
641 /// Set date/time from integers of the form [yy]YYMMDD and HHMMSS,
642 /// assume UTC (UTC) components:
643 ///
644 /// ~~~ {.cpp}
645 /// MM: 01=January .. 12=December
646 /// DD: 01 .. 31
647 ///
648 /// HH: 00=midnight .. 23
649 /// MM: 00 .. 59
650 /// SS: 00 .. 69
651 /// ~~~
652 ///
653 /// - Date must be in format 980418 or 19980418
654 /// 1001127 or 20001127 (i.e. year 100 = 2000),
655 /// - time must be in format 224512 (second precision),
656 /// - date must be >= 700101.
657 
658 void TTimeStamp::Set(Int_t date, Int_t time, Int_t nsec,
659  Bool_t isUTC, Int_t secOffset)
660 {
661  Int_t year = date/10000;
662  Int_t month = (date-year*10000)/100;
663  Int_t day = date%100;
664 
665  // protect against odd attempts at time offsets
666  const Int_t oneday = 240000;
667  while (time < 0) {
668  time += oneday;
669  day -= 1;
670  }
671  while (time > oneday) {
672  time -= oneday;
673  day += 1;
674  }
675  Int_t hour = time/10000;
676  Int_t min = (time-hour*10000)/100;
677  Int_t sec = time%100;
678 
679  Set(year, month, day, hour, min, sec, nsec, isUTC, secOffset);
680 }
681 
682 ////////////////////////////////////////////////////////////////////////////////
683 /// The input arg is a time_t value returned by time() or a value
684 /// returned by Convert(). This value is the number of seconds since
685 /// the EPOCH (i.e. 00:00:00 on Jan 1m 1970). If dosDate is true then
686 /// the input is a dosDate value.
687 
688 void TTimeStamp::Set(UInt_t tloc, Bool_t isUTC, Int_t secOffset, Bool_t dosDate)
689 {
690  struct tm localtm;
691  memset (&localtm, 0, sizeof (localtm));
692 
693  if (dosDate) {
694  localtm.tm_year = ((tloc >> 25) & 0x7f) + 80;
695  localtm.tm_mon = ((tloc >> 21) & 0xf);
696  localtm.tm_mday = (tloc >> 16) & 0x1f;
697  localtm.tm_hour = (tloc >> 11) & 0x1f;
698  localtm.tm_min = (tloc >> 5) & 0x3f;
699  localtm.tm_sec = (tloc & 0x1f) * 2 + secOffset;
700  localtm.tm_isdst = -1;
701  } else {
702  time_t t = (time_t) tloc;
703 #ifdef _REENTRANT
704  struct tm tpa;
705  struct tm *tp = localtime_r(&t, &tpa);
706 #else
707  struct tm *tp = localtime(&t);
708 #endif
709  localtm.tm_year = tp->tm_year;
710  localtm.tm_mon = tp->tm_mon;
711  localtm.tm_mday = tp->tm_mday;
712  localtm.tm_hour = tp->tm_hour;
713  localtm.tm_min = tp->tm_min;
714  localtm.tm_sec = tp->tm_sec + secOffset;
715  localtm.tm_isdst = -1;
716  }
717 
718  const time_t bad_time_t = (time_t) -1;
719  // convert tm struct to time_t, if values are given in UTC then
720  // no standard routine exists and we'll have to use our homegrown routine,
721  // if values are given in local time then use "mktime"
722  // which also normalizes the tm struct as a byproduct
723  time_t utc_sec = (isUTC && dosDate) ? MktimeFromUTC(&localtm) : mktime(&localtm);
724 
725  if (utc_sec == bad_time_t)
726  Error("TTimeStamp::Set","mktime returned -1");
727 
728  fSec = utc_sec;
729  fNanoSec = 0; //nsec;
730 
732 }
733 
734 ////////////////////////////////////////////////////////////////////////////////
735 /// Ensure that the fNanoSec field is in range [0,999999999].
736 
738 {
739  const Int_t kNsPerSec = 1000000000;
740  // deal with negative values
741  while (fNanoSec < 0) {
742  fNanoSec += kNsPerSec;
743  fSec -= 1;
744  }
745 
746  // deal with values inf fNanoSec greater than one sec
747  while (fNanoSec >= kNsPerSec) {
748  fNanoSec -= kNsPerSec;
749  fSec += 1;
750  }
751 }
752 
753 ////////////////////////////////////////////////////////////////////////////////
754 /// Equivalent of standard routine "mktime" but
755 /// using the assumption that tm struct is filled with UTC, not local, time.
756 ///
757 /// This version *ISN'T* configured to handle every possible
758 /// weirdness of out-of-range values in the case of normalizing
759 /// the tm struct.
760 ///
761 /// This version *DOESN'T* correctly handle values that can't be
762 /// fit into a time_t (i.e. beyond year 2038-01-18 19:14:07, or
763 /// before the start of Epoch).
764 
766 {
767  Int_t daysInMonth[] = { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
768  Int_t year = tmstruct->tm_year + 1900;
769  daysInMonth[1] = IsLeapYear(year) ? 29 : 28;
770 
771  // fill in tmstruct->tm_yday
772 
773  Int_t &ref_tm_mon = tmstruct->tm_mon;
774  Int_t &ref_tm_mday = tmstruct->tm_mday;
775  // count days in months past
776  tmstruct->tm_yday = 0;
777  for (Int_t imonth = 0; imonth < ref_tm_mon; imonth++) {
778  tmstruct->tm_yday += daysInMonth[imonth];
779  }
780  tmstruct->tm_yday += ref_tm_mday - 1; // day [1-31] but yday [0-365]
781 
782  // adjust if day in this month is more than the month has
783  while (ref_tm_mday > daysInMonth[ref_tm_mon]) {
784  ref_tm_mday -= daysInMonth[ref_tm_mon];
785  ref_tm_mon++;
786  }
787 
788  // *should* calculate tm_wday (0-6) here ...
789 
790  // UTC is never DST
791  tmstruct->tm_isdst = 0;
792 
793  // Calculate seconds since the Epoch based on formula in
794  // POSIX IEEEE Std 1003.1b-1993 pg 22
795 
796  Int_t utc_sec = tmstruct->tm_sec +
797  tmstruct->tm_min*60 +
798  tmstruct->tm_hour*3600 +
799  tmstruct->tm_yday*86400 +
800  (tmstruct->tm_year-70)*31536000 +
801  ((tmstruct->tm_year-69)/4)*86400;
802 
803  return utc_sec;
804 }
805 
806 ////////////////////////////////////////////////////////////////////////////////
807 /// Get the day of the year represented by day, month and year.
808 /// Valid return values range between 1 and 366, where January 1 = 1.
809 
811 {
812  Int_t dayOfYear = 0;
813  Int_t daysInMonth[] = { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
814  daysInMonth[1] = IsLeapYear(year) ? 29 : 28;
815 
816  for (Int_t i = 0; i < (month - 1); i++)
817  dayOfYear += daysInMonth[i];
818  dayOfYear += day;
819 
820  return dayOfYear;
821 }
822 
823 ////////////////////////////////////////////////////////////////////////////////
824 /// Method is using Zeller's formula for calculating the day number.
825 /// Valid return values range between 1 and 7, where Monday = 1.
826 
828 {
829  Int_t dayno;
830 
831  if (month < 3) {
832  year--;
833  month += 12;
834  }
835 
836  dayno = 1 + day + 2*month + 3*(month + 1)/5 + year + year/4 - year/100 + year/400;
837  dayno %= 7;
838 
839  // make monday first day of week
840  return ((dayno == 0) ? 7 : dayno);
841 }
842 
843 ////////////////////////////////////////////////////////////////////////////////
844 /// Get the week of the year. Valid week values are between 1 and 53.
845 /// The return value is the year*100+week (1 Jan may be in the last
846 /// week of the previous year so the year must be returned too).
847 
849 {
850  Int_t dayOfYear = GetDayOfYear(day, month, year);
851  Int_t dayJan1st = GetDayOfWeek(1, 1, year);
852  Int_t week = (dayOfYear + dayJan1st - 2) / 7 + 1;
853 
854  if (dayJan1st > 4)
855  week--;
856 
857  if (week == 53) {
858  Int_t dayNextJan1st = GetDayOfWeek(1, 1, year + 1);
859  if (dayNextJan1st > 1 && dayNextJan1st < 5) {
860  year++;
861  week = 1;
862  }
863  } else if (week == 0) {
864  Int_t dayPrevJan1st = GetDayOfWeek(1, 1, year - 1);
865  week = (dayPrevJan1st < 5 && dayJan1st > 4) ? 53 : 52;
866  year--;
867  }
868  return year * 100 + week;
869 }
870 
871 ////////////////////////////////////////////////////////////////////////////////
872 /// Is the given year a leap year.
873 /// The calendar year is 365 days long, unless the year is exactly divisible
874 /// by 4, in which case an extra day is added to February to make the year
875 /// 366 days long. If the year is the last year of a century, eg. 1700, 1800,
876 /// 1900, 2000, then it is only a leap year if it is exactly divisible by
877 /// 400. Therefore, 1900 wasn't a leap year but 2000 was. The reason for
878 /// these rules is to bring the average length of the calendar year into
879 /// line with the length of the Earth's orbit around the Sun, so that the
880 /// seasons always occur during the same months each year.
881 
883 {
884  return (year % 4 == 0) && !((year % 100 == 0) && (year % 400 > 0));
885 }
886 
887 ////////////////////////////////////////////////////////////////////////////////
888 /// Print out the "tm" structure:
889 /// ~~~ {.cpp}
890 /// tmstruct.tm_year = year; // years since 1900
891 /// tmstruct.tm_mon = month-1; // months since Jan [0,11]
892 /// tmstruct.tm_mday = day; // day of the month [1,31]
893 /// tmstruct.tm_hour = hour; // hours since midnight [0,23]
894 /// tmstruct.tm_min = min; // minutes after the hour [0,59]
895 /// tmstruct.tm_sec = sec; // seconds after the minute [0,59]
896 /// tmstruct.tm_wday // day of week [0,6]
897 /// tmstruct.tm_yday // days in year [0,365]
898 /// tmstruct.tm_isdst // DST [-1/0/1] (unknown,false,true)
899 /// ~~~
900 
901 void TTimeStamp::DumpTMStruct(const tm_t &tmstruct)
902 {
903  printf(" tm { year %4d, mon %2d, day %2d,\n",
904  tmstruct.tm_year,
905  tmstruct.tm_mon,
906  tmstruct.tm_mday);
907  printf(" hour %2d, min %2d, sec %2d,\n",
908  tmstruct.tm_hour,
909  tmstruct.tm_min,
910  tmstruct.tm_sec);
911  printf(" wday %2d, yday %3d, isdst %2d",
912  tmstruct.tm_wday,
913  tmstruct.tm_yday,
914  tmstruct.tm_isdst);
915 #if (defined(linux) && !defined(R__WINGCC)) || defined(R__MACOSX)
916  printf(",\n tm_gmtoff %6ld, tm_zone \"%s\"",
917 #if defined(__USE_BSD) || defined(R__MACOSX) || defined(__USE_MISC)
918  tmstruct.tm_gmtoff, tmstruct.tm_zone);
919 #else
920  tmstruct.__tm_gmtoff, tmstruct.__tm_zone);
921 #endif
922 #endif
923  printf(" }\n");
924 }
static time_t MktimeFromUTC(tm_t *tmstruct)
Equivalent of standard routine "mktime" but using the assumption that tm struct is filled with UTC...
Definition: TTimeStamp.cxx:765
static Vc_ALWAYS_INLINE int_v min(const int_v &x, const int_v &y)
Definition: vector.h:433
const char * AsString(const Option_t *option="") const
Return the date & time as a string.
Definition: TTimeStamp.cxx:269
Double_t AsGAST(Double_t UT1Offset=0) const
Return Greenwich apparent sidereal time (GAST) in hour-angle.
Definition: TTimeStamp.cxx:190
const char Option_t
Definition: RtypesCore.h:62
RooArgList L(const RooAbsArg &v1)
double T(double x)
Definition: ChebyshevPol.h:34
Buffer base class used for serializing objects.
Definition: TBuffer.h:40
This class implements a mutex interface.
Definition: TVirtualMutex.h:34
Basic string class.
Definition: TString.h:137
struct tm tm_t
Definition: TTimeStamp.h:60
Double_t AsLMST(Double_t Longitude, Double_t UT1Offset=0) const
Return local mean sidereal time (LMST) in hour-angle, given a longitude in degrees.
Definition: TTimeStamp.cxx:212
void ToLower()
Change string to lower-case.
Definition: TString.cxx:1088
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
Double_t AsJulianDate() const
Definition: TTimeStamp.h:144
const Bool_t kFALSE
Definition: Rtypes.h:92
void NormalizeNanoSec()
Ensure that the fNanoSec field is in range [0,999999999].
Definition: TTimeStamp.cxx:737
Int_t fSec
Definition: TTimeStamp.h:86
static std::string format(double x, double y, int digits, int width)
Int_t fNanoSec
Definition: TTimeStamp.h:87
void Add(const TTimeStamp &offset)
Add "offset" as a delta time.
Definition: TTimeStamp.cxx:532
UChar_t mod R__LOCKGUARD2(gSrvAuthenticateMutex)
Int_t GetDayOfYear(Bool_t inUTC=kTRUE, Int_t secOffset=0) const
Get the day of the year represented by this time stamp value.
Definition: TTimeStamp.cxx:395
void Copy(TTimeStamp &ts) const
Copy this to ts.
Definition: TTimeStamp.cxx:341
void Set()
Set Date/Time to current time as reported by the system.
Definition: TTimeStamp.cxx:554
void Error(const char *location, const char *msgfmt,...)
TTimeStamp()
Default ctor.
Definition: TTimeStamp.cxx:94
void Print(const Option_t *option="") const
Print date and time.
Definition: TTimeStamp.cxx:542
ClassImp(TTimeStamp)
static void DumpTMStruct(const tm_t &tmstruct)
Print out the "tm" structure: tmstruct.tm_year = year; // years since 1900 tmstruct.tm_mon = month-1; // months since Jan [0,11] tmstruct.tm_mday = day; // day of the month [1,31] tmstruct.tm_hour = hour; // hours since midnight [0,23] tmstruct.tm_min = min; // minutes after the hour [0,59] tmstruct.tm_sec = sec; // seconds after the minute [0,59] tmstruct.tm_wday // day of week [0,6] tmstruct.tm_yday // days in year [0,365] tmstruct.tm_isdst // DST [-1/0/1] (unknown,false,true).
Definition: TTimeStamp.cxx:901
Int_t GetWeek(Bool_t inUTC=kTRUE, Int_t secOffset=0) const
Get the week of the year.
Definition: TTimeStamp.cxx:454
unsigned int UInt_t
Definition: RtypesCore.h:42
UInt_t GetTime(Bool_t inUTC=kTRUE, Int_t secOffset=0, UInt_t *hour=0, UInt_t *min=0, UInt_t *sec=0) const
Return time in form of 123623 (i.e.
Definition: TTimeStamp.cxx:373
Double_t AsLAST(Double_t Longitude, Double_t UT1Offset=0) const
Return local apparent sidereal time (LAST) in hour-angle, given a longitude in degrees.
Definition: TTimeStamp.cxx:228
REAL epsilon
Definition: triangle.c:617
TBuffer & operator>>(TBuffer &buf, TTimeStamp &ts)
Read time stamp from TBuffer.
Definition: TTimeStamp.cxx:73
Double_t Cos(Double_t)
Definition: TMath.h:424
Double_t Pi()
Definition: TMath.h:44
double Double_t
Definition: RtypesCore.h:55
ClassImp(TMCParticle) void TMCParticle printf(": p=(%7.3f,%7.3f,%9.3f) ;", fPx, fPy, fPz)
The TTimeStamp encapsulates seconds and ns since EPOCH.
Definition: TTimeStamp.h:76
Bool_t IsLeapYear(Bool_t inUTC=kTRUE, Int_t secOffset=0) const
Is the year a leap year.
Definition: TTimeStamp.cxx:482
Double_t AsGMST(Double_t UT1Offset=0) const
Return Greenwich mean sidereal time (GMST) in hour-angle.
Definition: TTimeStamp.cxx:167
char Char_t
Definition: RtypesCore.h:29
std::ostream & operator<<(std::ostream &os, const TTimeStamp &ts)
Write time stamp to std::ostream.
Definition: TTimeStamp.cxx:59
UInt_t GetDate(Bool_t inUTC=kTRUE, Int_t secOffset=0, UInt_t *year=0, UInt_t *month=0, UInt_t *day=0) const
Return date in form of 19971224 (i.e.
Definition: TTimeStamp.cxx:351
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition: TString.h:567
Double_t Sin(Double_t)
Definition: TMath.h:421
Int_t GetDayOfWeek(Bool_t inUTC=kTRUE, Int_t secOffset=0) const
Method is using Zeller's formula for calculating the day number.
Definition: TTimeStamp.cxx:416
Int_t GetMonth(Bool_t inUTC=kTRUE, Int_t secOffset=0) const
Get the month of the year. Valid return values are between 1 and 12.
Definition: TTimeStamp.cxx:436
static Int_t GetZoneOffset()
Static method returning local (current) time zone offset from UTC.
Definition: TTimeStamp.cxx:502