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