Logo ROOT   6.18/05
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
15The TTimeStamp encapsulates seconds and ns since EPOCH
16
17This 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~~~
26No accounting of leap seconds is made.
27
28Due to ROOT/CINT limitations TTimeStamp does not explicitly
29hold a timespec struct; attempting to do so means the Streamer
30must be hand written. Instead we have chosen to simply contain
31similar fields within the private area of this class.
32
33NOTE: 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
55TVirtualMutex *gTimeMutex = 0; // local mutex
56
57////////////////////////////////////////////////////////////////////////////////
58/// Write time stamp to std::ostream.
59
60std::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
150TTimeStamp::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
214Double_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
230Double_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
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
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
438Int_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
456Int_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
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
534void TTimeStamp::Add(const TTimeStamp &offset)
535{
536 fSec += offset.fSec;
537 fNanoSec += offset.fNanoSec;
539}
540
541////////////////////////////////////////////////////////////////////////////////
542/// Print date and time.
543
544void 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
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
607void 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
660void 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
690void 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
903void 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}
int Int_t
Definition: RtypesCore.h:41
char Char_t
Definition: RtypesCore.h:29
unsigned int UInt_t
Definition: RtypesCore.h:42
const Bool_t kFALSE
Definition: RtypesCore.h:88
bool Bool_t
Definition: RtypesCore.h:59
double Double_t
Definition: RtypesCore.h:55
const char Option_t
Definition: RtypesCore.h:62
#define ClassImp(name)
Definition: Rtypes.h:365
void Error(const char *location, const char *msgfmt,...)
double cos(double)
double sin(double)
TBuffer & operator>>(TBuffer &buf, TTimeStamp &ts)
Read time stamp from TBuffer.
Definition: TTimeStamp.cxx:74
TVirtualMutex * gTimeMutex
Definition: TTimeStamp.cxx:55
std::ostream & operator<<(std::ostream &os, const TTimeStamp &ts)
Write time stamp to std::ostream.
Definition: TTimeStamp.cxx:60
struct tm tm_t
Definition: TTimeStamp.h:55
#define R__LOCKGUARD2(mutex)
Buffer base class used for serializing objects.
Definition: TBuffer.h:42
Basic string class.
Definition: TString.h:131
void ToLower()
Change string to lower-case.
Definition: TString.cxx:1125
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition: TString.h:619
The TTimeStamp encapsulates seconds and ns since EPOCH.
Definition: TTimeStamp.h:71
Bool_t IsLeapYear(Bool_t inUTC=kTRUE, Int_t secOffset=0) const
Is the year a leap year.
Definition: TTimeStamp.cxx:484
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
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
static void DumpTMStruct(const tm_t &tmstruct)
Print out the "tm" structure:
Definition: TTimeStamp.cxx:903
Int_t GetWeek(Bool_t inUTC=kTRUE, Int_t secOffset=0) const
Get the week of the year.
Definition: TTimeStamp.cxx:456
TTimeStamp()
Default ctor.
Definition: TTimeStamp.cxx:95
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
Double_t AsJulianDate() const
Definition: TTimeStamp.h:139
void Add(const TTimeStamp &offset)
Add "offset" as a delta time.
Definition: TTimeStamp.cxx:534
void Copy(TTimeStamp &ts) const
Copy this to ts.
Definition: TTimeStamp.cxx:343
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:418
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
Double_t AsGMST(Double_t UT1Offset=0) const
Return Greenwich mean sidereal time (GMST) in hour-angle.
Definition: TTimeStamp.cxx:168
void Print(const Option_t *option="") const
Print date and time.
Definition: TTimeStamp.cxx:544
Int_t fSec
Definition: TTimeStamp.h:81
void Set()
Set Date/Time to current time as reported by the system.
Definition: TTimeStamp.cxx:556
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
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
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
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
const char * AsString(const Option_t *option="") const
Return the date & time as a string.
Definition: TTimeStamp.cxx:271
Int_t fNanoSec
Definition: TTimeStamp.h:82
void NormalizeNanoSec()
Ensure that the fNanoSec field is in range [0,999999999].
Definition: TTimeStamp.cxx:739
This class implements a mutex interface.
Definition: TVirtualMutex.h:34
double T(double x)
Definition: ChebyshevPol.h:34
double Pi()
Mathematical constants.
Definition: Math.h:88
static constexpr double L
REAL epsilon
Definition: triangle.c:617