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