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
53
54
55TVirtualMutex *gTimeMutex = nullptr; // 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 constexpr std::size_t bufferSize = 64;
275
276 static Char_t formatted[nbuffers][bufferSize]; // strftime fields substituted
277 static Char_t formatted2[nbuffers][bufferSize]; // nanosec field substituted
278
279 static Int_t ibuffer = nbuffers;
280
282
283 ibuffer = (ibuffer+1)%nbuffers; // each call moves to next buffer
284
285 TString opt = option;
286 opt.ToLower();
287
288 if (opt.Contains("2")) {
289 // return string formatted as integer {sec,nsec}
290 snprintf(formatted[ibuffer], bufferSize, "{%d,%d}", fSec, fNanoSec);
291 return formatted[ibuffer];
292 }
293
294#ifdef R__LINUX
295 // under linux %z is the hour offset and %Z is the timezone name
296 const Char_t *kRFC822 = "%a, %d %b %Y %H:%M:%S %z (%Z) +#9ld nsec";
297 const Char_t *kISO8601 = "%Y-%m-%d %H:%M:%S.#9.9ld%z";
298 const Char_t *kISO8601Z = "%Y-%m-%d %H:%M:%S.#9.9ldZ";
299#else
300 // otherwise only %Z is guaranteed to be defined
301 const Char_t *kRFC822 = "%a, %d %b %Y %H:%M:%S %Z +#9ld nsec";
302 const Char_t *kISO8601 = "%Y-%m-%d %H:%M:%S.#9.9ld%Z";
303 const Char_t *kISO8601Z = "%Y-%m-%d %H:%M:%S.#9.9ldZ";
304#endif
305 const Char_t *kSQL = "%Y-%m-%d %H:%M:%S";
306
307 Bool_t asLocal = opt.Contains("l");
308 Bool_t asSQL = opt.Contains("s");
309 if (asSQL) asLocal = kFALSE;
310
311 const Char_t *format = kRFC822;
312 if (opt.Contains("c")) {
313 format = kISO8601;
314 if (!asLocal) format = kISO8601Z;
315 }
316 if (asSQL) format = kSQL;
317
318 // get the components into a tm struct
319 time_t seconds = (time_t) fSec;
320#ifndef R__WIN32
321 struct tm buf;
322 struct tm *ptm = (asLocal) ? localtime_r(&seconds, &buf) : gmtime_r(&seconds, &buf);
323#else
324 struct tm *ptm = (asLocal) ? localtime(&seconds) : gmtime(&seconds);
325#endif
326
327 // format all but the nsec field
328 // size_t length =
329 strftime(formatted[ibuffer], sizeof(formatted[ibuffer]), format, ptm);
330
331 if (asSQL) return formatted[ibuffer];
332
333 // hack in the nsec part
334 Char_t *ptr = strrchr(formatted[ibuffer], '#');
335 if (ptr) *ptr = '%'; // substitute % for #
336 snprintf(formatted2[ibuffer], bufferSize, formatted[ibuffer], fNanoSec);
337
338 return formatted2[ibuffer];
339}
340
341////////////////////////////////////////////////////////////////////////////////
342/// Copy this to ts.
343
345{
346 ts.fSec = fSec;
347 ts.fNanoSec = fNanoSec;
348}
349
350////////////////////////////////////////////////////////////////////////////////
351/// Return date in form of 19971224 (i.e. 24/12/1997),
352/// if non-zero pointers supplied for year, month, day fill those as well.
353
355 UInt_t *year, UInt_t *month, UInt_t *day) const
356{
357 time_t atime = fSec + secOffset;
358#ifndef R__WIN32
359 struct tm buf;
360 struct tm *ptm = (inUTC) ? gmtime_r(&atime, &buf) : localtime_r(&atime, &buf);
361#else
362 struct tm *ptm = (inUTC) ? gmtime(&atime) : localtime(&atime);
363#endif
364
365 if (day) *day = ptm->tm_mday;
366 if (month) *month = ptm->tm_mon + 1;
367 if (year) *year = ptm->tm_year + 1900;
368
369 return (1900+ptm->tm_year)*10000 + (1+ptm->tm_mon)*100 + ptm->tm_mday;
370}
371
372////////////////////////////////////////////////////////////////////////////////
373/// Return time in form of 123623 (i.e. 12:36:23),
374/// if non-zero pointers supplied for hour, min, sec fill those as well.
375
377 UInt_t *hour, UInt_t *min, UInt_t *sec) const
378{
379 time_t atime = fSec + secOffset;
380#ifndef R__WIN32
381 struct tm buf;
382 struct tm *ptm = (inUTC) ? gmtime_r(&atime, &buf) : localtime_r(&atime, &buf);
383#else
384 struct tm *ptm = (inUTC) ? gmtime(&atime) : localtime(&atime);
385#endif
386
387 if (hour) *hour = ptm->tm_hour;
388 if (min) *min = ptm->tm_min;
389 if (sec) *sec = ptm->tm_sec;
390
391 return ptm->tm_hour*10000 + ptm->tm_min*100 + ptm->tm_sec;
392}
393
394////////////////////////////////////////////////////////////////////////////////
395/// Get the day of the year represented by this time stamp value.
396/// Valid return values range between 1 and 366, where January 1 = 1.
397
399{
400 time_t atime = fSec + secOffset;
401#ifndef R__WIN32
402 struct tm buf;
403 struct tm *ptm = (inUTC) ? gmtime_r(&atime, &buf) : localtime_r(&atime, &buf);
404#else
405 struct tm *ptm = (inUTC) ? gmtime(&atime) : localtime(&atime);
406#endif
407
408 Int_t day = ptm->tm_mday;
409 Int_t month = ptm->tm_mon + 1;
410 Int_t year = ptm->tm_year + 1900;
411
412 return GetDayOfYear(day, month, year);
413}
414
415////////////////////////////////////////////////////////////////////////////////
416/// Method is using Zeller's formula for calculating the day number.
417/// Valid return values range between 1 and 7, where Monday = 1.
418
420{
421 time_t atime = fSec + secOffset;
422#ifndef R__WIN32
423 struct tm buf;
424 struct tm *ptm = (inUTC) ? gmtime_r(&atime, &buf) : localtime_r(&atime, &buf);
425#else
426 struct tm *ptm = (inUTC) ? gmtime(&atime) : localtime(&atime);
427#endif
428
429 Int_t day = ptm->tm_mday;
430 Int_t month = ptm->tm_mon + 1;
431 Int_t year = ptm->tm_year + 1900;
432
433 return GetDayOfWeek(day, month, year);
434}
435
436////////////////////////////////////////////////////////////////////////////////
437/// Get the month of the year. Valid return values are between 1 and 12.
438
439Int_t TTimeStamp::GetMonth(Bool_t inUTC, Int_t secOffset) const
440{
441 time_t atime = fSec + secOffset;
442#ifndef R__WIN32
443 struct tm buf;
444 struct tm *ptm = (inUTC) ? gmtime_r(&atime, &buf) : localtime_r(&atime, &buf);
445#else
446 struct tm *ptm = (inUTC) ? gmtime(&atime) : localtime(&atime);
447#endif
448
449 return ptm->tm_mon + 1;
450}
451
452////////////////////////////////////////////////////////////////////////////////
453/// Get the week of the year. Valid week values are between 1 and 53.
454/// The return value is the year*100+week (1 Jan may be in the last
455/// week of the previous year so the year must be returned too).
456
457Int_t TTimeStamp::GetWeek(Bool_t inUTC, Int_t secOffset) const
458{
459 time_t atime = fSec + secOffset;
460#ifndef R__WIN32
461 struct tm buf;
462 struct tm *ptm = (inUTC) ? gmtime_r(&atime, &buf) : localtime_r(&atime, &buf);
463#else
464 struct tm *ptm = (inUTC) ? gmtime(&atime) : localtime(&atime);
465#endif
466
467 Int_t day = ptm->tm_mday;
468 Int_t month = ptm->tm_mon + 1;
469 Int_t year = ptm->tm_year + 1900;
470
471 return GetWeek(day, month, year);
472}
473
474////////////////////////////////////////////////////////////////////////////////
475/// Is the year a leap year.
476/// The calendar year is 365 days long, unless the year is exactly divisible
477/// by 4, in which case an extra day is added to February to make the year
478/// 366 days long. If the year is the last year of a century, eg. 1700, 1800,
479/// 1900, 2000, then it is only a leap year if it is exactly divisible by
480/// 400. Therefore, 1900 wasn't a leap year but 2000 was. The reason for
481/// these rules is to bring the average length of the calendar year into
482/// line with the length of the Earth's orbit around the Sun, so that the
483/// seasons always occur during the same months each year.
484
486{
487 time_t atime = fSec + secOffset;
488#ifndef R__WIN32
489 struct tm buf;
490 struct tm *ptm = (inUTC) ? gmtime_r(&atime, &buf) : localtime_r(&atime, &buf);
491#else
492 struct tm *ptm = (inUTC) ? gmtime(&atime) : localtime(&atime);
493#endif
494
495 Int_t year = ptm->tm_year + 1900;
496
497 return IsLeapYear(year);
498}
499
500////////////////////////////////////////////////////////////////////////////////
501/// Static method returning local (current) time zone offset from UTC.
502/// This is the value in seconds one must add to the local time to arrive at
503/// Coordinated Universal Time, so it is negative east of the Prime Meridian.
504
506{
507 // ?? should tzset (_tzset) be called?
508#ifndef R__WIN32
509 tzset();
510#if defined(R__WINGCC)
511 return _timezone;
512#else
513#if !defined(R__FBSD) && !defined(R__OBSD)
514 return timezone; // unix has extern long int
515#else
516 time_t tp = 0;
517 time(&tp);
518#ifndef R__WIN32
519 struct tm buf;
520 return -localtime_r(&tp, &buf)->tm_gmtoff;
521#else
522 return -localtime(&tp)->tm_gmtoff;
523#endif
524#endif
525#endif
526#else
527 _tzset();
528 return _timezone; // Win32 prepends "_"
529#endif
530}
531
532////////////////////////////////////////////////////////////////////////////////
533/// Add "offset" as a delta time.
534
536{
537 fSec += offset.fSec;
538 fNanoSec += offset.fNanoSec;
540}
541
542////////////////////////////////////////////////////////////////////////////////
543/// Print date and time.
544
546{
547 printf("Date/Time = %s\n", AsString(option));
548}
549
550////////////////////////////////////////////////////////////////////////////////
551/// Set Date/Time to current time as reported by the system.
552/// No accounting for nanoseconds with std ANSI functions,
553/// ns part faked so that subsequent calls simply add 1 to it
554/// this ensures that calls within the same second come back
555/// distinct (and sortable). Time is since Jan 1, 1970.
556
558{
559#ifdef R__WIN32
560 ULARGE_INTEGER time;
561 GetSystemTimeAsFileTime((FILETIME *)&time);
562 // NT keeps time in FILETIME format which is 100ns ticks since
563 // Jan 1, 1601. TTimeStamp uses time in 100ns ticks since Jan 1, 1970,
564 // the difference is 134774 days.
565 fNanoSec = Int_t((time.QuadPart * (unsigned __int64) 100) %
566 (unsigned __int64) 1000000000);
567 time.QuadPart -=
568 (unsigned __int64) (1000*1000*10) // seconds
569 * (unsigned __int64) (60 * 60 * 24) // days
570 * (unsigned __int64) (134774); // # of days
571
572 fSec = Int_t(time.QuadPart/(unsigned __int64) (1000*1000*10));
573#else
574 struct timeval tp;
575 gettimeofday(&tp, nullptr);
576 fSec = tp.tv_sec;
577 fNanoSec = tp.tv_usec*1000;
578#endif
579
580 static Int_t sec = 0, nsec = 0, fake_ns = 0;
581
583
584 if (fSec == sec && fNanoSec == nsec)
585 fNanoSec += ++fake_ns;
586 else {
587 fake_ns = 0;
588 sec = fSec;
589 nsec = fNanoSec;
590 }
591}
592
593////////////////////////////////////////////////////////////////////////////////
594/// Set Date/Time from components.
595///
596/// Month & day both use normal 1..12 and 1..31 counting,
597/// hours, min, sec run from 0 to 23, 59, 59 respectively,
598/// secOffset provides method for adjusting for alternative timezones
599///
600/// ~~~ {.cpp}
601/// "year" | 0 1 ... 37 | 38...69 | 70 .. 100 101 .. 137
602/// true | 2000 2001 2037 | undefined | 1970 2000 2001 .. 2037
603///
604/// "year" | 138...1969 | 1970 .. 2037 | ...
605/// true | undefined | 1970 .. 2037 | undefined
606/// ~~~
607
608void TTimeStamp::Set(Int_t year, Int_t month, Int_t day,
609 Int_t hour, Int_t min, Int_t sec,
610 Int_t nsec, Bool_t isUTC, Int_t secOffset)
611{
612 // deal with special formats of year
613 if (year <= 37) year += 2000;
614 if (year >= 70 && year <= 137) year += 1900;
615 // tm.tm_year is years since 1900
616 if (year >= 1900) year -= 1900;
617
618 struct tm tmstruct;
619 tmstruct.tm_year = year; // years since 1900
620 tmstruct.tm_mon = month-1; // months since Jan [0,11]
621 tmstruct.tm_mday = day; // day of the month [1,31]
622 tmstruct.tm_hour = hour; // hours since midnight [0,23]
623 tmstruct.tm_min = min; // minutes after the hour [0,59]
624 tmstruct.tm_sec = sec + secOffset; // seconds after the minute [0,59]
625 tmstruct.tm_isdst = -1; // let "mktime" determine DST setting
626
627 const time_t bad_time_t = (time_t) -1;
628 // convert tm struct to time_t, if values are given in UTC then
629 // no standard routine exists and we'll have to use our homegrown routine,
630 // if values are given in local time then use "mktime"
631 // which also normalizes the tm struct as a byproduct
632 time_t utc_sec = (isUTC) ? MktimeFromUTC(&tmstruct) : mktime(&tmstruct);
633
634 if (utc_sec == bad_time_t)
635 Error("TTimeStamp::Set","mktime returned -1");
636
637 fSec = utc_sec;
638 fNanoSec = nsec;
639
641}
642
643////////////////////////////////////////////////////////////////////////////////
644/// Set date/time from integers of the form [yy]YYMMDD and HHMMSS,
645/// assume UTC (UTC) components:
646///
647/// ~~~ {.cpp}
648/// MM: 01=January .. 12=December
649/// DD: 01 .. 31
650///
651/// HH: 00=midnight .. 23
652/// MM: 00 .. 59
653/// SS: 00 .. 69
654/// ~~~
655///
656/// - Date must be in format 980418 or 19980418
657/// 1001127 or 20001127 (i.e. year 100 = 2000),
658/// - time must be in format 224512 (second precision),
659/// - date must be >= 700101.
660
661void TTimeStamp::Set(Int_t date, Int_t time, Int_t nsec,
662 Bool_t isUTC, Int_t secOffset)
663{
664 Int_t year = date/10000;
665 Int_t month = (date-year*10000)/100;
666 Int_t day = date%100;
667
668 // protect against odd attempts at time offsets
669 const Int_t oneday = 240000;
670 while (time < 0) {
671 time += oneday;
672 day -= 1;
673 }
674 while (time > oneday) {
675 time -= oneday;
676 day += 1;
677 }
678 Int_t hour = time/10000;
679 Int_t min = (time-hour*10000)/100;
680 Int_t sec = time%100;
681
682 Set(year, month, day, hour, min, sec, nsec, isUTC, secOffset);
683}
684
685////////////////////////////////////////////////////////////////////////////////
686/// The input arg is a time_t value returned by time() or a value
687/// returned by Convert(). This value is the number of seconds since
688/// the EPOCH (i.e. 00:00:00 on Jan 1m 1970). If dosDate is true then
689/// the input is a dosDate value.
690
691void TTimeStamp::Set(UInt_t tloc, Bool_t isUTC, Int_t secOffset, Bool_t dosDate)
692{
693 struct tm localtm;
694 memset (&localtm, 0, sizeof (localtm));
695
696 if (dosDate) {
697 localtm.tm_year = ((tloc >> 25) & 0x7f) + 80;
698 localtm.tm_mon = ((tloc >> 21) & 0xf);
699 localtm.tm_mday = (tloc >> 16) & 0x1f;
700 localtm.tm_hour = (tloc >> 11) & 0x1f;
701 localtm.tm_min = (tloc >> 5) & 0x3f;
702 localtm.tm_sec = (tloc & 0x1f) * 2 + secOffset;
703 localtm.tm_isdst = -1;
704 } else {
705 time_t t = (time_t) tloc;
706#ifndef R__WIN32
707 struct tm tpa;
708 struct tm *tp = localtime_r(&t, &tpa);
709#else
710 struct tm *tp = localtime(&t);
711#endif
712 localtm.tm_year = tp->tm_year;
713 localtm.tm_mon = tp->tm_mon;
714 localtm.tm_mday = tp->tm_mday;
715 localtm.tm_hour = tp->tm_hour;
716 localtm.tm_min = tp->tm_min;
717 localtm.tm_sec = tp->tm_sec + secOffset;
718 localtm.tm_isdst = -1;
719 }
720
721 const time_t bad_time_t = (time_t) -1;
722 // convert tm struct to time_t, if values are given in UTC then
723 // no standard routine exists and we'll have to use our homegrown routine,
724 // if values are given in local time then use "mktime"
725 // which also normalizes the tm struct as a byproduct
726 time_t utc_sec = (isUTC && dosDate) ? MktimeFromUTC(&localtm) : mktime(&localtm);
727
728 if (utc_sec == bad_time_t)
729 Error("TTimeStamp::Set","mktime returned -1");
730
731 fSec = utc_sec;
732 fNanoSec = 0; //nsec;
733
735}
736
737////////////////////////////////////////////////////////////////////////////////
738/// Ensure that the fNanoSec field is in range [0,999999999].
739
741{
742 const Int_t kNsPerSec = 1000000000;
743 // deal with negative values
744 while (fNanoSec < 0) {
745 fNanoSec += kNsPerSec;
746 fSec -= 1;
747 }
748
749 // deal with values inf fNanoSec greater than one sec
750 while (fNanoSec >= kNsPerSec) {
751 fNanoSec -= kNsPerSec;
752 fSec += 1;
753 }
754}
755
756////////////////////////////////////////////////////////////////////////////////
757/// Equivalent of standard routine "mktime" but
758/// using the assumption that tm struct is filled with UTC, not local, time.
759///
760/// This version *ISN'T* configured to handle every possible
761/// weirdness of out-of-range values in the case of normalizing
762/// the tm struct.
763///
764/// This version *DOESN'T* correctly handle values that can't be
765/// fit into a time_t (i.e. beyond year 2038-01-18 19:14:07, or
766/// before the start of Epoch).
767
769{
770 Int_t daysInMonth[] = { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
771 Int_t year = tmstruct->tm_year + 1900;
772 daysInMonth[1] = IsLeapYear(year) ? 29 : 28;
773
774 // fill in tmstruct->tm_yday
775
776 Int_t &ref_tm_mon = tmstruct->tm_mon;
777 Int_t &ref_tm_mday = tmstruct->tm_mday;
778 // count days in months past
779 tmstruct->tm_yday = 0;
780 for (Int_t imonth = 0; imonth < ref_tm_mon; imonth++) {
781 tmstruct->tm_yday += daysInMonth[imonth];
782 }
783 tmstruct->tm_yday += ref_tm_mday - 1; // day [1-31] but yday [0-365]
784
785 // adjust if day in this month is more than the month has
786 while (ref_tm_mday > daysInMonth[ref_tm_mon]) {
787 ref_tm_mday -= daysInMonth[ref_tm_mon];
788 ref_tm_mon++;
789 }
790
791 // *should* calculate tm_wday (0-6) here ...
792
793 // UTC is never DST
794 tmstruct->tm_isdst = 0;
795
796 // Calculate seconds since the Epoch based on formula in
797 // POSIX IEEEE Std 1003.1b-1993 pg 22
798
799 Int_t utc_sec = tmstruct->tm_sec +
800 tmstruct->tm_min*60 +
801 tmstruct->tm_hour*3600 +
802 tmstruct->tm_yday*86400 +
803 (tmstruct->tm_year-70)*31536000 +
804 ((tmstruct->tm_year-69)/4)*86400;
805
806 return utc_sec;
807}
808
809////////////////////////////////////////////////////////////////////////////////
810/// Get the day of the year represented by day, month and year.
811/// Valid return values range between 1 and 366, where January 1 = 1.
812
814{
815 Int_t dayOfYear = 0;
816 Int_t daysInMonth[] = { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
817 daysInMonth[1] = IsLeapYear(year) ? 29 : 28;
818
819 for (Int_t i = 0; i < (month - 1); i++)
820 dayOfYear += daysInMonth[i];
821 dayOfYear += day;
822
823 return dayOfYear;
824}
825
826////////////////////////////////////////////////////////////////////////////////
827/// Method is using Zeller's formula for calculating the day number.
828/// Valid return values range between 1 and 7, where Monday = 1.
829
831{
832 Int_t dayno;
833
834 if (month < 3) {
835 year--;
836 month += 12;
837 }
838
839 dayno = 1 + day + 2*month + 3*(month + 1)/5 + year + year/4 - year/100 + year/400;
840 dayno %= 7;
841
842 // make monday first day of week
843 return ((dayno == 0) ? 7 : dayno);
844}
845
846////////////////////////////////////////////////////////////////////////////////
847/// Get the week of the year. Valid week values are between 1 and 53.
848/// The return value is the year*100+week (1 Jan may be in the last
849/// week of the previous year so the year must be returned too).
850
852{
853 Int_t dayOfYear = GetDayOfYear(day, month, year);
854 Int_t dayJan1st = GetDayOfWeek(1, 1, year);
855 Int_t week = (dayOfYear + dayJan1st - 2) / 7 + 1;
856
857 if (dayJan1st > 4)
858 week--;
859
860 if (week == 53) {
861 Int_t dayNextJan1st = GetDayOfWeek(1, 1, year + 1);
862 if (dayNextJan1st > 1 && dayNextJan1st < 5) {
863 year++;
864 week = 1;
865 }
866 } else if (week == 0) {
867 Int_t dayPrevJan1st = GetDayOfWeek(1, 1, year - 1);
868 week = (dayPrevJan1st < 5 && dayJan1st > 4) ? 53 : 52;
869 year--;
870 }
871 return year * 100 + week;
872}
873
874////////////////////////////////////////////////////////////////////////////////
875/// Is the given year a leap year.
876/// The calendar year is 365 days long, unless the year is exactly divisible
877/// by 4, in which case an extra day is added to February to make the year
878/// 366 days long. If the year is the last year of a century, eg. 1700, 1800,
879/// 1900, 2000, then it is only a leap year if it is exactly divisible by
880/// 400. Therefore, 1900 wasn't a leap year but 2000 was. The reason for
881/// these rules is to bring the average length of the calendar year into
882/// line with the length of the Earth's orbit around the Sun, so that the
883/// seasons always occur during the same months each year.
884
886{
887 return (year % 4 == 0) && !((year % 100 == 0) && (year % 400 > 0));
888}
889
890////////////////////////////////////////////////////////////////////////////////
891/// Print out the "tm" structure:
892/// ~~~ {.cpp}
893/// tmstruct.tm_year = year; // years since 1900
894/// tmstruct.tm_mon = month-1; // months since Jan [0,11]
895/// tmstruct.tm_mday = day; // day of the month [1,31]
896/// tmstruct.tm_hour = hour; // hours since midnight [0,23]
897/// tmstruct.tm_min = min; // minutes after the hour [0,59]
898/// tmstruct.tm_sec = sec; // seconds after the minute [0,59]
899/// tmstruct.tm_wday // day of week [0,6]
900/// tmstruct.tm_yday // days in year [0,365]
901/// tmstruct.tm_isdst // DST [-1/0/1] (unknown,false,true)
902/// ~~~
903
904void TTimeStamp::DumpTMStruct(const tm_t &tmstruct)
905{
906 printf(" tm { year %4d, mon %2d, day %2d,\n",
907 tmstruct.tm_year,
908 tmstruct.tm_mon,
909 tmstruct.tm_mday);
910 printf(" hour %2d, min %2d, sec %2d,\n",
911 tmstruct.tm_hour,
912 tmstruct.tm_min,
913 tmstruct.tm_sec);
914 printf(" wday %2d, yday %3d, isdst %2d",
915 tmstruct.tm_wday,
916 tmstruct.tm_yday,
917 tmstruct.tm_isdst);
918#if (defined(linux) && !defined(R__WINGCC)) || defined(R__MACOSX)
919 printf(",\n tm_gmtoff %6ld, tm_zone \"%s\"",
920#if defined(__USE_BSD) || defined(R__MACOSX) || defined(__USE_MISC)
921 tmstruct.tm_gmtoff, tmstruct.tm_zone);
922#else
923 tmstruct.__tm_gmtoff, tmstruct.__tm_zone);
924#endif
925#endif
926 printf(" }\n");
927}
int Int_t
Definition RtypesCore.h:45
char Char_t
Definition RtypesCore.h:37
constexpr Bool_t kFALSE
Definition RtypesCore.h:101
const char Option_t
Definition RtypesCore.h:66
#define ClassImp(name)
Definition Rtypes.h:377
TBuffer & operator<<(TBuffer &buf, const Tmpl *obj)
Definition TBuffer.h:397
void Error(const char *location, const char *msgfmt,...)
Use this function in case an error occurred.
Definition TError.cxx:185
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
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:1540
Buffer base class used for serializing objects.
Definition TBuffer.h:43
void Streamer(TBuffer &) override
Stream an object of class TObject.
Basic string class.
Definition TString.h:139
void ToLower()
Change string to lower-case.
Definition TString.cxx:1182
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition TString.h:632
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.
virtual void Streamer(TBuffer &)
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.