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