NCFS-Pack
A generic (astro)particle physics analysis framework
Loading...
Searching...
No Matches
NcTimestamp.cxx
Go to the documentation of this file.
1
31
33
79// by the introduction of Leap Seconds when abs(UT1-UTC) exceeds 0.9 sec.
80// This time synchronisation is coordinated by the International Earth Rotation and
81// Reference Systems Service (IERS) via a daily monitoring of the Earth Orientation
82// Parameters (EOP).
83// Depending on dUT=UT1-UTC, these Leap Seconds can be positive or negative.
84// The introduction of Leap Seconds into UTC started at 01-jan-1972 00:00:00 UT.
85//
86// An overview of the history of introduced Leap seconds (TAI-UTC) is online available at :
87// https://hpiers.obspm.fr/iers/bul/bulc/Leap_Second.dat
88// or http://maia.usno.navy.mil/ser7/tai-utc.dat
89//
90// The time difference dUT=UT1-UTC is monitored on a daily basis and the data are available at :
91// https://hpiers.obspm.fr/iers/series/opa/eopc04
92// or http://maia.usno.navy.mil/ser7/ser7.dat
93//
94// The accuracy of dUT=UT1-UTC is about 10 microseconds, so in case of accurate astronomical
95// timing the user is advised to specify dUT in the various Set() facilities or use SetUT().
96// An automatic setting of dUT is provided based on the IERS data files.
97// Please refer to the member function LoadUTCparameterFiles() for further details.
98//
99// 4) In some cases Unix Time (also called POSIX Time or UNIX Epoch Time) is used.
100// Unix Time is closely releated to UTC and represents the (fractional) elapsed second count
101// since the start of the Unix Epoch, in which every Unix Time day contains exactly 86400 seconds.
102// This implies that for Unix Time the UTC leap seconds should be ignored, as explained below.
103// The UNIX Time EPOCH starts at 01-jan-1970 00:00:00 UTC which corresponds to JD=2440587.5
104// (i.e. the start of MJD=40587, as explained in the discussion on Julian Date below).
105// Synchronization with UTC is obtained by continuing the second count when a UTC leap second
106// occurs and then the Unix Time count jumps up or down 1 second at the beginning of the new
107// day after the UTC leap second has expired.
108// In case of a negative UTC leap second (which has not occurred so far) this would result
109// in a jump forward of 1 second in Unix Time, introducing a "gap" of 1 second in the timing
110// at the start of the new day.
111// In case of a positive UTC leap second this results in a jump back of 1 second in Unix Time
112// at the start of a new day.
113// In this case there exist 2 ambiguous Unix Times over a 1 second time interval,
114// namely at the beginning of the introduction of the UTC leap second and at the moment that
115// the UTC leap second expires, i.e. the start of the new day.
116// This NcTimestamp facility provides setting and retrieval of Unix Time, but for accurate
117// timing the user is advised to use one of the time scales mentioned below.
118//
119// Supported time scales :
120// ----------------------
121// UT : Universal Time.
122// 1 day is the time span between two successive solar meridian transitions.
123// This implies that UT is based on the actual rotation of the Earth and as such suited
124// for (synchronization of) astronomical observations at various locations on Earth.
125// The reference time is defined by transitions over the meridian at Greenwich.
126// ST : Siderial Time (see also the details below).
127// 1 day is the time span between two successive stellar meridian transitions.
128// This implies that ST is based on the actual rotation of the Earth and its rotation
129// around the Sun. Siderial Time is very well suited for astronomical observations.
130// The reference time is defined by transitions over the meridian at Greenwich.
131// Because of the stability of the rotation of the Earth around the Sun, the Siderial Time
132// is derived from the Universal Time and as such not treated as a separate time scale.
133// TAI : International Atomic Time (Temps Atomique International).
134// 1 day is the time span of 86400 standard atomic (SI) seconds at average sea level.
135// The standard atomic (SI) second is derived from a set of Cs atomic clocks.
136// This implies that TAI is not related to the actual rotation of the Earth and as such
137// will not run at the same pace as UT.
138// The start epoch of TAI is 01-jan-1958 00:00:00 UT, at which time UT1-UTC was about 0.
139// GPS : Global Positioning System time.
140// This satellite based timing system is based on TAI and broadcast via a satellite network.
141// The start epoch of GPS is 06-jan-1980 00:00:00 UTC, at which the number of Leap Seconds was 19.
142// This implies that at that time TAI=UTC+19 sec. and consequently we always have TAI=GPS+19 sec.
143// GPS is broadcast in two formats : (w,sow) and (w,dow,sod) with
144// w = week number after the start epoch. 1 week=7 days or 1 week=604800 seconds.
145// sow = (fractional) second count in the current week
146// dow = day number in the current week (sunday=0, monday=1 etc.)
147// sod = (fractional) second count in the current day
148// Early implementations used to reset the week count after a cycle of 1024 weeks and
149// provided the corresponding cycle count. Please refer to the SetGPS() memberfunctions
150// for further details.
151// TT : Terrestrial Time.
152// This timing system is based on TAI and provides the date/time at average sea level.
153// It has been introduced for observations from the surface of the Earth, to be consistent
154// with General Relativity. Since planetary orbits are very stable in time and not related
155// to the rotation of the Earth, TT is mainly used for observations of the Solar system.
156// TT was synchronized with TAI at 01-jan-1977 00:00:00 TAI, to indicate 00:00:32.184 in
157// order to provide a continuation of its (now obsolete) predecessor Ephemeris Time (ET).
158// This implies that always TT=TAI+32.184 sec.
159//
160// All Gregorian dates/times (e.g. 12-aug-1982 13:20:12) are treated on basis of
161// the time scales mentioned above. So, there is no need for leap second treatment
162// like this is the case for Coordinated Universal Time (UTC).
163//
164// In order to enable a precise measurement of elapsed time over (very) long periods,
165// a continuous day counting system has been introduced, called the Julian Date.
166// The Julian Date (JD) indicates the number of days since noon (12:00:00) on
167// 01 jan -4712 (i.e. noon 01 jan 4713 BC), being day 0 of the Julian calendar.
168// It is custom to couple the Julian Date to UT so that it serves astronomical observations.
169// However, this NcTimestamp facility allows to use a continuous day counting system
170// with all the supported time scales mentioned above.
171//
172// The Modified Julian Date (MJD) indicates the number of days since midnight (00:00:00)
173// on 17-nov-1858, which corresponds to 2400000.5 days after day 0 of the
174// Julian calendar.
175//
176// The Truncated Julian Date (TJD) corresponds to 2440000.5 days after day 0
177// of the Julian calendar and consequently TJD=MJD-40000.
178// This TJD date indication was used by the Vela and CGRO satellite missions in
179// view of Gamma Ray Burst investigations.
180//
181// The Julian Epoch (JE) indicates the fractional elapsed Julian year count
182// since the start of the Gregorian year count.
183// A Julian year is defined to be 365.25 days and starts at 01-jan 12:00:00.
184// As such, the integer part of JE corresponds to the usual Gregorian year count,
185// apart from 01-jan before 12:00:00.
186// So, 01-jan-1965 12:00:00 UT corresponds to JE=1965.0
187//
188// The Besselian Epoch (BE) indicates the fractional elapsed Besselian year count
189// since the start of the Gregorian year count.
190// A Besselian (or tropical) year is defined to be 365.242198781 days.
191// The date 31-dec-1949 22:09:46.862 UT corresponds to BE=1950.0
192//
193// The Besselian and Julian epochs are used in astronomical catalogs
194// to denote values of time varying observables like e.g. right ascension.
195//
196// Because of the fact that the Julian date indicators are all w.r.t. UT or TAI derived
197// time scales, they provide an absolute time scale irrespective of timezone or daylight
198// saving time (DST).
199//
200// In view of astronomical observations and positioning it is convenient
201// to have also a UT equivalent related to stellar meridian transitions.
202// This is achieved by the Greenwich Sidereal Time (GST).
203// The GST is defined as the right ascension of the objects passing
204// the meridian over Greenwich.
205// Due to the rotation of the Earth around the Sun, a sidereal day
206// lasts 86164.09 seconds (23h 56m 04.09s) compared to the mean solar
207// day of 86400 seconds (24h).
208// Furthermore, precession of the earth's spin axis results in the fact
209// that the zero point of right ascension (vernal equinox) gradually
210// moves along the celestial equator.
211// In addition, tidal friction and ocean and atmospheric effects will
212// induce seasonal variations in the earth's spin rate and polar motion
213// of the earth's spin axis.
214// Taking the above effects into account leads to what is called
215// the Greenwich Mean Sidereal Time (GMST).
216// In case also the nutation of the earth's spin axis is taken into
217// account we speak of the Greenwich Apparent Sidereal Time (GAST).
218//
219// This NcTimestamp facility allows for picosecond precision, in view
220// of time of flight analyses for particle physics experiments.
221// For normal date/time indication the standard nanosecond precision
222// will in general be sufficient.
223// Picosecond precision can be obtained by invokation of GetPs() or GetDifference().
224// Note that when the fractional JD, MJD and TJD counts are used instead
225// of the integer (days,sec,ns) specification, the nanosecond precision
226// may be lost due to computer accuracy w.r.t. floating point operations.
227//
228// The TTimeStamp EPOCH starts at 01-jan-1970 00:00:00
229// which corresponds to JD=2440587.5 or the start of MJD=40587 or TJD=587.
230// Using the corresponding MJD of this EPOCH allows construction of
231// the yy-mm-dd hh:mm:ss:ns TTimeStamp from a given input (M/T)JD and time.
232// Obviously this TTimeStamp implementation would prevent usage of values
233// smaller than JD=2440587.5 or MJD=40587 or TJD=587.
234// Furthermore, due to a limitation on the "seconds since the EPOCH start" count
235// in TTimeStamp, the latest accessible date/time is until 19-jan-2038 02:14:07.
236// However, this NcTimestamp facility provides support for the full range
237// of (M/T)JD values, but the setting of the corresponding TTimeStamp parameters
238// is restricted to the values allowed by the TTimeStamp implementation.
239// For these earlier/later (M/T)JD values, the standard TTimeStamp parameters will
240// be set corresponding to the start of the TTimeStamp EPOCH.
241// This implies that for these earlier/later (M/T)JD values the TTimeStamp parameters
242// do not match the Julian parameters of NcTimestamp.
243// As such the standard TTimeStamp parameters do not appear on the print output
244// when invoking the Date() memberfunction for these earlier/later (M/T)JD values.
245//
246// Examples :
247// ==========
248//
249// Note : All TTimeStamp functionality is available as well.
250//
251// NcTimestamp t;
252//
253// t.Date();
254//
255// // Set a specific Date/Time in Universal Time (UT1)
256// // without recording UTC nor the corresponding International Atomic Time (TAI)
257// t.SetUT("22-08-2016","14:03:29.7358",0,"U");
258//
259// // Set a specific Date/Time in Universal Time (UTC)
260// // without recording UT1 nor the corresponding International Atomic Time (TAI)
261// t.SetUT("22-08-2016","14:03:29.7358",0,"N");
262//
263// // Set a specific Date/Time in Universal Time (UTC)
264// // and also record UT1 and the corresponding International Atomic Time (TAI)
265// // using manual "leap" and "dut" settings
266// Int_t leap=34;
267// Double_t dut=-0.14;
268// t.SetUT("17-05-2011","05:43:18.31468",0,"M",leap,dut);
269//
270// // Set a specific Date/Time in Universal Time (UTC)
271// // and also record UT1 and the corresponding International Atomic Time (TAI)
272// // using automatic "leap" and "dut" settings from the IERS data files
273// t.LoadUTCparameterFiles("leap.txt","dut.txt");
274// t.SetUT("17-05-2011","05:43:18.31468",0,"A");
275//
276// // Set a specific Date/Time in Global Positioning System time (GPS)
277// // and also record the corresponding Universal Times (UTC and UT1) and TAI
278// // using automatic "leap" and "dut" settings from the IERS data files
279// t.LoadUTCparameterFiles("leap.txt","dut.txt");
280// t.SetTAI("GPS","17-05-2011","05:43:18.31468",0,"A",0,0);
281//
282// // Retrieve Julian Date to ns precision
283// Int_t jd,jsec,jns;
284// t.GetJD(jd,jsec,jns);
285// // Get the remaining ps precision
286// Int_t ps=GetPs();
287//
288// // Retrieve fractional Truncated Julian Date
289// Double_t tjd=t.GetTJD();
290//
291// // Retrieve fractional Julian Epoch
292// Double_t je=t.GetJE();
293//
294// // Set to a specific Modified Julian Date representing UTC
295// // without recording the corresponding International Atomic Time (TAI)
296// Int_t mjd=50537;
297// Int_t mjsec=1528;
298// Int_t mjns=185643;
299// Int_t mjps=35;
300// t.SetMJD(mjd,mjsec,mjns,mjps,"N");
301//
302// t.Date();
303//
304// // Set to a specific Modified Julian Date representing UTC
305// // and also record the corresponding International Atomic Time (TAI)
306// // using automatic "leap" and "dut" settings from the IERS data files
307// Int_t mjd=58457;
308// Int_t mjsec=1528;
309// Int_t mjns=185643;
310// Int_t mjps=35;
311// t.LoadUTCparameterFiles("leap.txt","dut.txt");
312// t.SetMJD(mjd,mjsec,mjns,mjps,"A");
313//
314// t.Date();
315//
316// // Set to a specific Modified Julian Date representing UT1
317// // and also record the corresponding International Atomic Time (TAI)
318// // using automatic "leap" and "dut" settings from the IERS data files
319// Int_t mjd=58457;
320// Int_t mjsec=1528;
321// Int_t mjns=185643;
322// Int_t mjps=35;
323// t.LoadUTCparameterFiles("leap.txt","dut.txt");
324// t.SetMJD(mjd,mjsec,mjns,mjps,"U");
325//
326// t.Date();
327//
328// // Time intervals for e.g. Trigger or Time Of Flight analysis
329// NcEvent evt;
330// NcTrack* tx=evt.GetTrack(5);
331// NcTimestamp* timex=tx->GetTimestamp();
332// Double_t dt=evt.GetDifference(timex,"ps");
333// NcTimestamp trig((NcTimestamp)evt);
334// trig.Add(0,0,2,173);
335// NcSignal* sx=evt.GetHit(23);
336// NcTimestamp* timex=sx->GetTimestamp();
337// Double_t dt=trig.GetDifference(timex,"ps");
338// Int_t d,s,ns,ps;
339// trig.GetDifference(timex,d,s,ns,ps);
340//
341// // Some practical conversion facilities
342// // Note : They don't influence the actual date/time settings
343// // and as such can also be invoked as NcTimestamp::Convert(...) etc...
344// Int_t y=1921;
345// Int_t m=7;
346// Int_t d=21;
347// Int_t hh=15;
348// Int_t mm=23;
349// Int_t ss=47;
350// Int_t ns=811743;
351// Double_t jdate=t.GetJD(y,m,d,hh,mm,ss,ns);
352//
353// Int_t days,secs,nsecs;
354// Double_t date=421.1949327;
355// t.Convert(date,days,secs,nsecs);
356//
357// days=875;
358// secs=23;
359// nsecs=9118483;
360// date=t.Convert(days,secs,nsecs);
361//
362// Double_t mjdate=40563.823744;
363// Double_t epoch=t.GetJE(mjdate,"mjd");
364//
365//--- Author: Nick van Eijndhoven 28-jan-2005 Utrecht University
366//- Modified: Nick van Eijndhoven, IIHE-VUB Brussel, UTC June 28, 2026 11:10
367~~~
368**/
370
371#include "NcTimestamp.h"
372#include "Riostream.h"
373
374ClassImp(NcTimestamp); // Class implementation to enable ROOT I/O
375
378{
387
388 FillJulian();
389 fJps=0;
390 fUtc=0;
391 fLeap=0;
392 fDut=0;
393 fTmjd=0;
394 fTsec=0;
395 fTns=0;
396 fTps=0;
397 fUTCdata=0;
398}
399
400NcTimestamp::NcTimestamp(TTimeStamp& t) : TTimeStamp(t)
401{
408
409 FillJulian();
410 fJps=0;
411 fUtc=0;
412 fLeap=0;
413 fDut=0;
414 fTmjd=0;
415 fTsec=0;
416 fTns=0;
417 fTps=0;
418 fUTCdata=0;
419}
420
422{
428
429 if (fUTCdata)
430 {
431 delete fUTCdata;
432 fUTCdata=0;
433 }
434}
435
436NcTimestamp::NcTimestamp(const NcTimestamp& t) : TTimeStamp(t)
437{
443
444 fMJD=t.fMJD;
445 fJsec=t.fJsec;
446 fJns=t.fJns;
447 fJps=t.fJps;
448 fCalcs=t.fCalcs;
450 fUtc=t.fUtc;
451 fLeap=t.fLeap;
452 fDut=t.fDut;
453 fTmjd=t.fTmjd;
454 fTsec=t.fTsec;
455 fTns=t.fTns;
456 fTps=t.fTps;
457 fUTCdata=0;
458 TTree* tx=t.fUTCdata;
459 if (tx) fUTCdata=(TTree*)tx->Clone();
460}
461
463{
469
470 NcTimestamp ts(t);
471
472 fUTCdata=0;
473 TTree* tx=ts.fUTCdata;
474 if (tx) fUTCdata=(TTree*)tx->Clone();
475
476 Int_t mjd=0;
477 Int_t sec=0;
478 Int_t ns=0;
479 Int_t ps=0;
480 Int_t leap=0;
481 Double_t dut=0;
482
483 ts.GetMJD(mjd,sec,ns);
484 ps=ts.fJps;
485
486 Int_t flag=ts.GetUTCparameters(leap,dut);
487
488 TString utc="N";
489 if (flag==1) utc="M";
490 if (flag==-1) utc="A";
491 if (flag==-2) utc="U";
492 if (flag==-3) utc="U";
493
494 SetMJD(mjd,sec,ns,ps,utc,leap,dut);
495
496 // Correct for double setting of dut
497 if (utc=="A" || utc=="M") AddSec(-dut);
498
499 return *this;
500}
501
502void NcTimestamp::Date(Int_t mode,Double_t offset)
503{
526
527 Int_t mjd,mjsec,mjns;
528 GetMJD(mjd,mjsec,mjns);
529
530 TString month[12]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
531 TString day[7]={"Mon","Tue","Wed","Thu","Fri","Sat","Sun"};
532 UInt_t y,m,d,wd;
533 Int_t hh,mm,ss,ns,ps;
534 Double_t gat,gast;
535 Bool_t date=kFALSE;
536
537 // The UT date and time
538 if (abs(mode)==1 || abs(mode)==3)
539 {
540 if (mjd>=40587 && (mjd<65442 || (mjd==65442 && mjsec<8047)))
541 {
542 GetDate(kTRUE,0,&y,&m,&d);
543 wd=GetDayOfWeek(kTRUE,0);
544 printf(" %-s, %02d %-s %-d ",day[wd-1].Data(),d,month[m-1].Data(),y);
545 date=kTRUE;
546 }
547 else
548 {
549 cout << " Time ";
550 date=kFALSE;
551 }
552 GetUT(hh,mm,ss,ns,ps);
553 printf("%02d:%02d:%02d.%09d%03d",hh,mm,ss,ns,ps);
554 if (!fUtc)
555 {
556 cout << " (UTC) ";
557 }
558 else
559 {
560 cout << " (UT1) ";
561 }
562
563 // The GMST time information
564 GetGMST(hh,mm,ss,ns,ps);
565 printf("%02d:%02d:%02d.%09d%03d (GMST)\n",hh,mm,ss,ns,ps);
566
567 // Equation of Time and Equation of Equinoxes
568 Double_t eot;
569 Double_t eox=Almanac(0,0,0,0,"Sun",0,0,0,&eot,10);
570 // Convert to fractional hours
571 eox/=3600.;
572 eot/=3600.;
573 if (date)
574 {
575 cout << " ";
576 }
577 else
578 {
579 cout << " ";
580 }
581 if (eot>=0) cout << " ";
582 PrintTime(eot,3); cout << " (LAT-LMT)";
583 cout << " ";
584 if (eox>=0) cout << " ";
585 PrintTime(eox,3); cout << " (LAST-LMST)"; cout << endl;
586
587 // Greenwich apparent time information
588 if (mode<0)
589 {
590 gat=GetLT(eot); // Obtain GAT via the Equation of Time as offset
591 gast=GetGAST();
592 if (date)
593 {
594 cout << " ";
595 }
596 else
597 {
598 cout << " ";
599 }
600 PrintTime(gat,12); cout << " (GAT) ";
601 PrintTime(gast,12); cout << " (GAST)" << endl;
602 }
603
604 // Local time information
605 if (offset)
606 {
607 // Determine the new date by including the offset
608 NcTimestamp t2(*this);
609 t2.Add(offset);
610 Int_t mjd2,mjsec2,mjns2;
611 t2.GetMJD(mjd2,mjsec2,mjns2);
612 if (mjd2>=40587 && (mjd2<65442 || (mjd2==65442 && mjsec2<8047)))
613 {
614 t2.GetDate(kTRUE,0,&y,&m,&d);
615 wd=t2.GetDayOfWeek(kTRUE,0);
616 printf(" %-s, %02d %-s %-d ",day[wd-1].Data(),d,month[m-1].Data(),y);
617 date=kTRUE;
618 }
619 else
620 {
621 cout << " Time ";
622 date=kFALSE;
623 }
624 // Determine the local time by including the offset w.r.t. the original timestamp
625 Double_t hlt=0;
626 Double_t hlst=0;
627 if (mode>0)
628 {
629 hlt=GetLT(offset);
630 hlst=GetLMST(offset);
631 PrintTime(hlt,12); cout << " (LMT) ";
632 PrintTime(hlst,12); cout << " (LMST)" << endl;
633 }
634 else
635 {
636 hlt=GetLT(offset+eot); // Obtain LAT via the Equation of Time as extra offset
637 hlst=GetLAST(offset);
638 PrintTime(hlt,12); cout << " (LAT) ";
639 PrintTime(hlst,12); cout << " (LAST)" << endl;
640 }
641 }
642 }
643
644 // Julian parameter information
645 if (abs(mode)==2 || abs(mode)==3)
646 {
647 Int_t jd,jsec,jns;
648 GetJD(jd,jsec,jns);
649 Int_t tjd,tjsec,tjns;
650 GetTJD(tjd,tjsec,tjns);
651 printf(" Julian Epoch : %-.20f Besselian Epoch : %-.20f\n",GetJE(),GetBE());
652 printf(" JD : %7d sec : %5d ns : %9d ps : %3d Fractional : %25.17f\n",jd,jsec,jns,fJps,GetJD());
653 printf(" MJD : %7d sec : %5d ns : %9d ps : %3d Fractional : %25.17f\n",mjd,mjsec,mjns,fJps,GetMJD());
654 printf(" TJD : %7d sec : %5d ns : %9d ps : %3d Fractional : %25.17f\n",tjd,tjsec,tjns,fJps,GetTJD());
655 if (fUtc && fUtc!=-3)
656 {
657 printf(" TAI : %7d sec : %5d ns : %9d ps : %3d Fractional : %25.17f\n",fTmjd,fTsec,fTns,fTps,GetTAI());
658 }
659 }
660
661 // TAI related information
662 if (mode==4 && fUtc && fUtc!=-3)
663 {
664 printf( " Cumulated (TAI-UTC) leap seconds: %-3d UT1-UTC : %-.6f sec.",fLeap,fDut);
665 if (fUtc<0) cout << " (IERS database)" << endl;
666 if (fUtc>0) cout << " (Manual setting)" << endl;
667
668 // A dummy timestamp is used to obtain the TAI corresponding date indicator
669 NcTimestamp tx;
671
672 if (fTmjd>=40587 && (fTmjd<65442 || (fTmjd==65442 && fTsec<8047)))
673 {
674 tx.GetDate(kTRUE,0,&y,&m,&d);
675 wd=tx.GetDayOfWeek(kTRUE,0);
676 printf(" %-s, %02d %-s %-d ",day[wd-1].Data(),d,month[m-1].Data(),y);
677 date=kTRUE;
678 }
679 else
680 {
681 cout << " Time ";
682 date=kFALSE;
683 }
684
685 // Determine the TAI derived times
686 GetTAI(hh,mm,ss,ns,ps,"TAI");
687 printf("%02d:%02d:%02d.%09d%03d (TAI) ",hh,mm,ss,ns,ps);
688
689 GetTAI(hh,mm,ss,ns,ps,"UTC");
690 printf("%02d:%02d:%02d.%09d%03d (UTC)\n",hh,mm,ss,ns,ps);
691
692 GetTAI(hh,mm,ss,ns,ps,"GPS");
693 if (!date)
694 {
695 cout << " ";
696 }
697 else
698 {
699 cout << " ";
700 }
701 printf("%02d:%02d:%02d.%09d%03d (GPS) ",hh,mm,ss,ns,ps);
702
703 GetTAI(hh,mm,ss,ns,ps,"TT");
704 printf("%02d:%02d:%02d.%09d%03d (TT)\n",hh,mm,ss,ns,ps);
705 }
706}
707
708Double_t NcTimestamp::GetJD(Int_t y,Int_t m,Int_t d,Int_t hh,Int_t mm,Int_t ss,Int_t ns) const
709{
741
742 if (y<0 || m<1 || m>12 || d<1 || d>31) return -1;
743 if (hh<0 || hh>23 || mm<0 || mm>59 || ss<0 || ss>59 || ns<0 || ns>1e9) return -1;
744
745 // The UT daytime in fractional hours
746 Double_t ut=double(hh)+double(mm)/60.+(double(ss)+double(ns)*1.e-9)/3600.;
747
748 Double_t JD=0;
749
750 JD=367*y-int(7*(y+int((m+9)/12))/4)
751 -int(3*(int((y+(m-9)/7)/100)+1)/4)
752 +int(275*m/9)+d+1721028.5+ut/24.;
753
754 return JD;
755}
756
757Double_t NcTimestamp::GetMJD(Int_t y,Int_t m,Int_t d,Int_t hh,Int_t mm,Int_t ss,Int_t ns) const
758{
790
791 Double_t JD=GetJD(y,m,d,hh,mm,ss,ns);
792
793 if (JD<0) return JD;
794
795 Double_t MJD=JD-2400000.5;
796
797 return MJD;
798}
799
800Double_t NcTimestamp::GetTJD(Int_t y,Int_t m,Int_t d,Int_t hh,Int_t mm,Int_t ss,Int_t ns) const
801{
833
834 Double_t JD=GetJD(y,m,d,hh,mm,ss,ns);
835
836 if (JD<0) return JD;
837
838 Double_t TJD=JD-2440000.5;
839
840 return TJD;
841}
842
843Double_t NcTimestamp::GetJE(Double_t date,TString mode) const
844{
870
871 if ((mode != "jd") && (mode != "mjd") && (mode != "tjd")) return -99999;
872
873 Double_t jd=date;
874 if (mode=="mjd") jd=date+2400000.5;
875 if (mode=="tjd") jd=date+2440000.5;
876
877 Double_t je=2000.+(jd-2451545.)/365.25;
878
879 return je;
880}
881
882Double_t NcTimestamp::GetBE(Double_t date,TString mode) const
883{
909
910 if ((mode != "jd") && (mode != "mjd") && (mode != "tjd")) return -99999;
911
912 Double_t jd=date;
913 if (mode=="mjd") jd=date+2400000.5;
914 if (mode=="tjd") jd=date+2440000.5;
915
916 Double_t be=1900.+(jd-2415020.31352)/365.242198781;
917
918 return be;
919}
920
921void NcTimestamp::Convert(Double_t date,Int_t& days,Int_t& secs,Int_t& ns) const
922{
946
947 days=int(date);
948 date=date-double(days);
949 Int_t daysecs=24*3600;
950 date=date*double(daysecs);
951 secs=int(date);
952 date=date-double(secs);
953 ns=int(date*1.e9);
954}
955
956Double_t NcTimestamp::Convert(Int_t days,Int_t secs,Int_t ns) const
957{
980
981 Double_t frac=double(secs)+double(ns)*1.e-9;
982 Int_t daysecs=24*3600;
983 frac=frac/double(daysecs);
984 Double_t date=double(days)+frac;
985 return date;
986}
987
988void NcTimestamp::Convert(Double_t h,Int_t& hh,Int_t& mm,Int_t& ss,Int_t& ns,Int_t& ps) const
989{
1009
1010 // Neglect sign of h
1011 h=fabs(h);
1012
1013 hh=int(h);
1014 h=h-double(hh);
1015 h=h*60.;
1016 mm=int(h);
1017 h=h-double(mm);
1018 h=h*60.;
1019 ss=int(h);
1020 h=h-double(ss);
1021 h=h*1.e9;
1022 ns=int(h);
1023 h=h-double(ns);
1024 h=h*1000.;
1025 ps=int(h);
1026}
1027
1028void NcTimestamp::Convert(Double_t h,Int_t& hh,Int_t& mm,Double_t& ss) const
1029{
1048
1049 // Neglect sign of h
1050 h=fabs(h);
1051
1052 hh=int(h);
1053 h=h-double(hh);
1054 h=h*60.;
1055 mm=int(h);
1056 h=h-double(mm);
1057 ss=h*60.;
1058}
1059
1060Double_t NcTimestamp::Convert(Int_t hh,Int_t mm,Int_t ss,Int_t ns,Int_t ps) const
1061{
1081
1082 // Neglect the sign of the input values
1083 hh=abs(hh);
1084 mm=abs(mm);
1085 ss=abs(ss);
1086 ns=abs(ns);
1087 ps=abs(ps);
1088
1089 Double_t h=hh;
1090 h+=double(mm)/60.+(double(ss)+double(ns)*1.e-9+double(ps)*1.e-12)/3600.;
1091
1092 return h;
1093}
1094
1095Double_t NcTimestamp::Convert(Int_t hh,Int_t mm,Double_t ss) const
1096{
1115
1116 // Neglect the sign of the input values
1117 hh=abs(hh);
1118 mm=abs(mm);
1119 ss=fabs(ss);
1120
1121 Double_t h=hh;
1122 h+=double(mm)/60.+ss/3600.;
1123
1124 return h;
1125}
1126
1127void NcTimestamp::PrintTime(Double_t h,Int_t ndig) const
1128{
1145
1146 Int_t hh,mm,ss;
1147 ULong64_t sfrac;
1148 Double_t s;
1149
1150 while (h<-24)
1151 {
1152 h+=24.;
1153 }
1154 while (h>24)
1155 {
1156 h-=24.;
1157 }
1158
1159 Convert(h,hh,mm,s);
1160 ss=Int_t(s);
1161 s-=Double_t(ss);
1162 s*=pow(10.,ndig);
1163 sfrac=ULong64_t(s);
1164
1165 if (h<0) printf("%-s","-");
1166 printf("%02d:%02d:%02d.%0*llu",hh,mm,ss,ndig,sfrac);
1167}
1168
1170{
1177
1178 UInt_t y,m,d,hh,mm,ss;
1179
1180 GetDate(kTRUE,0,&y,&m,&d);
1181 GetTime(kTRUE,0,&hh,&mm,&ss);
1182 Int_t ns=GetNanoSec();
1183
1184 Double_t mjd=GetMJD(y,m,d,hh,mm,ss,ns);
1185
1186 fMJD=int(mjd);
1187 fJsec=GetSec()%(24*3600); // Daytime in elapsed seconds
1188 fJns=ns; // Remaining fractional elapsed second in nanoseconds
1189
1190 // Store the TTimeStamp seconds and nanoseconds values
1191 // for which this Julian calculation was performed.
1192 fCalcs=GetSec();
1193 fCalcns=GetNanoSec();
1194}
1195
1196void NcTimestamp::GetMJD(Int_t& mjd,Int_t& sec,Int_t& ns)
1197{
1209
1210 if (fCalcs != GetSec() || fCalcns != GetNanoSec())
1211 {
1212 FillJulian();
1213 SetUTCparameters("A",0,0);
1214 }
1215
1216 mjd=fMJD;
1217 sec=fJsec;
1218 ns=fJns;
1219}
1220
1222{
1232
1233 Int_t mjd=0;
1234 Int_t sec=0;
1235 Int_t ns=0;
1236 GetMJD(mjd,sec,ns);
1237
1238 Double_t date=Convert(mjd,sec,ns);
1239
1240 return date;
1241}
1242
1243void NcTimestamp::GetTJD(Int_t& tjd,Int_t& sec,Int_t& ns)
1244{
1256
1257 Int_t mjd=0;
1258 GetMJD(mjd,sec,ns);
1259
1260 tjd=mjd-40000;
1261}
1262
1264{
1274
1275 Int_t tjd=0;
1276 Int_t sec=0;
1277 Int_t ns=0;
1278 GetTJD(tjd,sec,ns);
1279
1280 Double_t date=Convert(tjd,sec,ns);
1281
1282 return date;
1283}
1284
1285Int_t NcTimestamp::GetTAI(Int_t& d,Int_t& sec,Int_t& ns,Int_t& ps,Bool_t tmjd)
1286{
1312
1313 // Make sure to have the updated parameters
1314 GetMJD(d,sec,ns);
1315 FillTAI();
1316
1317 d=0;
1318 sec=0;
1319 ns=0;
1320 ps=0;
1321
1322 if (!fUtc) return 0;
1323
1324 d=fTmjd;
1325 sec=fTsec;
1326 ns=fTns;
1327 ps=fTps;
1328
1329 if (!tmjd) d-=36204;
1330
1331 return fUtc;
1332}
1333
1334Double_t NcTimestamp::GetTAI(Bool_t tmjd)
1335{
1357
1358 if (!fUtc) return 0;
1359
1360 Int_t d=0;
1361 Int_t s=0;
1362 Int_t ns=0;
1363 Int_t ps=0;
1364 GetTAI(d,s,ns,ps,tmjd);
1365
1366 Double_t days=Convert(d,s,ns);
1367
1368 return days;
1369}
1370
1371Int_t NcTimestamp::GetTAI(Int_t& hh,Int_t& mm,Int_t& ss,Int_t& ns,Int_t& ps,TString type)
1372{
1396
1397 hh=0;
1398 mm=0;
1399 ss=0;
1400 ns=0;
1401 ps=0;
1402
1403 if (type!="TAI" && type!="UTC" && type!="GPS" && type!="TT") return 0;
1404
1405 Int_t d,sec,nsec,psec;
1406
1407 // Use a dummy timestamp to easily correct for the various offsets
1408 NcTimestamp tx=(*this);
1409 if (type=="UTC") tx.Add(0,-fLeap,0,0);
1410 if (type=="GPS") tx.Add(0,-19,0,0);
1411 if (type=="TT") tx.Add(0,32,184000000,0);
1412
1413 // Use the UTC parameters of the actual (unmodified) timestamp
1414 tx.fLeap=fLeap;
1415 tx.fDut=fDut;
1416
1417 tx.GetTAI(d,sec,nsec,psec);
1418
1419 hh=sec/3600;
1420 sec=sec%3600;
1421 mm=sec/60;
1422 ss=sec%60;
1423 ns=nsec;
1424 ps=psec;
1425
1426 return fUtc;
1427}
1428
1430{
1461
1462 Double_t t=0;
1463
1464 Int_t days=0;
1465 Int_t secs=0;
1466 Int_t ns=0;
1467 Int_t mjd=0;
1468 GetMJD(mjd,secs,ns);
1469 Int_t ps=GetPs();
1470
1471 // Get UTC from the stored UT1 via UTC=UT1-dUT
1472 if (fUtc)
1473 {
1474 NcTimestamp tx;
1475 tx.SetMJD(mjd,secs,ns,ps);
1476 tx.AddSec(-fDut);
1477 tx.GetMJD(mjd,secs,ns);
1478 ps=tx.GetPs();
1479 }
1480
1481 days=mjd-40587;
1482
1483 t=(days*86400)+secs;
1484 t+=double(ns)*1.e-9+double(ps)*1.e-12;
1485
1486 return t;
1487}
1488
1489void NcTimestamp::GetJD(Int_t& jd,Int_t& sec,Int_t& ns)
1490{
1502
1503 Int_t mjd=0;
1504 GetMJD(mjd,sec,ns);
1505
1506 jd=mjd+2400000;
1507 sec+=12*3600;
1508 if (sec >= 24*3600)
1509 {
1510 sec-=24*3600;
1511 jd+=1;
1512 }
1513}
1514
1516{
1526
1527 Int_t jd=0;
1528 Int_t sec=0;
1529 Int_t ns=0;
1530 GetJD(jd,sec,ns);
1531
1532 Double_t date=Convert(jd,sec,ns);
1533
1534 return date;
1535}
1536
1538{
1545
1546 Double_t jd=GetJD();
1547 Double_t je=GetJE(jd);
1548 return je;
1549}
1550
1552{
1559
1560 Double_t jd=GetJD();
1561 Double_t be=GetBE(jd);
1562 return be;
1563}
1564
1565void NcTimestamp::SetMJD(Int_t mjd,Int_t sec,Int_t ns,Int_t ps,TString utc,Int_t leap,Double_t dut)
1566{
1645
1646 if (sec<0 || sec>=24*3600 || ns<0 || ns>=1e9 || ps<0 || ps>=1000)
1647 {
1648 cout << " *NcTimestamp::SetMJD* Invalid input."
1649 << " sec : " << sec << " ns : " << ns << " ps : " << ps << endl;
1650 return;
1651 }
1652
1653 fMJD=mjd;
1654 fJsec=sec;
1655 fJns=ns;
1656 fJps=ps;
1657
1658 Int_t epoch=40587; // MJD of the start of the epoch
1659 Int_t limit=65442; // MJD of the latest possible TTimeStamp date/time
1660
1661 Int_t date,time;
1662 if (mjd<epoch || mjd>limit || (mjd==limit && sec>=8047))
1663 {
1664 Set(0,kFALSE,0,kFALSE);
1665 date=GetDate();
1666 time=GetTime();
1667 Set(date,time,0,kTRUE,0);
1668 }
1669 else
1670 {
1671 // The elapsed time since start of EPOCH
1672 Int_t days=mjd-epoch;
1673 UInt_t secs=days*24*3600;
1674 secs+=sec;
1675 Set(secs,kFALSE,0,kFALSE);
1676 date=GetDate();
1677 time=GetTime();
1678 Set(date,time,ns,kTRUE,0);
1679 }
1680
1681 // Denote that the Julian and TTimeStamp parameters are synchronised,
1682 // even in the case the MJD falls outside the TTimeStamp validity range.
1683 // The latter still allows retrieval of Julian parameters for these
1684 // earlier times.
1685 fCalcs=GetSec();
1686 fCalcns=GetNanoSec();
1687
1688 // Update the UTC parameters and corresonding TAI time recording
1689 SetUTCparameters(utc,leap,dut);
1690
1691 if (utc=="A" || utc=="M") AddSec(fDut);
1692}
1693
1694void NcTimestamp::SetMJD(Double_t mjd,TString utc,Int_t leap,Double_t dut)
1695{
1774
1775 Int_t days=0;
1776 Int_t secs=0;
1777 Int_t ns=0;
1778 Convert(mjd,days,secs,ns);
1779 SetMJD(days,secs,ns,0,utc,leap,dut);
1780}
1781
1782void NcTimestamp::SetJD(Int_t jd,Int_t sec,Int_t ns,Int_t ps,TString utc,Int_t leap,Double_t dut)
1783{
1862
1863 Int_t mjd=jd-2400000;
1864 sec-=12*3600;
1865 if (sec<0)
1866 {
1867 sec+=24*3600;
1868 mjd-=1;
1869 }
1870
1871 SetMJD(mjd,sec,ns,ps,utc,leap,dut);
1872}
1873
1874void NcTimestamp::SetJD(Double_t jd,TString utc,Int_t leap,Double_t dut)
1875{
1954
1955 Int_t days=0;
1956 Int_t secs=0;
1957 Int_t ns=0;
1958 Convert(jd,days,secs,ns);
1959
1960 SetJD(days,secs,ns,0,utc,leap,dut);
1961}
1962
1963void NcTimestamp::SetTJD(Int_t tjd,Int_t sec,Int_t ns,Int_t ps,TString utc,Int_t leap,Double_t dut)
1964{
2043
2044 Int_t mjd=tjd+40000;
2045
2046 SetMJD(mjd,sec,ns,ps,utc,leap,dut);
2047}
2048
2049void NcTimestamp::SetTJD(Double_t tjd,TString utc,Int_t leap,Double_t dut)
2050{
2129
2130 Int_t days=0;
2131 Int_t secs=0;
2132 Int_t ns=0;
2133 Convert(tjd,days,secs,ns);
2134
2135 SetTJD(days,secs,ns,0,utc,leap,dut);
2136}
2137
2139{
2147
2148 if (!fUtc || fUtc==-3)
2149 {
2150 fTmjd=0;
2151 fTsec=0;
2152 fTns=0;
2153 fTps=0;
2154 return;
2155 }
2156
2157 // Use memberfunction to ensure most recent values for the stored UT1
2159 fTps=GetPs();
2160
2161 // Dummy timestamp to easily obtain TAI based day etc. counts
2162 // It is essential not to use UTC parameters here in order to prevent an infinite loop
2163 NcTimestamp tx;
2164 tx.SetMJD(fTmjd,fTsec,fTns,fTps,"N"); // This stores UT1 as if it were UTC
2165
2166 tx.AddSecCalc(-fDut,kFALSE); // Convert the stored UT1 into UTC via UTC=UT1-dUT
2167 tx.AddCalc(0,fLeap,0,0,kFALSE); // Account for the leap seconds
2168
2169 // Retrieve the corresponding TAI day etc. count
2170 tx.GetMJD(fTmjd,fTsec,fTns);
2171 fTps=tx.GetPs();
2172}
2173
2174Int_t NcTimestamp::SetTAI(TString type,TString date,TString time,Int_t mode,TString utc,Int_t leap,Double_t dut)
2175{
2231
2232 Int_t ibad=0;
2233
2234 if (type!="UTC" && type!="GPS" && type!="TAI" && type!="TT") ibad=1;
2235
2236 if (utc!="M" && utc!="A") ibad=1;
2237
2238 if (utc=="M" && fabs(dut)>0.9) ibad=1;
2239
2240 if (utc=="A" && !fUTCdata) ibad=1;
2241
2242 // In case utc="A" check whether the corresponding IERS database info is available
2243 if (utc=="A")
2244 {
2245 NcTimestamp tx; // Dummy timestamp for easy MJD retrieval
2246 tx.SetUT(date,time,mode,utc);
2247 Int_t ien=GetUTCparameters(tx.fMJD,leap,dut);
2248 if (ien<0) ibad=1;
2249 }
2250
2251 if (ibad)
2252 {
2253 SetJD(0,"N");
2254 return fUtc;
2255 }
2256
2257 SetUT(date,time,mode,utc,leap,dut);
2258 if (type != "UTC") Add(0,-fLeap,0,0); // Account for the leap seconds
2259 if (type == "GPS") Add(0,19,0,0); // Account for TAI-GPS=19 sec.
2260 if (type == "TT") Add(0,-32,-184000000,0); // Account for TAI-TT=-32.184 sec.
2261
2262 return fUtc;
2263}
2264
2265Int_t NcTimestamp::SetTAI(Int_t d,Int_t sec,Int_t ns,Int_t ps,TString utc,Int_t leap,Double_t dut,Bool_t tmjd)
2266{
2333
2334 Int_t ibad=0;
2335
2336 if (sec<0 || sec>86400 || ns<0 || ns>999999999 || ps<0 || ps>999) ibad=1;
2337
2338 if (utc!="M" && utc!="A") ibad=1;
2339
2340 if (utc=="M" && fabs(dut)>0.9) ibad=1;
2341
2342 if (utc=="A" && !fUTCdata) ibad=1;
2343
2344 // Set the corresponding MJD
2345 Int_t mjd=d;
2346 if (!tmjd) mjd+=36204;
2347
2348 // In case utc="A" check whether the corresponding IERS database info is available
2349 if (utc=="A")
2350 {
2351 Int_t ien=GetUTCparameters(mjd,leap,dut);
2352 if (ien<0) ibad=1;
2353 }
2354
2355 if (ibad)
2356 {
2357 SetJD(0,"N");
2358 return fUtc;
2359 }
2360
2361 SetMJD(mjd,sec,ns,ps);
2362 SetUTCparameters(utc,leap,dut); // Update the UTC parameters and corresonding TAI time recording
2363 Add(0,-fLeap,0,0); // Account for the leap seconds
2364 AddSec(fDut); // Account for dUT=UT1-UTC
2365
2366 // Set the corresponding TAI day count etc.
2367 FillTAI();
2368
2369 return fUtc;
2370}
2371
2372Int_t NcTimestamp::SetTAI(Double_t tai,TString utc,Int_t leap,Double_t dut,Bool_t tmjd)
2373{
2440
2441 Int_t days=0;
2442 Int_t secs=0;
2443 Int_t ns=0;
2444 Convert(tai,days,secs,ns);
2445
2446 SetTAI(days,secs,ns,0,utc,leap,dut,tmjd);
2447
2448 return fUtc;
2449}
2450
2451Int_t NcTimestamp::SetGPS(Int_t w,Int_t sow,Int_t ns,Int_t ps,TString utc,Int_t leap,Double_t dut,Int_t icycle)
2452{
2508
2509 if (w<0 || sow<0 || sow>604800 || ns<0 || ns>999999999 || ps<0 || ps>999 || icycle<0)
2510 {
2511 SetJD(0,"N");
2512 return fUtc;
2513 }
2514
2515 // Correct the week count for the cycle number if needed
2516 if (icycle) w+=icycle*1024;
2517
2518 Int_t days=8040+w*7;
2519 sow+=19;
2520 Int_t daysecs=24*3600;
2521 Int_t days2=sow/daysecs;
2522 days+=days2;
2523 Int_t secs=sow%daysecs;
2524
2525 SetTAI(days,secs,ns,ps,utc,leap,dut);
2526
2527 return fUtc;
2528}
2529
2530Int_t NcTimestamp::SetGPS(Int_t w,Int_t dow,Int_t sod,Int_t ns,Int_t ps,TString utc,Int_t leap,Double_t dut,Int_t icycle)
2531{
2588
2589 if (w<0 || dow<0 || dow>7 || sod<0 || sod>86400 || ns<0 || ns>999999999 || ps<0 || ps>999 || icycle<0)
2590 {
2591 SetJD(0,"N");
2592 return fUtc;
2593 }
2594
2595 // Correct the week count for the cycle number if needed
2596 if (icycle) w+=icycle*1024;
2597
2598 Int_t days=8040+w*7+dow;
2599 sod+=19;
2600
2601 SetTAI(days,sod,ns,ps,utc,leap,dut);
2602
2603 return fUtc;
2604}
2605
2606Int_t NcTimestamp::SetUnixTime(Double_t sec,TString utc,Int_t leap,Double_t dut)
2607{
2688
2689 // Determine the fractional day count since the start of the Unix Epoch
2690 Double_t tday=sec/86400.;
2691
2692 Int_t days=0;
2693 Int_t s=0;
2694 Int_t ns=0;
2695 Convert(tday,days,s,ns);
2696
2697 // Determine the remaining elapsed picoseconds
2698 Int_t iword=int(sec);
2699 sec=sec-double(iword);
2700 sec*=1e9;
2701 iword=int(sec);
2702 sec=sec-double(iword);
2703 Int_t ps=int(sec*1000.);
2704
2705 // Unix time is related to UTC and not to UT1.
2706 if (utc=="U") utc="A";
2707
2708 SetMJD(40587,0,0,0); // Start of the Unix Epoch
2709 SetUTCparameters(utc,leap,dut); // Update the UTC parameters and corresonding TAI time recording
2710 Add(days,s,ns,ps); // Add the elapsed time
2711 if (fUtc) AddSec(fDut); // Correct for dUT=UT1-UTC
2712
2713 return fUtc;
2714}
2715
2717{
2729
2730 if (ns>=0 && ns<=999999999) fJns=ns;
2731}
2732
2734{
2743
2744 return fJns;
2745}
2746
2748{
2759
2760 if (ps>=0 && ps<=999) fJps=ps;
2761}
2762
2764{
2772
2773 return fJps;
2774}
2775
2776Int_t NcTimestamp::GetUTCparameters(Int_t& leap,Double_t& dut) const
2777{
2799
2800 leap=fLeap;
2801 dut=fDut;
2802
2803 return fUtc;
2804}
2805
2806Int_t NcTimestamp::GetUTCparameters(Int_t mjd,Int_t& leap,Double_t& dut) const
2807{
2818
2819 leap=0;
2820 dut=0;
2821
2822 if (!fUTCdata) return -1;
2823
2824 Int_t nen=fUTCdata->GetEntries();
2825
2826 if (!nen) return -1;
2827
2828 Int_t dbmjd=0;
2829 Int_t dbleap=0;
2830 Double_t dbdut=0;
2831
2832 fUTCdata->SetBranchAddress("mjd",&dbmjd);
2833 fUTCdata->SetBranchAddress("lsec",&dbleap);
2834 fUTCdata->SetBranchAddress("dut",&dbdut);
2835
2836 // Data of the first entry
2837 fUTCdata->GetEntry(0);
2838 Int_t ien=mjd-dbmjd;
2839
2840 if (ien<0 || ien>=nen) return -1; // Specified mjd not in range of database
2841
2842 fUTCdata->GetEntry(ien);
2843 if (dbmjd==mjd) // Specified mjd is found in database
2844 {
2845 leap=dbleap;
2846 dut=dbdut;
2847 }
2848 else
2849 {
2850 ien=-1;
2851 leap=0;
2852 dut=0;
2853 }
2854
2855 return ien;
2856}
2857
2858Int_t NcTimestamp::SetUTCparameters(TString utc,Int_t leap,Double_t dut)
2859{
2920
2921 fUtc=0;
2922 if (utc=="U") fUtc=-3;
2923 fLeap=0;
2924 fDut=0;
2925
2926 Int_t ibad=0;
2927
2928 if (utc!="N" && utc!="M" && utc!="A" && utc!="U") ibad=1;
2929
2930 if (utc=="N" || ((utc=="A" || utc=="U") && !fUTCdata)) ibad=1;
2931
2932 if (utc=="M" && fabs(dut)>0.9) ibad=1;
2933
2934 if (ibad)
2935 {
2936 FillTAI();
2937 return fUtc;
2938 }
2939
2940 // From here only utc="M", utc="A" or utc="U"
2941
2942 if (utc=="M")
2943 {
2944 fUtc=1;
2945 fLeap=leap;
2946 fDut=dut;
2947
2948 FillTAI();
2949 return fUtc;
2950 }
2951
2952 // Automatic setting of the UTC parameters from the loaded data files
2953 Int_t nen=fUTCdata->GetEntries();
2954
2955 if (nen<=0) // No entries in the IERS data TTree
2956 {
2957 FillTAI();
2958 return fUtc;
2959 }
2960
2961 Int_t mjd=0;
2962
2963 fUTCdata->SetBranchAddress("mjd",&mjd);
2964 fUTCdata->SetBranchAddress("lsec",&leap);
2965 fUTCdata->SetBranchAddress("dut",&dut);
2966
2967 // Get the starting mjd of the IERS daily data
2968 // and determine the entry for the current MJD info
2969 fUTCdata->GetEntry(0);
2970 Int_t ien=fMJD-mjd;
2971 if (ien>=0 && ien<nen)
2972 {
2973 fUTCdata->GetEntry(ien);
2974 if (mjd==fMJD)
2975 {
2976 fUtc=-1;
2977 if (utc=="U") fUtc=-2;
2978 fLeap=leap;
2979 fDut=dut;
2980 }
2981 }
2982
2983 FillTAI();
2984
2985 return fUtc;
2986}
2987
2988TTree* NcTimestamp::LoadUTCparameterFiles(TString leapfile,TString dutfile)
2989{
3038
3039 // Expand the input file pathnames
3040 leapfile=gSystem->ExpandPathName(leapfile.Data());
3041 dutfile=gSystem->ExpandPathName(dutfile.Data());
3042
3043 if (fUTCdata)
3044 {
3045 delete fUTCdata;
3046 fUTCdata=0;
3047 }
3048
3049 // The Leap Second input data file
3050 ifstream fleap;
3051 fleap.clear();
3052 fleap.open(leapfile.Data());
3053 if (!fleap.good())
3054 {
3055 cout << " *NcTimestamp::LoadUTCparameterFiles* Data file for Leap Seconds not found ***" << endl;
3056 cout << " File name provided was : " << leapfile.Data() << endl;
3057 return 0;
3058 }
3059
3060 // The dUT=UT1-UTC input data file
3061 ifstream fdut;
3062 fdut.clear();
3063 fdut.open(dutfile.Data());
3064 if (!fdut.good())
3065 {
3066 cout << " *NcTimestamp::LoadUTCparameterFiles* Data file for dUT=UT-UTC not found ***" << endl;
3067 cout << " File name provided was : " << dutfile.Data() << endl;
3068 return 0;
3069 }
3070
3071 // Determine the number of characters in the Leap Second input file
3072 // to reserve sufficient array storage of all Leap Second entries
3073 fleap.seekg(0,fleap.end); // Position at end of file
3074 Int_t ndim=fleap.tellg();
3075
3076 // The storage arrays for the Leap second data
3077 Int_t* lmjd=new Int_t[ndim];
3078 Int_t* leap=new Int_t[ndim];
3079
3081 // Read the Leap Second data //
3083
3084 fleap.seekg(0); // Position at begin of file
3085
3086 // Read title lines until the first data line is found
3087 string line;
3088 Int_t i=0;
3089 while (getline(fleap,line))
3090 {
3091 if (line.find("1972")!=line.npos) break;
3092 i++;
3093 }
3094
3095 // Go to the beginning of the file and skip the title lines preceding the data lines
3096 fleap.seekg(0);
3097 for (Int_t j=0; j<i; j++)
3098 {
3099 getline(fleap,line);
3100 }
3101
3102 // Read the data
3103 Float_t rmjd=0;
3104 Int_t lsec=0;
3105 Float_t x; // Dummy variable for skipping non-requested data columns
3106 i=0;
3107 while (fleap >> rmjd >> x >> x >> x >> lsec)
3108 {
3109 lmjd[i]=int(rmjd);
3110 leap[i]=lsec;
3111 i++;
3112 }
3113
3114 // The number of actual Leap Second entries
3115 Int_t nleap=i;
3116
3118 // Read the dUT=UT1-UTC //
3120
3121 fdut.seekg(0); // Position at begin of file
3122
3123 // Read title lines until the first data line is found
3124 i=0;
3125 while (getline(fdut,line))
3126 {
3127 if (line.find("1962")!=line.npos) break;
3128 i++;
3129 }
3130
3131 // Go to the beginning of the file and skip the title lines preceding the data lines
3132 fdut.seekg(0);
3133 for (Int_t j=0; j<i; j++)
3134 {
3135 getline(fdut,line);
3136 }
3137
3138 // Read the dUT daily data and fill the TTree structure
3139 Int_t mjd=0;
3140 Double_t dut=0;
3141
3142 // The produced output structure
3143 fUTCdata=new TTree("UTCdata","Daily UTC leap second and dUT=UT-UTC parameter data");
3144
3145 // Prevent this Tree to be automatically coupled to a user defined output file
3146 fUTCdata->SetDirectory(0);
3147
3148 // The output variables for the Tree
3149 fUTCdata->Branch("mjd",&mjd,"mjd/I");
3150 fUTCdata->Branch("lsec",&lsec,"lsec/I");
3151 fUTCdata->Branch("dut",&dut,"dut/D");
3152
3153 while (fdut >> x >> x >> x >> mjd >> x >> x >> dut >> x >> x >> x >> x >> x >> x >> x >> x >> x)
3154 {
3155 lsec=0;
3156 // Retrieve the corresponding Leap Second info
3157 for (Int_t j=nleap-1; j>=0; j--)
3158 {
3159 if (mjd>=lmjd[j])
3160 {
3161 lsec=leap[j];
3162 break;
3163 }
3164 }
3165 fUTCdata->Fill();
3166 }
3167
3168 delete[] lmjd;
3169 delete[] leap;
3170
3171 // Retrieve the UTC parameters for the current timestamp
3172 if (!fUtc) // Reference time is UTC
3173 {
3174 SetUTCparameters("A",0,0);
3175 AddSec(fDut);
3176 }
3177 else // Reference time is UT1
3178 {
3179 SetUTCparameters("U",0,0);
3180 }
3181
3182 return fUTCdata;
3183}
3184
3186{
3194
3195 return fUTCdata;
3196}
3197
3198void NcTimestamp::Add(Int_t d,Int_t s,Int_t ns,Int_t ps)
3199{
3225
3226 AddCalc(d,s,ns,ps);
3227}
3228
3229void NcTimestamp::Add(Double_t hours)
3230{
3243
3244 AddCalc(hours);
3245}
3246
3247void NcTimestamp::AddSec(Double_t seconds)
3248{
3261
3262 AddSecCalc(seconds);
3263}
3264
3265void NcTimestamp::AddCalc(Int_t d,Int_t s,Int_t ns,Int_t ps,Bool_t utcpar)
3266{
3296
3297 Int_t days=0;
3298 Int_t secs=0;
3299 Int_t nsec=0;
3300 // Use Get functions to ensure updated Julian parameters.
3301 GetMJD(days,secs,nsec);
3302 Int_t psec=GetPs();
3303
3304 psec+=ps%1000;
3305 nsec+=ps/1000;
3306 while (psec<0)
3307 {
3308 nsec-=1;
3309 psec+=1000;
3310 }
3311 while (psec>999)
3312 {
3313 nsec+=1;
3314 psec-=1000;
3315 }
3316
3317 nsec+=ns%1000000000;
3318 secs+=ns/1000000000;
3319 while (nsec<0)
3320 {
3321 secs-=1;
3322 nsec+=1000000000;
3323 }
3324 while (nsec>999999999)
3325 {
3326 secs+=1;
3327 nsec-=1000000000;
3328 }
3329
3330 secs+=s%(24*3600);
3331 days+=s/(24*3600);
3332 while (secs<0)
3333 {
3334 days-=1;
3335 secs+=24*3600;
3336 }
3337 while (secs>=24*3600)
3338 {
3339 days+=1;
3340 secs-=24*3600;
3341 }
3342
3343 days+=d;
3344
3345 TString utc="N";
3346 if (fUtc==1) utc="M";
3347 if (fUtc==-1) utc="A";
3348 if (fUtc==-2) utc="U";
3349 if (fUtc==-3) utc="U";
3350 Int_t leap=fLeap;
3351 Double_t dut=fDut;
3352 SetMJD(days,secs,nsec,psec);
3353
3354 if (utcpar) SetUTCparameters(utc,leap,dut);
3355}
3356
3357void NcTimestamp::AddCalc(Double_t hours,Bool_t utcpar)
3358{
3377
3378 Int_t d,s,ns,ps;
3379 Double_t h=fabs(hours);
3380 d=int(h/24.);
3381 h-=double(d)*24.;
3382 h*=3600.;
3383 s=int(h);
3384 h-=double(s);
3385 h*=1.e9;
3386 ns=int(h);
3387 h-=double(ns);
3388 ps=int(h*1000.);
3389 if (hours>0) AddCalc(d,s,ns,ps,utcpar);
3390 if (hours<0) AddCalc(-d,-s,-ns,-ps,utcpar);
3391}
3392
3393void NcTimestamp::AddSecCalc(Double_t seconds,Bool_t utcpar)
3394{
3413
3414 Int_t s,ns,ps;
3415 Double_t a=fabs(seconds);
3416 s=int(a);
3417 a-=double(s);
3418 a*=1.e9;
3419 ns=int(a);
3420 a-=double(ns);
3421 ps=int(a*1000.);
3422 if (seconds>0) AddCalc(0,s,ns,ps,utcpar);
3423 if (seconds<0) AddCalc(0,-s,-ns,-ps,utcpar);
3424}
3425
3426Int_t NcTimestamp::GetDifference(NcTimestamp* t,Int_t& d,Int_t& s,Int_t& ns,Int_t& ps,TString type)
3427{
3474
3475 d=0;
3476 s=0;
3477 ns=0;
3478 ps=0;
3479
3480 if (!t || (type!="UT" && type!="TAI")) return 0;
3481
3482 Int_t tUtc=t->fUtc;
3483 if (type=="TAI" && (!fUtc || !tUtc || fUtc==-3 || tUtc==-3)) return 0;
3484
3485 Int_t d1=0;
3486 Int_t s1=0;
3487 Int_t ns1=0;
3488 Int_t ps1=0;
3489
3490 Int_t d2=0;
3491 Int_t s2=0;
3492 Int_t ns2=0;
3493 Int_t ps2=0;
3494
3495 NcTimestamp ts1(*t);
3496 NcTimestamp ts2(*this);
3497
3498 // Check for a mixed use of UT1 and UTC
3499 if (type=="UT")
3500 {
3501 Double_t dut=0;
3502 if (!fUtc && tUtc) // This timestamp is in UTC and the other in UT1
3503 {
3504 dut=t->fDut;
3505 ts1.AddSec(-dut);
3506 }
3507 if (fUtc && !tUtc) // This timestamp is in UT1 and the other in UTC
3508 {
3509 ts2.AddSec(-fDut);
3510 }
3511 }
3512
3513 // Use Get functions to ensure updated Julian and TAI parameters.
3514 if (type=="UT")
3515 {
3516 ts1.GetMJD(d1,s1,ns1);
3517 ps1=ts1.GetPs();
3518 ts2.GetMJD(d2,s2,ns2);
3519 ps2=ts2.GetPs();
3520 }
3521 if (type=="TAI")
3522 {
3523 t->GetTAI(d1,s1,ns1,ps1);
3524 GetTAI(d2,s2,ns2,ps2);
3525 }
3526
3527 d=d1-d2;
3528 s=s1-s2;
3529 ns=ns1-ns2;
3530 ps=ps1-ps2;
3531
3532 if (!d && !s && !ns && !ps) return 0;
3533
3534 Int_t sign=0;
3535
3536 if (d>0) sign=1;
3537 if (d<0) sign=-1;
3538
3539 if (!sign && s>0) sign=1;
3540 if (!sign && s<0) sign=-1;
3541
3542 if (!sign && ns>0) sign=1;
3543 if (!sign && ns<0) sign=-1;
3544
3545 if (!sign && ps>0) sign=1;
3546 if (!sign && ps<0) sign=-1;
3547
3548 // In case the input stamp was earlier, take the reverse difference
3549 // to simplify the algebra.
3550 if (sign<0)
3551 {
3552 d=-d;
3553 s=-s;
3554 ns=-ns;
3555 ps=-ps;
3556 }
3557
3558 // Here we always have a positive time difference
3559 // and can now unambiguously correct for other negative values.
3560 if (ps<0)
3561 {
3562 ns-=1;
3563 ps+=1000;
3564 }
3565
3566 if (ns<0)
3567 {
3568 s-=1;
3569 ns+=1000000000;
3570 }
3571
3572 if (s<0)
3573 {
3574 d-=1;
3575 s+=24*3600;
3576 }
3577
3578 return sign;
3579}
3580
3581Int_t NcTimestamp::GetDifference(NcTimestamp& t,Int_t& d,Int_t& s,Int_t& ns,Int_t& ps,TString type)
3582{
3629
3630 return GetDifference(&t,d,s,ns,ps,type);
3631}
3632
3633Double_t NcTimestamp::GetDifference(NcTimestamp* t,TString u,Int_t mode,TString type)
3634{
3701
3702 if (!t || mode<1 || mode>3 || (type!="UT" && type!="TAI")) return 0;
3703
3704 if (u!="d" && u!="s" && u!="ns" && u!="ps") return 0;
3705
3706
3707 Int_t tUtc=t->fUtc;
3708 if (type=="TAI" && (!fUtc || !tUtc || fUtc==-3 || tUtc==-3)) return 0;
3709
3710 Double_t dt=0;
3711
3712 Int_t d1=0;
3713 Int_t s1=0;
3714 Int_t ns1=0;
3715 Int_t ps1=0;
3716
3717 Int_t d2=0;
3718 Int_t s2=0;
3719 Int_t ns2=0;
3720 Int_t ps2=0;
3721
3722 NcTimestamp ts1(*t);
3723 NcTimestamp ts2(*this);
3724
3725 // Check for a mixed use of UT1 and UTC
3726 if (type=="UT")
3727 {
3728 Double_t dut=0;
3729 if (!fUtc && tUtc) // This timestamp is in UTC and the other in UT1
3730 {
3731 dut=t->fDut;
3732 ts1.AddSec(-dut);
3733 }
3734 if (fUtc && !tUtc) // This timestamp is in UT1 and the other in UTC
3735 {
3736 ts2.AddSec(-fDut);
3737 }
3738 }
3739
3740 // Use Get functions to ensure updated Julian and TAI parameters.
3741 if (type=="UT")
3742 {
3743 ts1.GetMJD(d1,s1,ns1);
3744 ps1=ts1.GetPs();
3745 ts2.GetMJD(d2,s2,ns2);
3746 ps2=ts2.GetPs();
3747 }
3748 if (type=="TAI")
3749 {
3750 t->GetTAI(d1,s1,ns1,ps1);
3751 GetTAI(d2,s2,ns2,ps2);
3752 }
3753
3754 Long_t dd=d1-d2;
3755 Long_t ds=s1-s2;
3756 Long_t dns=ns1-ns2;
3757 Long_t dps=ps1-ps2;
3758
3759 // Time difference for the specified units only
3760 if (mode==3)
3761 {
3762 if (u=="d") dt=dd;
3763 if (u=="s") dt=ds;
3764 if (u=="ns") dt=dns;
3765 if (u=="ps") dt=dps;
3766 return dt;
3767 }
3768
3769 // Suppress elapsed time for the larger units than specified
3770 if (mode==2)
3771 {
3772 if (u=="s") dd=0;
3773 if (u=="ns")
3774 {
3775 dd=0;
3776 ds=0;
3777 }
3778 if (u=="ps")
3779 {
3780 dd=0;
3781 ds=0;
3782 dns=0;
3783 }
3784 }
3785
3786 // Compute the time difference as requested
3787 if (u=="s" || u=="d")
3788 {
3789 // The time difference in (fractional) seconds
3790 dt=double(dd*24*3600+ds)+(double(dns)*1e-9)+(double(dps)*1e-12);
3791 if (u=="d") dt=dt/double(24*3600);
3792 }
3793 if (u=="ns") dt=(double(dd*24*3600+ds)*1e9)+double(dns)+(double(dps)*1e-3);
3794 if (u=="ps") dt=(double(dd*24*3600+ds)*1e12)+(double(dns)*1e3)+double(dps);
3795
3796 return dt;
3797}
3798
3799Double_t NcTimestamp::GetDifference(NcTimestamp& t,TString u,Int_t mode,TString type)
3800{
3867
3868 return GetDifference(&t,u,mode,type);
3869}
3870
3871void NcTimestamp::SetUT(Int_t y,Int_t m,Int_t d,Int_t hh,Int_t mm,Int_t ss,Int_t ns,Int_t ps,TString utc,Int_t leap,Double_t dut)
3872{
3949
3950 if (d<1 || d>31 || m<1 || m>12 || hh<0 || hh>23 || mm<0 || mm>59 || ss<0 || ss>59 || ns<0 || ns>999999999 || ps<0 || ps>999)
3951 {
3952 cout << " *NcTimestamp::SetUT* Incompatible argument(s) Day=" << d << " Month=" << m << " Year=" << y
3953 << " hour=" << hh << " min=" << mm << " sec=" << ss << " ns=" << ns << " ps=" << ps << endl;
3954 cout << " ==> TAI related time recording is disabled and JD=0 has been set." << endl;
3955 SetJD(0,"N");
3956 return;
3957 }
3958
3959 Int_t day=GetDayOfYear(d,m,y);
3960 Int_t secs=hh*3600+mm*60+ss;
3961 SetUT(y,day-1,secs,ns,ps,utc,leap,dut);
3962}
3963
3964void NcTimestamp::SetUT(Int_t y,Int_t m,Int_t d,Int_t hh,Int_t mm,Double_t s,TString utc,Int_t leap,Double_t dut)
3965{
4029
4030 Int_t ss=int(s);
4031 s-=double(ss);
4032 Int_t ns=s*1.e9;
4033 s-=double(ns)*1.e-9;
4034 Int_t ps=s*1.e12;
4035 SetUT(y,m,d,hh,mm,ss,ns,ps,utc,leap,dut);
4036}
4037
4038void NcTimestamp::SetUT(Int_t y,Int_t m,Int_t d,TString time,TString utc,Int_t leap,Double_t dut)
4039{
4101
4102 Long64_t iword=0;
4103 Int_t hh=0;
4104 Int_t mm=0;
4105 Int_t ss=0;
4106 Int_t ns=0;
4107 Int_t ps=0;
4108 time.ReplaceAll(":","");
4109
4110 // Unpack the hhmmss integer part
4111 iword=time.Atoll();
4112 hh=iword/10000;
4113 iword=iword%10000;
4114 mm=iword/100;
4115 iword=iword%100;
4116 ss=iword;
4117
4118 // Unpack the fractional part in ns and ps
4119 time.Remove(0,7); // Remove the integer part, including the decimal "."
4120 Int_t length=time.Length();
4121 time.Append('0',12-length); // Increase the string to represent the integer number of ns
4122 iword=time.Atoll();
4123 ns=iword/1000;
4124 ps=iword%1000;
4125 SetUT(y,m,d,hh,mm,ss,ns,ps,utc,leap,dut);
4126}
4127
4128void NcTimestamp::SetUT(TString date,TString time,Int_t mode,TString utc,Int_t leap,Double_t dut)
4129{
4195
4196 Int_t iword=0;
4197 Int_t utdate=0;
4198 Int_t year=0;
4199 Int_t month=0;
4200 Int_t day=0;
4201 TString datex=date;
4202 datex.ReplaceAll("-","");
4203 datex.ReplaceAll("/","");
4204 utdate=datex.Atoi();
4205 iword=utdate;
4206 if (mode==0)
4207 {
4208 day=iword/1000000;
4209 iword=iword%1000000;
4210 month=iword/10000;
4211 iword=iword%10000;
4212 year=iword;
4213 }
4214 if (mode==1)
4215 {
4216 year=iword/10000;
4217 iword=iword%10000;
4218 month=iword/100;
4219 iword=iword%100;
4220 day=iword;
4221 }
4222 if (mode==2)
4223 {
4224 month=iword/1000000;
4225 iword=iword%1000000;
4226 day=iword/10000;
4227 iword=iword%10000;
4228 year=iword;
4229 }
4230 if (mode==3)
4231 {
4232 year=iword/10000;
4233 iword=iword%10000;
4234 day=iword/100;
4235 iword=iword%100;
4236 month=iword;
4237 }
4238
4239 if (day<1 || day>31 || month<1 || month>12)
4240 {
4241 cout << " *NcTimestamp::SetUT* Incompatible argument(s) Date: " << date << " Time: " << time << " mode: " << mode << endl;
4242 cout << " ==> TAI related time recording is disabled and JD=0 has been set." << endl;
4243 SetJD(0,"N");
4244 }
4245 else
4246 {
4247 SetUT(year,month,day,time,utc,leap,dut);
4248 }
4249}
4250
4251void NcTimestamp::SetUT(Int_t y,Int_t d,Int_t s,Int_t ns,Int_t ps,TString utc,Int_t leap,Double_t dut)
4252{
4334
4335 Double_t jd=GetJD(y,1,1,0,0,0,0);
4336 SetJD(jd);
4337
4338 Int_t mjd,sec,nsec;
4339 GetMJD(mjd,sec,nsec);
4340 SetMJD(mjd,0,0,0);
4341 SetUTCparameters(utc,leap,dut); // Update the UTC parameters and corresonding TAI time recording
4342 Add(d,s,ns,ps);
4343
4344 // Determine UT1 using dut=UT1-UTC if UTC was provided as input
4345 if (utc!="U") AddSec(fDut);
4346}
4347
4348void NcTimestamp::GetUT(Int_t& hh,Int_t& mm,Int_t& ss,Int_t& ns,Int_t& ps)
4349{
4357
4358 Int_t mjd,sec,nsec,psec;
4359
4360 GetMJD(mjd,sec,nsec);
4361 psec=GetPs();
4362
4363 hh=sec/3600;
4364 sec=sec%3600;
4365 mm=sec/60;
4366 ss=sec%60;
4367 ns=nsec;
4368 ps=psec;
4369}
4370
4372{
4380
4381 Int_t hh,mm,ss,ns,ps;
4382
4383 GetUT(hh,mm,ss,ns,ps);
4384
4385 Double_t ut=Convert(hh,mm,ss,ns,ps);
4386
4387 return ut;
4388}
4389
4390void NcTimestamp::GetGMST(Int_t& hh,Int_t& mm,Int_t& ss,Int_t& ns,Int_t& ps)
4391{
4401
4402 Int_t mjd,sec,nsec,psec;
4403
4404 // The current UT based timestamp data
4405 GetMJD(mjd,sec,nsec);
4406 psec=fJps;
4407
4408 // The basis for the daily corrections in units of Julian centuries w.r.t. J2000.
4409 // Note : Epoch J2000 starts at 01-jan-2000 12:00:00 UT.
4410 Double_t tau=(GetJD()-2451545.)/36525.;
4411
4412 // Syncronise sidereal time with current timestamp
4413 NcTimestamp sid;
4414 sid.SetMJD(mjd,sec,nsec,psec);
4415
4416 // Add offset for GMST start value defined as 06:41:50.54841 at 01-jan 00:00:00 UT
4417 sec=6*3600+41*60+50;
4418 nsec=548410000;
4419 psec=0;
4420 sid.Add(0,sec,nsec,psec);
4421
4422 // Daily correction for precession and polar motion
4423 Double_t addsec=8640184.812866*tau+0.093104*pow(tau,2)-6.2e-6*pow(tau,3);
4424 sec=int(addsec);
4425 addsec-=double(sec);
4426 nsec=int(addsec*1.e9);
4427 addsec-=double(nsec)*1.e-9;
4428 psec=int(addsec*1.e12);
4429 sid.Add(0,sec,nsec,psec);
4430
4431 sid.GetMJD(mjd,sec,nsec);
4432 psec=sid.GetPs();
4433
4434 hh=sec/3600;
4435 sec=sec%3600;
4436 mm=sec/60;
4437 ss=sec%60;
4438 ns=nsec;
4439 ps=psec;
4440}
4441
4443{
4452
4453 Int_t hh,mm,ss,ns,ps;
4454
4455 GetGMST(hh,mm,ss,ns,ps);
4456
4457 Double_t gst=Convert(hh,mm,ss,ns,ps);
4458
4459 return gst;
4460}
4461
4463{
4483
4484 Double_t da=Almanac();
4485
4486 // Convert to fractional hours
4487 da/=3600.;
4488
4489 Double_t gast=GetGMST()+da;
4490
4491 while (gast<0)
4492 {
4493 gast+=24.;
4494 }
4495 while (gast>24.)
4496 {
4497 gast-=24.;
4498 }
4499
4500 return gast;
4501}
4502
4503Double_t NcTimestamp::GetLT(Double_t offset)
4504{
4517
4518 // Current UT time in fractional hours
4519 Double_t h=GetUT();
4520
4521 h+=offset;
4522
4523 while (h<0)
4524 {
4525 h+=24.;
4526 }
4527 while (h>24)
4528 {
4529 h-=24.;
4530 }
4531
4532 return h;
4533}
4534
4535Double_t NcTimestamp::GetLAT(Double_t offset)
4536{
4556
4557 // Current UT time in fractional hours
4558 Double_t h=GetUT();
4559
4560 // Equation of Time
4561 Double_t eot; // LAT-LMT
4562 Almanac(0,0,0,0,"Sun",0,0,0,&eot,10);
4563 eot/=3600.; // Convert to fractional hours
4564
4565 h+=offset+eot;
4566
4567 while (h<0)
4568 {
4569 h+=24.;
4570 }
4571 while (h>24)
4572 {
4573 h-=24.;
4574 }
4575
4576 return h;
4577}
4578
4579Double_t NcTimestamp::GetLMST(Double_t offset)
4580{
4593
4594 // Current GMST time in fractional hours
4595 Double_t h=GetGMST();
4596
4597 h+=offset;
4598
4599 while (h<0)
4600 {
4601 h+=24.;
4602 }
4603 while (h>24)
4604 {
4605 h-=24.;
4606 }
4607
4608 return h;
4609}
4610
4611Double_t NcTimestamp::GetLAST(Double_t offset)
4612{
4625
4626 // Current GAST time in fractional hours
4627 Double_t h=GetGAST();
4628
4629 h+=offset;
4630
4631 while (h<0)
4632 {
4633 h+=24.;
4634 }
4635 while (h>24)
4636 {
4637 h-=24.;
4638 }
4639
4640 return h;
4641}
4642
4643void NcTimestamp::SetLT(Double_t dt,Int_t y,Int_t m,Int_t d,Int_t hh,Int_t mm,Int_t ss,Int_t ns,Int_t ps,TString utc,Int_t leap,Double_t dut)
4644{
4709
4710 SetUT(y,m,d,hh,mm,ss,ns,ps,utc,leap,dut);
4711 Add(-dt);
4712}
4713
4714void NcTimestamp::SetLT(Double_t dt,Int_t y,Int_t m,Int_t d,Int_t hh,Int_t mm,Double_t s,TString utc,Int_t leap,Double_t dut)
4715{
4772
4773 SetUT(y,m,d,hh,mm,s,utc,leap,dut);
4774 Add(-dt);
4775}
4776
4777void NcTimestamp::SetLT(Double_t dt,Int_t y,Int_t m,Int_t d,TString time,TString utc,Int_t leap,Double_t dut)
4778{
4833
4834 SetUT(y,m,d,time,utc,leap,dut);
4835 Add(-dt);
4836}
4837
4838void NcTimestamp::SetLT(Double_t dt,TString date,TString time,Int_t mode,TString utc,Int_t leap,Double_t dut)
4839{
4896
4897 SetUT(date,time,mode,utc,leap,dut);
4898 Add(-dt);
4899}
4900
4901void NcTimestamp::SetLT(Double_t dt,Int_t y,Int_t d,Int_t s,Int_t ns,Int_t ps,TString utc,Int_t leap,Double_t dut)
4902{
4971
4972 SetUT(y,d,s,ns,ps,utc,leap,dut);
4973 Add(-dt);
4974}
4975
4976
4976Double_t NcTimestamp::GetJD(Double_t e,TString mode) const
4977{
4989
4990 Double_t jd=0;
4991
4992 if (mode=="J" || mode=="j") jd=(e-2000.0)*365.25+2451545.0;
4993
4994 if (mode=="B" || mode=="b") jd=(e-1900.0)*365.242198781+2415020.31352;
4995
4996 return jd;
4997}
4998
4999Double_t NcTimestamp::GetMJD(Double_t e,TString mode) const
5000{
5012
5013 Double_t mjd=GetJD(e,mode)-2400000.5;
5014
5015 return mjd;
5016}
5017
5018Double_t NcTimestamp::GetTJD(Double_t e,TString mode) const
5019{
5031
5032 Double_t tjd=GetJD(e,mode)-2440000.5;
5033
5034 return tjd;
5035}
5036
5037Double_t NcTimestamp::Almanac(Double_t* dpsi,Double_t* deps,Double_t* eps,Double_t* dl,TString name,Double_t* el,Double_t* eb,Double_t* dr,Double_t* value,Int_t j)
5038{
5147
5148 Double_t pi=acos(-1.);
5149
5150 Double_t td; // Time difference in fractional Julian days w.r.t. the start of J2000.
5151 Double_t tc; // Time difference in fractional Julian centuries w.r.t. the start of J2000.
5152 Double_t tm; // Time difference in fractional Julian millennia w.r.t. the start of J2000.
5153 const Int_t nvals=11;
5154 Double_t val[nvals]; // Array to hold the additional (orbital) parameters
5155
5156 // Initialize the solar system body related values
5157 if (el) *el=720;
5158 if (eb) *eb=720;
5159 if (dr) *dr=-1;
5160 for (Int_t i=0; i<nvals; i++)
5161 {
5162 val[i]=720;
5163 }
5164 val[0]=-1; // Semi major axis of the orbit
5165 val[1]=-1; // Eccentricity of the orbit
5166 val[10]=0; // Equation of Time, this will always be calculated correctly if requested
5167
5168 // Initialize the requested additional observable value
5169 if (value)
5170 {
5171 *value=0;
5172 if (j>=0 && j<nvals) *value=val[j];
5173 }
5174
5175 td=GetJD()-2451545.0;
5176 tc=td/36525.;
5177 tm=tc/10.;
5178
5179 // Fundamental solar system variables (in arcseconds) w.r.t. the J2000.0 equinox.
5180 // The expressions are taken from the USNO circular 179.
5181 // epsilon : Mean obliquity of the ecliptic
5182 // l : Mean anomaly of the Moon
5183 // lp : Mean anomaly of the Sun
5184 // f : Mean argument of latitude of the moon
5185 // d : Mean elongation of the Moon from the Sun
5186 // om : Mean longitude of the Moon's mean ascending node
5187 Double_t epsilon=84381.406-46.836769*tc-0.0001831*pow(tc,2)+0.00200340*pow(tc,3)-0.000000576*pow(tc,4)-0.0000000434*pow(tc,5);
5188 Double_t l=485868.249036+1717915923.2178*tc+31.8792*pow(tc,2)+0.051635*pow(tc,3)-0.00024470*pow(tc,4);
5189 Double_t lp=1287104.79305+129596581.0481*tc-0.5532*pow(tc,2)+0.000136*pow(tc,3)-0.00001149*pow(tc,4);
5190 Double_t f=335779.526232+1739527262.8478*tc-12.7512*pow(tc,2)-0.001037*pow(tc,3)+0.00000417*pow(tc,4);
5191 Double_t d=1072260.70369+1602961601.2090*tc-6.3706*pow(tc,2)+0.006593*pow(tc,3)-0.00003169*pow(tc,4);
5192 Double_t om=450160.398036-6962890.5431*tc+7.4722*pow(tc,2)+0.007702*pow(tc,3)-0.00005939*pow(tc,4);
5193
5194 // General precession in longitude (in arcseconds) w.r.t. J2000.0
5195 // according to Jean Meeus Ch.21 (page 136)
5196 Double_t prec=5029.0966*tc+1.11113*pow(tc,2)-0.000006*pow(tc,3);
5197
5198 if (eps) *eps=epsilon;
5199 if (dl) *dl=prec;
5200
5201 // Convert to radians for use with goniometric functions
5202 Double_t fac=pi/(180.*3600.);
5203 epsilon*=fac;
5204 l*=fac;
5205 lp*=fac;
5206 f*=fac;
5207 d*=fac;
5208 om*=fac;
5209
5210 //The IAU 2000A nutation series expansion.
5211 Double_t phi[28]={om,2.*(f-d+om),2.*(f+om),2.*om,lp,lp+2.*(f-d+om),l,
5212 2.*f+om,l+2.*(f+om),2.*(f-d+om)-lp,2.*(f-d)+om,2.*(f+om)-l,2.*d-l,l+om,
5213 om-l,2.*(f+d+om)-l,l+2.*f+om,2.*(f-l)+om,2.*d,2.*(f+d+om),2.*(f-d+om-lp),
5214 2.*(d-l),2.*(l+d+om),l+2.*(f-d+om),2.*f+om-l,2.*l,2.*f,lp+om};
5215 Double_t s[28]={-17.2064161,-1.3170907,-0.2276413, 0.2074554, 0.1475877,-0.0516821, 0.0711159,
5216 -0.0387298,-0.0301461, 0.0215829, 0.0128227, 0.0123457, 0.0156994, 0.0063110,
5217 -0.0057976,-0.0059641,-0.0051613, 0.0045893, 0.0063384,-0.0038571, 0.0032481,
5218 -0.0047722,-0.0031046, 0.0028593, 0.0020441, 0.0029243, 0.0025887,-0.0014053};
5219 Double_t sd[28]={-0.0174666,-0.0001675,-0.0000234, 0.0000207,-0.0003633, 0.0001226, 0.0000073,
5220 -0.0000367,-0.0000036,-0.0000494, 0.0000137, 0.0000011, 0.0000010, 0.0000063,
5221 -0.0000063,-0.0000011,-0.0000042, 0.0000050, 0.0000011,-0.0000001, 0.0000000,
5222 0.0000000,-0.0000001, 0.0000000, 0.0000021, 0.0000000, 0.0000000,-0.0000025};
5223 Double_t cp[28]={ 0.0033386,-0.0013696, 0.0002796,-0.0000698, 0.0011817,-0.0000524,-0.0000872,
5224 0.0000380, 0.0000816, 0.0000111, 0.0000181, 0.0000019,-0.0000168, 0.0000027,
5225 -0.0000189, 0.0000149, 0.0000129, 0.0000031,-0.0000150, 0.0000158, 0.0000000,
5226 -0.0000018, 0.0000131,-0.0000001, 0.0000010,-0.0000074,-0.0000066, 0.0000079};
5227 Double_t c[28]= { 9.2052331, 0.5730336, 0.0978459,-0.0897492, 0.0073871, 0.0224386,-0.0006750,
5228 0.0200728, 0.0129025,-0.0095929,-0.0068982,-0.0053311,-0.0001235,-0.0033228,
5229 0.0031429, 0.0025543, 0.0026366,-0.0024236,-0.0001220, 0.0016452,-0.0013870,
5230 0.0000477, 0.0013238,-0.0012338,-0.0010758,-0.0000609,-0.0000550, 0.0008551};
5231 Double_t cd[28]={ 0.0009086,-0.0003015,-0.0000485, 0.0000470,-0.0000184,-0.0000677, 0.0000000,
5232 0.0000018,-0.0000063, 0.0000299,-0.0000009, 0.0000032, 0.0000000, 0.0000000,
5233 0.0000000,-0.0000011, 0.0000000,-0.0000010, 0.0000000,-0.0000011, 0.0000000,
5234 0.0000000,-0.0000011, 0.0000010, 0.0000000, 0.0000000, 0.0000000,-0.0000002};
5235 Double_t sp[28]={ 0.0015377,-0.0004587, 0.0001374,-0.0000291,-0.0001924,-0.0000174, 0.0000358,
5236 0.0000318, 0.0000367, 0.0000132, 0.0000039,-0.0000004, 0.0000082,-0.0000009,
5237 -0.0000075, 0.0000066, 0.0000078, 0.0000020, 0.0000029, 0.0000068, 0.0000000,
5238 -0.0000025, 0.0000059,-0.0000003,-0.0000003, 0.0000013, 0.0000011,-0.0000045};
5239
5240 Double_t dp=0,de=0,da=0;
5241 for (Int_t i=0; i<28; i++)
5242 {
5243 dp+=(s[i]+sd[i]*tc)*sin(phi[i])+cp[i]*cos(phi[i]);
5244 de+=(c[i]+cd[i]*tc)*cos(phi[i])+sp[i]*sin(phi[i]);
5245 }
5246
5247 da=dp*cos(epsilon)+0.00264096*sin(om)+0.00006352*sin(2.*om)
5248 +0.00001175*sin(2.*f-2.*d+3.*om)+0.00001121*sin(2.*f-2.*d+om)
5249 -0.00000455*sin(2.*f-2.*d+2.*om)+0.00000202*sin(2.*f+3.*om)+0.00000198*sin(2.*f+om)
5250 -0.00000172*sin(3.*om)-0.00000087*tc*sin(om);
5251
5252 if (dpsi) *dpsi=dp;
5253 if (deps) *deps=de;
5254
5255 // Convert to seconds
5256 da/=15.;
5257
5259 // Determination of the Equation of Time via a recursive invokation //
5261 if (j==10)
5262 {
5263 Double_t xdpsi,xdeps,xeps,xlambda,xbeta;
5264 Almanac(&xdpsi,&xdeps,&xeps,0,"Sun",&xlambda,&xbeta);
5265
5266 // Convert from arcsec to degrees
5267 xdpsi/=3600.;
5268 xdeps/=3600.;
5269 xeps/=3600.;
5270
5271 // Correct for nutation to get the true values
5272 xeps+=xdeps;
5273 xlambda+=xdpsi;
5274
5275 while (xlambda<0) { xlambda+=360.; }
5276 while (xlambda>360) { xlambda-=360.; }
5277
5278 // Convert to radians for gonio
5279 Double_t epsr=xeps*pi/180.;
5280 Double_t lambdar=xlambda*pi/180.;
5281 Double_t betar=xbeta*pi/180.;
5282
5283 // True Right Ascension of the Sun (see Ch.13 p.93 of J. Meeus)
5284 Double_t x=sin(lambdar)*cos(epsr)-tan(betar)*sin(epsr);
5285 Double_t y=cos(lambdar);
5286 Double_t alpha=0;
5287 if (x || y) alpha=atan2(x,y)*180./pi;
5288
5289 while (alpha<0) { alpha+=360.; }
5290 while (alpha>360) { alpha-=360.; }
5291
5292 // Mean longitude of the Sun (see Ch.28 p.183 of J. Meeus)
5293 Double_t L0=280.4664567+360007.6982779*tm+0.03032028*pow(tm,2)+pow(tm,3)/49931.-pow(tm,4)/15300.-pow(tm,5)/2000000.;
5294
5295 while (L0<0) { L0+=360.; }
5296 while (L0>360) { L0-=360.; }
5297
5298 // Determine the Equation of Time in degrees (see Ch.28 p.183 of J. Meeus)
5299 Double_t eot=L0-0.0057183-alpha+xdpsi*cos(xeps*pi/180.);
5300
5301 // The Equation of Time never exceeds 20 minutes (= 5 degrees)
5302 while (eot<-5) { eot+=360.; }
5303 while (eot>5) { eot-=360.; }
5304
5305 // Convert the Equation of Time from degrees to seconds
5306 eot*=240.;
5307
5308 val[10]=eot;
5309 if (value) *value=eot;
5310 }
5311
5313 // Determination of the mean orbital elements and true ecliptic coordinates //
5314 // of a requested solar system body, for the mean equinox of the date. //
5316
5317 // The definitions and expressions are the ones used in the book of Jean Meeus
5318 // "Astronomical Algorithms" (2nd edition of August 2009), esp. chapters 31-33.
5319
5320 // The various observables are :
5321 // a : Semi major axis (in AU) of the orbit
5322 // e : Eccentricity of the orbit
5323 // inc : Inclination (in degrees) of the orbit with the ecliptic
5324 // omega : Mean ecliptic longitude (in degrees) of the ascending node
5325 // lp : Mean orbital longitude (in degrees) of the perihelion
5326 // l : Mean orbital longitude (in degrees) of the body
5327 // omega2 : Orbital argument (in degrees) of the perihelion
5328 // m : Mean orbital anomaly (in degrees) of the body
5329 // ec : Equation of the center (in degrees)
5330 // nu : True anomaly (in degrees) of the body
5331 // ltrue : Heliocentric longitude of the body
5332 // btrue : Heliocentric latitude of the body
5333 // r : Distance between the body and the sun
5334 // lambda : Geocentric ecliptic longitude
5335 // beta : Geocentric ecliptic latitude
5336
5337 Double_t a=0;
5338 Double_t e=0;
5339 Double_t inc=0;
5340 Double_t omega=0;
5341 Double_t omega2=0;
5342 Double_t m=0;
5343 Double_t ec=0;
5344 Double_t nu=0;
5345 Double_t ltrue=0;
5346 Double_t btrue=0;
5347 Double_t r=0;
5348 Double_t lambda=0;
5349 Double_t beta=0;
5350
5351 // Polynomial coefficients for a (in AU)of the 8 major planets
5352 Double_t aa0[8]={0.387098310,0.723329820,1.000001018,1.523679342,5.202603209,9.554909192,19.218446062,30.110386869};
5353 Double_t aa1[8]={0,0,0,0,0.0000001913,-0.0000021390,-0.0000000372,-0.0000001663};
5354 Double_t aa2[8]={0,0,0,0,0,0.000000004,0.00000000098,0.00000000069};
5355 Double_t aa3[8]={0,0,0,0,0,0,0,0};
5356 // Polynomial coefficients for e of the 8 major planets
5357 Double_t ea0[8]={0.20563175,0.00677192,0.01670863,0.09340065,0.04849793,0.05554814,0.04638122,0.00945575};
5358 Double_t ea1[8]={0.000020407,-0.000047765,-0.000042037,0.000090484,0.000163225,-0.000346641,-0.000027293,0.000006033};
5359 Double_t ea2[8]={-0.0000000283,0.0000000981,-0.0000001267,-0.0000000806,-0.0000004714,-0.0000006436,0.0000000789,0};
5360 Double_t ea3[8]={-0.00000000018,0.00000000046,0.00000000014,-0.00000000025,-0.00000000201,0.00000000340,0.00000000024,-0.00000000005};
5361 // Polynomial coefficients for inc (in degrees) of the 8 major planets
5362 Double_t ia0[8]={7.004986,3.394662,0,1.849726,1.303267,2.488879,0.773197,1.769953};
5363 Double_t ia1[8]={0.0018215,0.0010037,0,-0.0006011,-0.0054965,-0.0037362,0.0007744,-0.0093082};
5364 Double_t ia2[8]={-0.00001810,-0.00000088,0,0.00001276,0.00000466,-0.00001519,0.00003749,-0.00000708};
5365 Double_t ia3[8]={0.000000056,-0.000000007,0,-0.000000007,-0.000000002,0.000000087,-0.000000092,0.000000027};
5366 // Polynomial coefficients for omega (in degrees) of the 8 major planets
5367 Double_t oa0[8]={48.330893,76.679920,0,49.558093,100.464407,113.665503,74.005957,131.784057};
5368 Double_t oa1[8]={1.1861883,0.9011206,0,0.7720959,1.0209774,0.8770880,0.5211278,1.1022039};
5369 Double_t oa2[8]={0.00017542,0.00040618,0,0.00001557,0.00040315,-0.00012176,0.00133947,0.00025952};
5370 Double_t oa3[8]={0.000000215,-0.000000093,0,0.000002267,0.000000404,-0.000002249,0.000018484,-0.000000637};
5371 // Polynomial coefficients for lp (in degrees) of the 8 major planets
5372 Double_t pa0[8]={77.456119,131.563703,102.937348,336.060234,14.331207,93.057237,173.005291,48.120276};
5373 Double_t pa1[8]={1.5564776,1.4022288,1.7195366,1.8410449,1.6126352,1.9637613,1.4863790,1.4262957};
5374 Double_t pa2[8]={0.00029544,-0.00107618,0.00045688,0.00013477,0.00103042,0.00083753,0.00021406,0.00038434};
5375 Double_t pa3[8]={0.000000009,-0.000005678,-0.000000018,0.000000536,-0.000004464,0.000004928,0.000000434,0.000000020};
5376 // Polynomial coefficients for l (in degrees) of the 8 major planets
5377 Double_t la0[8]={252.250906,181.979801,100.466457,355.433000,34.351519,50.077444,314.055005,304.348665};
5378 Double_t la1[8]={149474.0722491,58519.2130302,36000.7698278,19141.6964471,3036.3027748,1223.5110686,429.8640561,219.8833092};
5379 Double_t la2[8]={0.00030350,0.00031014,0.00030322,0.00031052,0.00022330,0.00051908,0.00030390,0.00030882};
5380 Double_t la3[8]={0.000000018,0.000000015,0.000000020,0.000000016,0.000000037,-0.000000030,0.000000026,0.000000018};
5381
5382 TString names[10]={"Mercury","Venus","Earth","Mars","Jupiter","Saturn","Uranus","Neptune","Sun","Moon"};
5383
5384 Int_t k=-1;
5385 Int_t geo=1;
5386 for (Int_t jbody=0; jbody<10; jbody++)
5387 {
5388 if (name.Contains("*")) geo=0;
5389 if (name.Contains(names[jbody].Data()))
5390 {
5391 k=jbody;
5392 break;
5393 }
5394 }
5395
5396 if (k<0) return da; // Non-supported solar system body
5397
5398 if (!geo && k==8) return da; // Request for heliocentric data of the Sun itself
5399
5400 if (geo && k==2) return da; // Request for geocentric data of the Earth itself
5401
5402 // In case geocentric data for the Sun are requested, the heliocentric data
5403 // of the Earth are used to construct the corresponding data for the Sun.
5404 Int_t sun=0;
5405 if (k==8)
5406 {
5407 k=2;
5408 sun=1;
5409 }
5410
5411 // In case heliocentric data for the Moon are requested, the corresponding data
5412 // for the Earth are provided in view of negligible differences within the
5413 // accuracy of the algorithms used here.
5414 Int_t moon=0;
5415 if (k==9) moon=1;
5416 if (!geo && k==9) k=2;
5417
5418 lambda=0;
5419 beta=0;
5420
5422 // Determination of the geocentric data for the Moon //
5424
5425 if (geo && k==9)
5426 {
5427 // Low-precision geocentric ecliptic coordinates (in degrees) of the Moon.
5428 // Source : Astronomical Alamanac 2012 page D22.
5429 // Maximal errors : 0.3 degr. in lambda, 0.2 degr. in beta, 0.003 degr. in plax and 0.2 R_Earth in r
5430 // A more accurate method is the series expansion given in the book of Jean Meeus.
5431 lambda=218.32+481267.881*tc
5432 +6.29*sin((135.+477198.87*tc)*pi/180.)-1.27*sin((259.3-413335.36*tc)*pi/180.)
5433 +0.66*sin((235.7+890534.22*tc)*pi/180.)+0.21*sin((269.9+954397.74*tc)*pi/180.)
5434 -0.19*sin((357.5+35999.05*tc)*pi/180.)-0.11*sin((186.5+966404.03*tc)*pi/180.);
5435 beta=5.13*sin((93.3+483202.02*tc)*pi/180.)+0.28*sin((228.2+960400.89*tc)*pi/180.)
5436 -0.28*sin((318.3+6003.15*tc)*pi/180.)-0.17*sin((217.6-407332.21*tc)*pi/180.);
5437 Double_t plax=0.9508
5438 +0.0518*cos((135.+477198.87*tc)*pi/180.)+0.0095*cos((259.3-413335.36*tc)*pi/180.)
5439 +0.0078*cos((235.7+890534.22*tc)*pi/180.)+0.0028*cos((269.9+954397.74*tc)*pi/180.);
5440 r=1./sin(plax*pi/180.);
5441
5442 // Convert r into km using an average Earth radius of 6367.45 km
5443 r*=6367.45;
5444
5445 while (lambda<0) { lambda+=360.; }
5446 while (lambda>360) { lambda-=360.; }
5447
5448 if (el) *el=lambda;
5449 if (eb) *eb=beta;
5450 if (dr) *dr=r;
5451
5452 return da;
5453 }
5454
5456 // Determination of the heliocentric data for the requested solar system body //
5458
5459 a=0;
5460 e=0;
5461 inc=0;
5462 omega=0;
5463 l=0;
5464 lp=0;
5465
5466 a=aa0[k]+aa1[k]*tc+aa2[k]*pow(tc,2)+aa3[k]*pow(tc,3);
5467 e=ea0[k]+ea1[k]*tc+ea2[k]*pow(tc,2)+ea3[k]*pow(tc,3);
5468 inc=ia0[k]+ia1[k]*tc+ia2[k]*pow(tc,2)+ia3[k]*pow(tc,3);
5469 omega=oa0[k]+oa1[k]*tc+oa2[k]*pow(tc,2)+oa3[k]*pow(tc,3);
5470 lp=pa0[k]+pa1[k]*tc+pa2[k]*pow(tc,2)+pa3[k]*pow(tc,3);
5471 l=la0[k]+la1[k]*tc+la2[k]*pow(tc,2)+la3[k]*pow(tc,3);
5472
5473 while (omega<0) { omega+=360.; }
5474 while (omega>360) { omega-=360.; }
5475
5476 m=l-lp;
5477
5478 while (m<0) { m+=360.; }
5479 while (m>360) { m-=360.; }
5480
5481 ec=(2.*e-(pow(e,3)/4.)+(5.*pow(e,5)/96.))*sin(m*pi/180.)+((5.*pow(e,2)/4.)-(11.*pow(e,4)/24.))*sin(2.*m*pi/180.)
5482 +((13.*pow(e,3)/12.)-(43.*pow(e,5)/64.))*sin(3.*m*pi/180.)+(103.*pow(e,4)*sin(4.*m*pi/180.)/96.)
5483 +(1097.*pow(e,5)*sin(5.*m*pi/180.)/960.);
5484 ec*=180./pi;
5485
5486 omega2=lp-omega;
5487
5488 while (omega2<0) { omega2+=360.; }
5489 while (omega2>360) { omega2-=360.; }
5490
5491 while (lp<0) { lp+=360.; }
5492 while (lp>360) { lp-=360.; }
5493
5494 while (l<0) { l+=360.; }
5495 while (l>360) { l-=360.; }
5496
5497 nu=m+ec;
5498
5499 while (nu<0) { nu+=360.; }
5500 while (nu>360) { nu-=360.; }
5501
5502 // Store the orbital parameters in the additional values array
5503 if (!sun && !moon)
5504 {
5505 val[0]=a;
5506 val[1]=e;
5507 val[2]=inc;
5508 val[3]=omega;
5509 val[4]=lp;
5510 val[5]=l;
5511 val[6]=omega2;
5512 val[7]=m;
5513 val[8]=ec;
5514 val[9]=nu;
5515 }
5516
5517 // Make requested value available
5518 if (value)
5519 {
5520 *value=0;
5521 if (j>=0 && j<nvals) *value=val[j];
5522 }
5523
5524 r=a*(1.-e*e)/(1.+e*cos(nu*pi/180.));
5525
5526 // Use sine rule to obtain the latitude in radians
5527 Double_t sinb=sin(inc*pi/180.)*sin((l-omega+ec)*pi/180.);
5528 btrue=asin(sinb);
5529
5530 ltrue=omega;
5531 // Use Neper's rule to obtain the extra term of the longitude
5532 Double_t arg=l-omega+ec;
5533 while (arg<0) { arg+=360.; }
5534 while (arg>360) { arg-=360.; }
5535 Double_t extra=0;
5536 if (cos(btrue))
5537 {
5538 Double_t cosl=cos(arg*pi/180.)/cos(btrue);
5539 extra=acos(cosl)*180./pi;
5540 if (arg>180) extra=-extra;
5541 }
5542
5543 btrue*=180./pi;
5544 ltrue+=extra;
5545
5546 // Convert heliocentric Earth data into geocentric Sun data if requested
5547 if (sun)
5548 {
5549 btrue=-btrue;
5550 ltrue+=180.;
5551 }
5552
5553 while (ltrue<0) { ltrue+=360.; }
5554 while (ltrue>360) { ltrue-=360.; }
5555
5556 if (el) *el=ltrue;
5557 if (eb) *eb=btrue;
5558 if (dr) *dr=r;
5559
5560 if (!geo || sun) return da; // Heliocentric (or geocentric Sun) coordinates were requested
5561
5563 // Convert into geocentric ecliptic coordinates //
5565
5566 // The algorithm used here is the one outlined in Ch. 33 of the book of Jean Meeus.
5567 // In view of the accuracy of the current algorithm, the effects of light-time
5568 // and aberration are not taken into account here.
5569
5570 // Determine the heliocentric coordinates of the Earth
5571 // via recursive invokation of this memberfunction
5572 Double_t l0,b0,r0;
5573 Almanac(0,0,0,0,"Earth*",&l0,&b0,&r0);
5574
5575 Double_t x=r*cos(btrue*pi/180.)*cos(ltrue*pi/180.)-r0*cos(b0*pi/180.)*cos(l0*pi/180.);
5576 Double_t y=r*cos(btrue*pi/180.)*sin(ltrue*pi/180.)-r0*cos(b0*pi/180.)*sin(l0*pi/180.);
5577 Double_t z=r*sin(btrue*pi/180.)-r0*sin(b0*pi/180.);
5578
5579 lambda=atan2(y,x)*180./pi;
5580 beta=atan2(z,sqrt(x*x+y*y))*180./pi;
5581 r=sqrt(x*x+y*y+z*z);
5582
5583 while (lambda<0) { lambda+=360.; }
5584 while (lambda>360) { lambda-=360.; }
5585
5586 if (el) *el=lambda;
5587 if (eb) *eb=beta;
5588 if (dr) *dr=r;
5589
5590 return da;
5591}
5592
5593void NcTimestamp::SetEpoch(Double_t e,TString mode,TString utc,Int_t leap,Double_t dut)
5594{
5650
5651 Double_t jd=GetJD(e,mode);
5652 SetJD(jd,utc,leap,dut);
5653}
5654
5655Double_t NcTimestamp::GetEpoch(TString mode)
5656{
5666
5667 Double_t e=0;
5668 if (mode=="B" || mode=="b") e=GetBE();
5669 if (mode=="J" || mode=="j") e=GetJE();
5670 return e;
5671}
5672
5673TString NcTimestamp::GetDayTimeString(TString mode,Int_t ndig,Double_t offset,TString* date,TString* time,Bool_t full)
5674{
5718
5719 Bool_t set=kFALSE;
5720
5721 TString sdate=mode;
5722 sdate+=" information unavailable";
5723
5724 TString stime=mode;
5725 stime+=" information unavailable";
5726
5727 TString daytime=mode;
5728 daytime+=" information unavailable";
5729
5730 TString month[12]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
5731 TString day[7]={"Mon","Tue","Wed","Thu","Fri","Sat","Sun"};
5732
5733 UInt_t y=0;
5734 UInt_t m=0;
5735 UInt_t d=0;
5736 UInt_t wd=0;
5737 Int_t hh,mm,ss,ns,ps;
5738 Double_t s=0;
5739 ULong64_t sfrac=0;
5740 Double_t gat=0;
5741 Double_t gast=0;
5742 Bool_t bdate=kFALSE;
5743
5744 Int_t mjd,mjsec,mjns;
5745 GetMJD(mjd,mjsec,mjns);
5746
5747 // Check whether UT1 is the main reference
5748 if (mode=="UT1" && fUtc) mode="UT";
5749
5750 // Check whether UTC is the main reference
5751 if (mode=="UTC" && !fUtc) mode="UT";
5752
5753 // UT related information : UT, GAT, GMST and GAST date and time
5754 if (mode=="UT" || mode=="GAT" || mode=="GMST" || mode=="GAST")
5755 {
5756 if (mjd>=40587 && (mjd<65442 || (mjd==65442 && mjsec<8047)))
5757 {
5758 GetDate(kTRUE,0,&y,&m,&d);
5759 wd=GetDayOfWeek(kTRUE,0);
5760 bdate=kTRUE;
5761 }
5762 if (mode=="UT") GetUT(hh,mm,ss,ns,ps);
5763 if (mode=="GMST") GetGMST(hh,mm,ss,ns,ps);
5764 if (mode=="GAT")
5765 {
5766 // Obtain GAT as LAT without offset
5767 gat=GetLAT(0);
5768 Convert(gat,hh,mm,ss,ns,ps);
5769 }
5770 if (mode=="GAST")
5771 {
5772 gast=GetGAST();
5773 Convert(gast,hh,mm,ss,ns,ps);
5774 }
5775
5776 set=kTRUE;
5777 }
5778
5779 // TAI related information : TAI, UTC, GPS and TT date and time
5780 if (mode=="TAI" || mode=="UTC" || mode=="GPS" || mode=="TT")
5781 {
5782 if (fUtc && fUtc!=-3)
5783 {
5784 // A dummy timestamp is used to obtain the TAI corresponding date indicator
5785 NcTimestamp tx;
5787
5788 // Convert to the corresponding UTC, GPS or TT timestamps
5789 if (mode=="UTC") tx.AddSec(-fLeap);
5790 if (mode=="GPS") tx.AddSec(-19);
5791 if (mode=="TT") tx.AddSec(32.184);
5792
5793 Int_t tmjd,tsec,tns;
5794 tx.GetMJD(tmjd,tsec,tns);
5795
5796 if (tmjd>=40587 && (tmjd<65442 || (tmjd==65442 && tsec<8047)))
5797 {
5798 tx.GetDate(kTRUE,0,&y,&m,&d);
5799 wd=tx.GetDayOfWeek(kTRUE,0);
5800 bdate=kTRUE;
5801 }
5802 GetTAI(hh,mm,ss,ns,ps,mode);
5803
5804 set=kTRUE;
5805 }
5806 }
5807
5808 // Local time information
5809 if (mode=="LMT" || mode=="LAT" || mode=="LMST" || mode=="LAST")
5810 {
5811 // Determine the new date by including the offset
5812 NcTimestamp t2(*this);
5813 t2.Add(offset);
5814 Int_t mjd2,mjsec2,mjns2;
5815 t2.GetMJD(mjd2,mjsec2,mjns2);
5816 if (mjd2>=40587 && (mjd2<65442 || (mjd2==65442 && mjsec2<8047)))
5817 {
5818 t2.GetDate(kTRUE,0,&y,&m,&d);
5819 wd=t2.GetDayOfWeek(kTRUE,0);
5820 bdate=kTRUE;
5821 }
5822 // Determine the local time by including the offset w.r.t. the original timestamp
5823 Double_t hlt=0;
5824 if (mode=="LMT") hlt=GetLT(offset);
5825 if (mode=="LAT") hlt=GetLAT(offset);
5826 if (mode=="LMST") hlt=GetLMST(offset);
5827 if (mode=="LAST") hlt=GetLAST(offset);
5828 Convert(hlt,hh,mm,ss,ns,ps);
5829
5830 set=kTRUE;
5831 }
5832
5833 // No match found with requested date/time system
5834 if (!set)
5835 {
5836 if (date) *date=sdate;
5837 if (time) *time=stime;
5838 return daytime;
5839 }
5840
5841 // Create the date and time info string
5842 sdate="";
5843 stime="";
5844
5845 // The date string
5846 if (bdate)
5847 {
5848 if (full)
5849 {
5850 sdate.Form("%-s %02i-%-s-%-i",day[wd-1].Data(),d,month[m-1].Data(),y);
5851 }
5852 else
5853 {
5854 sdate.Form("%02i-%02i-%-i",d,m,y);
5855 }
5856 }
5857
5858 // The time string
5859 if (hh<10) stime+="0";
5860 stime+=hh;
5861 stime+=":";
5862 if (mm<10) stime+="0";
5863 stime+=mm;
5864 stime+=":";
5865 if (ss<10) stime+="0";
5866 stime+=ss;
5867 if (ndig>0)
5868 {
5869 stime+=".";
5870 s=double(ns)*1e-9+double(ps)*1e-12;
5871 s*=pow(10.,ndig);
5872 sfrac=ULong64_t(s);
5873 ULong64_t isfrac=pow(10,ndig-1);
5874 while (sfrac<isfrac)
5875 {
5876 stime+="0";
5877 isfrac/=10;
5878 }
5879 if (sfrac) stime+=sfrac;
5880 }
5881
5882 // Construct the combined date/time string
5883 daytime=sdate;
5884 daytime+=" ";
5885 daytime+=stime;
5886
5887 // Add the time system indicator
5888 if (mode=="UT")
5889 {
5890 mode="UT1";
5891 if (!fUtc) mode="UTC";
5892 }
5893 if (sdate=="") sdate="---";
5894 if (full)
5895 {
5896 sdate+=" ";
5897 sdate+=mode;
5898 stime+=" ";
5899 stime+=mode;
5900 daytime+=" ";
5901 daytime+=mode;
5902 }
5903
5904 if (date) *date=sdate;
5905 if (time) *time=stime;
5906
5907 return daytime;
5908}
5909
5911{
5920
5921 // Retrieve the current system clock time
5922 Set();
5923
5924 // Store this time as UTC
5925 FillJulian();
5926 Int_t ret=SetUTCparameters("A",0,0);
5927
5928 // Use the UTC parameters (if any) to determine UT1
5929 if (ret && ret!=-3)
5930 {
5931 AddSec(fDut); // Correct UTC for dUT=UT1-UTC to obtain UT1 as main reference
5932 }
5933 else
5934 {
5935 SetUTCparameters("N",0,0); // Keep the system clock time as main (UTC) reference
5936 }
5937 FillTAI();
5938}
5939
5941{
5947
5948 Bool_t ut1=kTRUE;
5949 if (!fUtc) ut1=kFALSE;
5950
5951 return ut1;
5952}
5953
ClassImp(NcTimestamp)
Handling of timestamps for (astro)particle physics research.
Definition NcTimestamp.h:20
virtual ~NcTimestamp()
Double_t GetEpoch(TString mode)
Double_t GetTJD()
Int_t SetUnixTime(Double_t sec, TString utc="A", Int_t leap=0, Double_t dut=0)
Int_t SetTAI(TString type, TString date, TString time, Int_t mode, TString utc, Int_t leap, Double_t dut=0)
Double_t GetMJD(Int_t y, Int_t m, Int_t d, Int_t hh, Int_t mm, Int_t ss, Int_t ns) const
Int_t SetGPS(Int_t w, Int_t sow, Int_t ns, Int_t ps, TString utc, Int_t leap, Double_t dut=0, Int_t icycle=0)
void SetLT(Double_t dt, Int_t y, Int_t m, Int_t d, Int_t hh, Int_t mm, Int_t ss, Int_t ns=0, Int_t ps=0, TString utc="A", Int_t leap=0, Double_t dut=0)
void SetSystemTime()
TString GetDayTimeString(TString mode, Int_t ndig=0, Double_t offset=0, TString *date=0, TString *time=0, Bool_t full=kTRUE)
Double_t Almanac(Double_t *dpsi=0, Double_t *deps=0, Double_t *eps=0, Double_t *dl=0, TString name="", Double_t *el=0, Double_t *eb=0, Double_t *dr=0, Double_t *value=0, Int_t j=0)
NcTimestamp & operator=(const NcTimestamp &t)
Double_t GetLAT(Double_t offset)
TTree * GetIERSdatabase() const
Double_t GetGMST()
Double_t GetLMST(Double_t offset)
Double_t GetUT()
Double_t GetMJD()
Bool_t IsUT1() const
Int_t GetPs() const
Double_t GetLT(Double_t offset)
void AddSecCalc(Double_t seconds, Bool_t utcpar=kTRUE)
Double_t GetBE()
Int_t SetUTCparameters(TString utc, Int_t leap, Double_t dut)
void SetEpoch(Double_t e, TString mode, TString utc="U", Int_t leap=0, Double_t dut=0)
Double_t GetGAST()
void SetUT(Int_t y, Int_t m, Int_t d, Int_t hh, Int_t mm, Int_t ss, Int_t ns=0, Int_t ps=0, TString utc="A", Int_t leap=0, Double_t dut=0)
void PrintTime(Double_t h, Int_t ndig=1) const
Double_t GetLAST(Double_t offset)
TTree * fUTCdata
TTree * LoadUTCparameterFiles(TString leapfile="$(NCFS)/IERS/leap.txt", TString dutfile="$(NCFS)/IERS/dut.txt")
void SetTJD(Int_t tjd, Int_t sec, Int_t ns, Int_t ps=0, TString utc="U", Int_t leap=0, Double_t dut=0)
void SetMJD(Int_t mjd, Int_t sec, Int_t ns, Int_t ps=0, TString utc="U", Int_t leap=0, Double_t dut=0)
Int_t GetNs() const
Double_t fDut
void SetJD(Int_t jd, Int_t sec, Int_t ns, Int_t ps=0, TString utc="U", Int_t leap=0, Double_t dut=0)
Double_t GetJE()
Double_t GetUnixTime()
void Add(Int_t d, Int_t s, Int_t ns, Int_t ps=0)
void Convert(Double_t date, Int_t &days, Int_t &secs, Int_t &ns) const
Int_t GetUTCparameters(Int_t &leap, Double_t &dut) const
Int_t GetDifference(NcTimestamp *t, Int_t &days, Int_t &sec, Int_t &ns, Int_t &ps, TString type="UT")
void AddSec(Double_t seconds)
void Date(Int_t mode=3, Double_t offset=0)
void AddCalc(Int_t d, Int_t s, Int_t ns, Int_t ps=0, Bool_t utcpar=kTRUE)
Int_t GetTAI(Int_t &d, Int_t &sec, Int_t &ns, Int_t &ps, Bool_t tmjd=kTRUE)
Double_t GetJD()
void SetPs(Int_t ps)
void SetNs(Int_t ns)