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
78// This UTC time runs at the pace of TAI, but is kept close (within 0.9 sec) to UT1
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, October 29, 2024 07:15Z
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
462void NcTimestamp::Date(Int_t mode,Double_t offset)
463{
486
487 Int_t mjd,mjsec,mjns;
488 GetMJD(mjd,mjsec,mjns);
489
490 TString month[12]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
491 TString day[7]={"Mon","Tue","Wed","Thu","Fri","Sat","Sun"};
492 UInt_t y,m,d,wd;
493 Int_t hh,mm,ss,ns,ps;
494 Double_t gat,gast;
495 Bool_t date=kFALSE;
496
497 // The UT date and time
498 if (abs(mode)==1 || abs(mode)==3)
499 {
500 if (mjd>=40587 && (mjd<65442 || (mjd==65442 && mjsec<8047)))
501 {
502 GetDate(kTRUE,0,&y,&m,&d);
503 wd=GetDayOfWeek(kTRUE,0);
504 printf(" %-s, %02d %-s %-d ",day[wd-1].Data(),d,month[m-1].Data(),y);
505 date=kTRUE;
506 }
507 else
508 {
509 cout << " Time ";
510 date=kFALSE;
511 }
512 GetUT(hh,mm,ss,ns,ps);
513 printf("%02d:%02d:%02d.%09d%03d",hh,mm,ss,ns,ps);
514 if (!fUtc)
515 {
516 cout << " (UTC) ";
517 }
518 else
519 {
520 cout << " (UT1) ";
521 }
522
523 // The GMST time information
524 GetGMST(hh,mm,ss,ns,ps);
525 printf("%02d:%02d:%02d.%09d%03d (GMST)\n",hh,mm,ss,ns,ps);
526
527 // Equation of Time and Equation of Equinoxes
528 Double_t eot;
529 Double_t eox=Almanac(0,0,0,0,"Sun",0,0,0,&eot,10);
530 // Convert to fractional hours
531 eox/=3600.;
532 eot/=3600.;
533 if (date)
534 {
535 cout << " ";
536 }
537 else
538 {
539 cout << " ";
540 }
541 if (eot>=0) cout << " ";
542 PrintTime(eot,3); cout << " (LAT-LMT)";
543 cout << " ";
544 if (eox>=0) cout << " ";
545 PrintTime(eox,3); cout << " (LAST-LMST)"; cout << endl;
546
547 // Greenwich apparent time information
548 if (mode<0)
549 {
550 gat=GetLT(eot); // Obtain GAT via the Equation of Time as offset
551 gast=GetGAST();
552 if (date)
553 {
554 cout << " ";
555 }
556 else
557 {
558 cout << " ";
559 }
560 PrintTime(gat,12); cout << " (GAT) ";
561 PrintTime(gast,12); cout << " (GAST)" << endl;
562 }
563
564 // Local time information
565 if (offset)
566 {
567 // Determine the new date by including the offset
568 NcTimestamp t2(*this);
569 t2.Add(offset);
570 Int_t mjd2,mjsec2,mjns2;
571 t2.GetMJD(mjd2,mjsec2,mjns2);
572 if (mjd2>=40587 && (mjd2<65442 || (mjd2==65442 && mjsec2<8047)))
573 {
574 t2.GetDate(kTRUE,0,&y,&m,&d);
575 wd=t2.GetDayOfWeek(kTRUE,0);
576 printf(" %-s, %02d %-s %-d ",day[wd-1].Data(),d,month[m-1].Data(),y);
577 date=kTRUE;
578 }
579 else
580 {
581 cout << " Time ";
582 date=kFALSE;
583 }
584 // Determine the local time by including the offset w.r.t. the original timestamp
585 Double_t hlt=0;
586 Double_t hlst=0;
587 if (mode>0)
588 {
589 hlt=GetLT(offset);
590 hlst=GetLMST(offset);
591 PrintTime(hlt,12); cout << " (LMT) ";
592 PrintTime(hlst,12); cout << " (LMST)" << endl;
593 }
594 else
595 {
596 hlt=GetLT(offset+eot); // Obtain LAT via the Equation of Time as extra offset
597 hlst=GetLAST(offset);
598 PrintTime(hlt,12); cout << " (LAT) ";
599 PrintTime(hlst,12); cout << " (LAST)" << endl;
600 }
601 }
602 }
603
604 // Julian parameter information
605 if (abs(mode)==2 || abs(mode)==3)
606 {
607 Int_t jd,jsec,jns;
608 GetJD(jd,jsec,jns);
609 Int_t tjd,tjsec,tjns;
610 GetTJD(tjd,tjsec,tjns);
611 printf(" Julian Epoch : %-.20f Besselian Epoch : %-.20f\n",GetJE(),GetBE());
612 printf(" JD : %7d sec : %5d ns : %9d ps : %3d Fractional : %25.17f\n",jd,jsec,jns,fJps,GetJD());
613 printf(" MJD : %7d sec : %5d ns : %9d ps : %3d Fractional : %25.17f\n",mjd,mjsec,mjns,fJps,GetMJD());
614 printf(" TJD : %7d sec : %5d ns : %9d ps : %3d Fractional : %25.17f\n",tjd,tjsec,tjns,fJps,GetTJD());
615 if (fUtc && fUtc!=-3)
616 {
617 printf(" TAI : %7d sec : %5d ns : %9d ps : %3d Fractional : %25.17f\n",fTmjd,fTsec,fTns,fTps,GetTAI());
618 }
619 }
620
621 // TAI related information
622 if (mode==4 && fUtc && fUtc!=-3)
623 {
624 printf( " Cumulated (TAI-UTC) leap seconds: %-3d UT1-UTC : %-.6f sec.",fLeap,fDut);
625 if (fUtc<0) cout << " (IERS database)" << endl;
626 if (fUtc>0) cout << " (Manual setting)" << endl;
627
628 // A dummy timestamp is used to obtain the TAI corresponding date indicator
629 NcTimestamp tx;
631
632 if (fTmjd>=40587 && (fTmjd<65442 || (fTmjd==65442 && fTsec<8047)))
633 {
634 tx.GetDate(kTRUE,0,&y,&m,&d);
635 wd=tx.GetDayOfWeek(kTRUE,0);
636 printf(" %-s, %02d %-s %-d ",day[wd-1].Data(),d,month[m-1].Data(),y);
637 date=kTRUE;
638 }
639 else
640 {
641 cout << " Time ";
642 date=kFALSE;
643 }
644
645 // Determine the TAI derived times
646 GetTAI(hh,mm,ss,ns,ps,"TAI");
647 printf("%02d:%02d:%02d.%09d%03d (TAI) ",hh,mm,ss,ns,ps);
648
649 GetTAI(hh,mm,ss,ns,ps,"UTC");
650 printf("%02d:%02d:%02d.%09d%03d (UTC)\n",hh,mm,ss,ns,ps);
651
652 GetTAI(hh,mm,ss,ns,ps,"GPS");
653 if (!date)
654 {
655 cout << " ";
656 }
657 else
658 {
659 cout << " ";
660 }
661 printf("%02d:%02d:%02d.%09d%03d (GPS) ",hh,mm,ss,ns,ps);
662
663 GetTAI(hh,mm,ss,ns,ps,"TT");
664 printf("%02d:%02d:%02d.%09d%03d (TT)\n",hh,mm,ss,ns,ps);
665 }
666}
667
668Double_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
669{
701
702 if (y<0 || m<1 || m>12 || d<1 || d>31) return -1;
703 if (hh<0 || hh>23 || mm<0 || mm>59 || ss<0 || ss>59 || ns<0 || ns>1e9) return -1;
704
705 // The UT daytime in fractional hours
706 Double_t ut=double(hh)+double(mm)/60.+(double(ss)+double(ns)*1.e-9)/3600.;
707
708 Double_t JD=0;
709
710 JD=367*y-int(7*(y+int((m+9)/12))/4)
711 -int(3*(int((y+(m-9)/7)/100)+1)/4)
712 +int(275*m/9)+d+1721028.5+ut/24.;
713
714 return JD;
715}
716
717Double_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
718{
750
751 Double_t JD=GetJD(y,m,d,hh,mm,ss,ns);
752
753 if (JD<0) return JD;
754
755 Double_t MJD=JD-2400000.5;
756
757 return MJD;
758}
759
760Double_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
761{
793
794 Double_t JD=GetJD(y,m,d,hh,mm,ss,ns);
795
796 if (JD<0) return JD;
797
798 Double_t TJD=JD-2440000.5;
799
800 return TJD;
801}
802
803Double_t NcTimestamp::GetJE(Double_t date,TString mode) const
804{
830
831 if ((mode != "jd") && (mode != "mjd") && (mode != "tjd")) return -99999;
832
833 Double_t jd=date;
834 if (mode=="mjd") jd=date+2400000.5;
835 if (mode=="tjd") jd=date+2440000.5;
836
837 Double_t je=2000.+(jd-2451545.)/365.25;
838
839 return je;
840}
841
842Double_t NcTimestamp::GetBE(Double_t date,TString mode) const
843{
869
870 if ((mode != "jd") && (mode != "mjd") && (mode != "tjd")) return -99999;
871
872 Double_t jd=date;
873 if (mode=="mjd") jd=date+2400000.5;
874 if (mode=="tjd") jd=date+2440000.5;
875
876 Double_t be=1900.+(jd-2415020.31352)/365.242198781;
877
878 return be;
879}
880
881void NcTimestamp::Convert(Double_t date,Int_t& days,Int_t& secs,Int_t& ns) const
882{
906
907 days=int(date);
908 date=date-double(days);
909 Int_t daysecs=24*3600;
910 date=date*double(daysecs);
911 secs=int(date);
912 date=date-double(secs);
913 ns=int(date*1.e9);
914}
915
916Double_t NcTimestamp::Convert(Int_t days,Int_t secs,Int_t ns) const
917{
940
941 Double_t frac=double(secs)+double(ns)*1.e-9;
942 Int_t daysecs=24*3600;
943 frac=frac/double(daysecs);
944 Double_t date=double(days)+frac;
945 return date;
946}
947
948void NcTimestamp::Convert(Double_t h,Int_t& hh,Int_t& mm,Int_t& ss,Int_t& ns,Int_t& ps) const
949{
969
970 // Neglect sign of h
971 h=fabs(h);
972
973 hh=int(h);
974 h=h-double(hh);
975 h=h*60.;
976 mm=int(h);
977 h=h-double(mm);
978 h=h*60.;
979 ss=int(h);
980 h=h-double(ss);
981 h=h*1.e9;
982 ns=int(h);
983 h=h-double(ns);
984 h=h*1000.;
985 ps=int(h);
986}
987
988void NcTimestamp::Convert(Double_t h,Int_t& hh,Int_t& mm,Double_t& ss) const
989{
1008
1009 // Neglect sign of h
1010 h=fabs(h);
1011
1012 hh=int(h);
1013 h=h-double(hh);
1014 h=h*60.;
1015 mm=int(h);
1016 h=h-double(mm);
1017 ss=h*60.;
1018}
1019
1020Double_t NcTimestamp::Convert(Int_t hh,Int_t mm,Int_t ss,Int_t ns,Int_t ps) const
1021{
1041
1042 // Neglect the sign of the input values
1043 hh=abs(hh);
1044 mm=abs(mm);
1045 ss=abs(ss);
1046 ns=abs(ns);
1047 ps=abs(ps);
1048
1049 Double_t h=hh;
1050 h+=double(mm)/60.+(double(ss)+double(ns)*1.e-9+double(ps)*1.e-12)/3600.;
1051
1052 return h;
1053}
1054
1055Double_t NcTimestamp::Convert(Int_t hh,Int_t mm,Double_t ss) const
1056{
1075
1076 // Neglect the sign of the input values
1077 hh=abs(hh);
1078 mm=abs(mm);
1079 ss=fabs(ss);
1080
1081 Double_t h=hh;
1082 h+=double(mm)/60.+ss/3600.;
1083
1084 return h;
1085}
1086
1087void NcTimestamp::PrintTime(Double_t h,Int_t ndig) const
1088{
1105
1106 Int_t hh,mm,ss;
1107 ULong64_t sfrac;
1108 Double_t s;
1109
1110 while (h<-24)
1111 {
1112 h+=24.;
1113 }
1114 while (h>24)
1115 {
1116 h-=24.;
1117 }
1118
1119 Convert(h,hh,mm,s);
1120 ss=Int_t(s);
1121 s-=Double_t(ss);
1122 s*=pow(10.,ndig);
1123 sfrac=ULong64_t(s);
1124
1125 if (h<0) printf("%-s","-");
1126 printf("%02d:%02d:%02d.%0*llu",hh,mm,ss,ndig,sfrac);
1127}
1128
1130{
1137
1138 UInt_t y,m,d,hh,mm,ss;
1139
1140 GetDate(kTRUE,0,&y,&m,&d);
1141 GetTime(kTRUE,0,&hh,&mm,&ss);
1142 Int_t ns=GetNanoSec();
1143
1144 Double_t mjd=GetMJD(y,m,d,hh,mm,ss,ns);
1145
1146 fMJD=int(mjd);
1147 fJsec=GetSec()%(24*3600); // Daytime in elapsed seconds
1148 fJns=ns; // Remaining fractional elapsed second in nanoseconds
1149
1150 // Store the TTimeStamp seconds and nanoseconds values
1151 // for which this Julian calculation was performed.
1152 fCalcs=GetSec();
1153 fCalcns=GetNanoSec();
1154}
1155
1156void NcTimestamp::GetMJD(Int_t& mjd,Int_t& sec,Int_t& ns)
1157{
1169
1170 if (fCalcs != GetSec() || fCalcns != GetNanoSec())
1171 {
1172 FillJulian();
1173 SetUTCparameters("A",0,0);
1174 }
1175
1176 mjd=fMJD;
1177 sec=fJsec;
1178 ns=fJns;
1179}
1180
1182{
1192
1193 Int_t mjd=0;
1194 Int_t sec=0;
1195 Int_t ns=0;
1196 GetMJD(mjd,sec,ns);
1197
1198 Double_t date=Convert(mjd,sec,ns);
1199
1200 return date;
1201}
1202
1203void NcTimestamp::GetTJD(Int_t& tjd,Int_t& sec,Int_t& ns)
1204{
1216
1217 Int_t mjd=0;
1218 GetMJD(mjd,sec,ns);
1219
1220 tjd=mjd-40000;
1221}
1222
1224{
1234
1235 Int_t tjd=0;
1236 Int_t sec=0;
1237 Int_t ns=0;
1238 GetTJD(tjd,sec,ns);
1239
1240 Double_t date=Convert(tjd,sec,ns);
1241
1242 return date;
1243}
1244
1245Int_t NcTimestamp::GetTAI(Int_t& d,Int_t& sec,Int_t& ns,Int_t& ps,Bool_t tmjd)
1246{
1272
1273 // Make sure to have the updated parameters
1274 GetMJD(d,sec,ns);
1275 FillTAI();
1276
1277 d=0;
1278 sec=0;
1279 ns=0;
1280 ps=0;
1281
1282 if (!fUtc) return 0;
1283
1284 d=fTmjd;
1285 sec=fTsec;
1286 ns=fTns;
1287 ps=fTps;
1288
1289 if (!tmjd) d-=36204;
1290
1291 return fUtc;
1292}
1293
1294Double_t NcTimestamp::GetTAI(Bool_t tmjd)
1295{
1317
1318 if (!fUtc) return 0;
1319
1320 Int_t d=0;
1321 Int_t s=0;
1322 Int_t ns=0;
1323 Int_t ps=0;
1324 GetTAI(d,s,ns,ps,tmjd);
1325
1326 Double_t days=Convert(d,s,ns);
1327
1328 return days;
1329}
1330
1331Int_t NcTimestamp::GetTAI(Int_t& hh,Int_t& mm,Int_t& ss,Int_t& ns,Int_t& ps,TString type)
1332{
1356
1357 hh=0;
1358 mm=0;
1359 ss=0;
1360 ns=0;
1361 ps=0;
1362
1363 if (type!="TAI" && type!="UTC" && type!="GPS" && type!="TT") return 0;
1364
1365 Int_t d,sec,nsec,psec;
1366
1367 // Use a dummy timestamp to easily correct for the various offsets
1368 NcTimestamp tx=(*this);
1369 if (type=="UTC") tx.Add(0,-fLeap,0,0);
1370 if (type=="GPS") tx.Add(0,-19,0,0);
1371 if (type=="TT") tx.Add(0,32,184000000,0);
1372
1373 // Use the UTC parameters of the actual (unmodified) timestamp
1374 tx.fLeap=fLeap;
1375 tx.fDut=fDut;
1376
1377 tx.GetTAI(d,sec,nsec,psec);
1378
1379 hh=sec/3600;
1380 sec=sec%3600;
1381 mm=sec/60;
1382 ss=sec%60;
1383 ns=nsec;
1384 ps=psec;
1385
1386 return fUtc;
1387}
1388
1390{
1421
1422 Double_t t=0;
1423
1424 Int_t days=0;
1425 Int_t secs=0;
1426 Int_t ns=0;
1427 Int_t mjd=0;
1428 GetMJD(mjd,secs,ns);
1429 Int_t ps=GetPs();
1430
1431 // Get UTC from the stored UT1 via UTC=UT1-dUT
1432 if (fUtc)
1433 {
1434 NcTimestamp tx;
1435 tx.SetMJD(mjd,secs,ns,ps);
1436 tx.AddSec(-fDut);
1437 tx.GetMJD(mjd,secs,ns);
1438 ps=tx.GetPs();
1439 }
1440
1441 days=mjd-40587;
1442
1443 t=(days*86400)+secs;
1444 t+=double(ns)*1.e-9+double(ps)*1.e-12;
1445
1446 return t;
1447}
1448
1449void NcTimestamp::GetJD(Int_t& jd,Int_t& sec,Int_t& ns)
1450{
1462
1463 Int_t mjd=0;
1464 GetMJD(mjd,sec,ns);
1465
1466 jd=mjd+2400000;
1467 sec+=12*3600;
1468 if (sec >= 24*3600)
1469 {
1470 sec-=24*3600;
1471 jd+=1;
1472 }
1473}
1474
1476{
1486
1487 Int_t jd=0;
1488 Int_t sec=0;
1489 Int_t ns=0;
1490 GetJD(jd,sec,ns);
1491
1492 Double_t date=Convert(jd,sec,ns);
1493
1494 return date;
1495}
1496
1498{
1505
1506 Double_t jd=GetJD();
1507 Double_t je=GetJE(jd);
1508 return je;
1509}
1510
1512{
1519
1520 Double_t jd=GetJD();
1521 Double_t be=GetBE(jd);
1522 return be;
1523}
1524
1525void NcTimestamp::SetMJD(Int_t mjd,Int_t sec,Int_t ns,Int_t ps,TString utc,Int_t leap,Double_t dut)
1526{
1605
1606 if (sec<0 || sec>=24*3600 || ns<0 || ns>=1e9 || ps<0 || ps>=1000)
1607 {
1608 cout << " *NcTimestamp::SetMJD* Invalid input."
1609 << " sec : " << sec << " ns : " << ns << " ps : " << ps << endl;
1610 return;
1611 }
1612
1613 fMJD=mjd;
1614 fJsec=sec;
1615 fJns=ns;
1616 fJps=ps;
1617
1618 Int_t epoch=40587; // MJD of the start of the epoch
1619 Int_t limit=65442; // MJD of the latest possible TTimeStamp date/time
1620
1621 Int_t date,time;
1622 if (mjd<epoch || mjd>limit || (mjd==limit && sec>=8047))
1623 {
1624 Set(0,kFALSE,0,kFALSE);
1625 date=GetDate();
1626 time=GetTime();
1627 Set(date,time,0,kTRUE,0);
1628 }
1629 else
1630 {
1631 // The elapsed time since start of EPOCH
1632 Int_t days=mjd-epoch;
1633 UInt_t secs=days*24*3600;
1634 secs+=sec;
1635 Set(secs,kFALSE,0,kFALSE);
1636 date=GetDate();
1637 time=GetTime();
1638 Set(date,time,ns,kTRUE,0);
1639 }
1640
1641 // Denote that the Julian and TTimeStamp parameters are synchronised,
1642 // even in the case the MJD falls outside the TTimeStamp validity range.
1643 // The latter still allows retrieval of Julian parameters for these
1644 // earlier times.
1645 fCalcs=GetSec();
1646 fCalcns=GetNanoSec();
1647
1648 // Update the UTC parameters and corresonding TAI time recording
1649 SetUTCparameters(utc,leap,dut);
1650
1651 if (utc=="A" || utc=="M") AddSec(fDut);
1652}
1653
1654void NcTimestamp::SetMJD(Double_t mjd,TString utc,Int_t leap,Double_t dut)
1655{
1734
1735 Int_t days=0;
1736 Int_t secs=0;
1737 Int_t ns=0;
1738 Convert(mjd,days,secs,ns);
1739 SetMJD(days,secs,ns,0,utc,leap,dut);
1740}
1741
1742void NcTimestamp::SetJD(Int_t jd,Int_t sec,Int_t ns,Int_t ps,TString utc,Int_t leap,Double_t dut)
1743{
1822
1823 Int_t mjd=jd-2400000;
1824 sec-=12*3600;
1825 if (sec<0)
1826 {
1827 sec+=24*3600;
1828 mjd-=1;
1829 }
1830
1831 SetMJD(mjd,sec,ns,ps,utc,leap,dut);
1832}
1833
1834void NcTimestamp::SetJD(Double_t jd,TString utc,Int_t leap,Double_t dut)
1835{
1914
1915 Int_t days=0;
1916 Int_t secs=0;
1917 Int_t ns=0;
1918 Convert(jd,days,secs,ns);
1919
1920 SetJD(days,secs,ns,0,utc,leap,dut);
1921}
1922
1923void NcTimestamp::SetTJD(Int_t tjd,Int_t sec,Int_t ns,Int_t ps,TString utc,Int_t leap,Double_t dut)
1924{
2003
2004 Int_t mjd=tjd+40000;
2005
2006 SetMJD(mjd,sec,ns,ps,utc,leap,dut);
2007}
2008
2009void NcTimestamp::SetTJD(Double_t tjd,TString utc,Int_t leap,Double_t dut)
2010{
2089
2090 Int_t days=0;
2091 Int_t secs=0;
2092 Int_t ns=0;
2093 Convert(tjd,days,secs,ns);
2094
2095 SetTJD(days,secs,ns,0,utc,leap,dut);
2096}
2097
2099{
2107
2108 if (!fUtc || fUtc==-3)
2109 {
2110 fTmjd=0;
2111 fTsec=0;
2112 fTns=0;
2113 fTps=0;
2114 return;
2115 }
2116
2117 // Use memberfunction to ensure most recent values for the stored UT1
2119 fTps=GetPs();
2120
2121 // Dummy timestamp to easily obtain TAI based day etc. counts
2122 // It is essential not to use UTC parameters here in order to prevent an infinite loop
2123 NcTimestamp tx;
2124 tx.SetMJD(fTmjd,fTsec,fTns,fTps,"N"); // This stores UT1 as if it were UTC
2125
2126 tx.AddSecCalc(-fDut,kFALSE); // Convert the stored UT1 into UTC via UTC=UT1-dUT
2127 tx.AddCalc(0,fLeap,0,0,kFALSE); // Account for the leap seconds
2128
2129 // Retrieve the corresponding TAI day etc. count
2130 tx.GetMJD(fTmjd,fTsec,fTns);
2131 fTps=tx.GetPs();
2132}
2133
2134Int_t NcTimestamp::SetTAI(TString type,TString date,TString time,Int_t mode,TString utc,Int_t leap,Double_t dut)
2135{
2191
2192 Int_t ibad=0;
2193
2194 if (type!="UTC" && type!="GPS" && type!="TAI" && type!="TT") ibad=1;
2195
2196 if (utc!="M" && utc!="A") ibad=1;
2197
2198 if (utc=="M" && fabs(dut)>0.9) ibad=1;
2199
2200 if (utc=="A" && !fUTCdata) ibad=1;
2201
2202 // In case utc="A" check whether the corresponding IERS database info is available
2203 if (utc=="A")
2204 {
2205 NcTimestamp tx; // Dummy timestamp for easy MJD retrieval
2206 tx.SetUT(date,time,mode,utc);
2207 Int_t ien=GetUTCparameters(tx.fMJD,leap,dut);
2208 if (ien<0) ibad=1;
2209 }
2210
2211 if (ibad)
2212 {
2213 SetJD(0,"N");
2214 return fUtc;
2215 }
2216
2217 SetUT(date,time,mode,utc,leap,dut);
2218 if (type != "UTC") Add(0,-fLeap,0,0); // Account for the leap seconds
2219 if (type == "GPS") Add(0,19,0,0); // Account for TAI-GPS=19 sec.
2220 if (type == "TT") Add(0,-32,-184000000,0); // Account for TAI-TT=-32.184 sec.
2221
2222 return fUtc;
2223}
2224
2225Int_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)
2226{
2293
2294 Int_t ibad=0;
2295
2296 if (sec<0 || sec>86400 || ns<0 || ns>999999999 || ps<0 || ps>999) ibad=1;
2297
2298 if (utc!="M" && utc!="A") ibad=1;
2299
2300 if (utc=="M" && fabs(dut)>0.9) ibad=1;
2301
2302 if (utc=="A" && !fUTCdata) ibad=1;
2303
2304 // Set the corresponding MJD
2305 Int_t mjd=d;
2306 if (!tmjd) mjd+=36204;
2307
2308 // In case utc="A" check whether the corresponding IERS database info is available
2309 if (utc=="A")
2310 {
2311 Int_t ien=GetUTCparameters(mjd,leap,dut);
2312 if (ien<0) ibad=1;
2313 }
2314
2315 if (ibad)
2316 {
2317 SetJD(0,"N");
2318 return fUtc;
2319 }
2320
2321 SetMJD(mjd,sec,ns,ps);
2322 SetUTCparameters(utc,leap,dut); // Update the UTC parameters and corresonding TAI time recording
2323 Add(0,-fLeap,0,0); // Account for the leap seconds
2324 AddSec(fDut); // Account for dUT=UT1-UTC
2325
2326 // Set the corresponding TAI day count etc.
2327 FillTAI();
2328
2329 return fUtc;
2330}
2331
2332Int_t NcTimestamp::SetTAI(Double_t tai,TString utc,Int_t leap,Double_t dut,Bool_t tmjd)
2333{
2400
2401 Int_t days=0;
2402 Int_t secs=0;
2403 Int_t ns=0;
2404 Convert(tai,days,secs,ns);
2405
2406 SetTAI(days,secs,ns,0,utc,leap,dut,tmjd);
2407
2408 return fUtc;
2409}
2410
2411Int_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)
2412{
2468
2469 if (w<0 || sow<0 || sow>604800 || ns<0 || ns>999999999 || ps<0 || ps>999 || icycle<0)
2470 {
2471 SetJD(0,"N");
2472 return fUtc;
2473 }
2474
2475 // Correct the week count for the cycle number if needed
2476 if (icycle) w+=icycle*1024;
2477
2478 Int_t days=8040+w*7;
2479 sow+=19;
2480 Int_t daysecs=24*3600;
2481 Int_t days2=sow/daysecs;
2482 days+=days2;
2483 Int_t secs=sow%daysecs;
2484
2485 SetTAI(days,secs,ns,ps,utc,leap,dut);
2486
2487 return fUtc;
2488}
2489
2490Int_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)
2491{
2548
2549 if (w<0 || dow<0 || dow>7 || sod<0 || sod>86400 || ns<0 || ns>999999999 || ps<0 || ps>999 || icycle<0)
2550 {
2551 SetJD(0,"N");
2552 return fUtc;
2553 }
2554
2555 // Correct the week count for the cycle number if needed
2556 if (icycle) w+=icycle*1024;
2557
2558 Int_t days=8040+w*7+dow;
2559 sod+=19;
2560
2561 SetTAI(days,sod,ns,ps,utc,leap,dut);
2562
2563 return fUtc;
2564}
2565
2566Int_t NcTimestamp::SetUnixTime(Double_t sec,TString utc,Int_t leap,Double_t dut)
2567{
2648
2649 // Determine the fractional day count since the start of the Unix Epoch
2650 Double_t tday=sec/86400.;
2651
2652 Int_t days=0;
2653 Int_t s=0;
2654 Int_t ns=0;
2655 Convert(tday,days,s,ns);
2656
2657 // Determine the remaining elapsed picoseconds
2658 Int_t iword=int(sec);
2659 sec=sec-double(iword);
2660 sec*=1e9;
2661 iword=int(sec);
2662 sec=sec-double(iword);
2663 Int_t ps=int(sec*1000.);
2664
2665 // Unix time is related to UTC and not to UT1.
2666 if (utc=="U") utc="A";
2667
2668 SetMJD(40587,0,0,0); // Start of the Unix Epoch
2669 SetUTCparameters(utc,leap,dut); // Update the UTC parameters and corresonding TAI time recording
2670 Add(days,s,ns,ps); // Add the elapsed time
2671 if (fUtc) AddSec(fDut); // Correct for dUT=UT1-UTC
2672
2673 return fUtc;
2674}
2675
2677{
2689
2690 if (ns>=0 && ns<=999999999) fJns=ns;
2691}
2692
2694{
2703
2704 return fJns;
2705}
2706
2708{
2719
2720 if (ps>=0 && ps<=999) fJps=ps;
2721}
2722
2724{
2732
2733 return fJps;
2734}
2735
2736Int_t NcTimestamp::GetUTCparameters(Int_t& leap,Double_t& dut) const
2737{
2759
2760 leap=fLeap;
2761 dut=fDut;
2762
2763 return fUtc;
2764}
2765
2766Int_t NcTimestamp::GetUTCparameters(Int_t mjd,Int_t& leap,Double_t& dut) const
2767{
2778
2779 leap=0;
2780 dut=0;
2781
2782 if (!fUTCdata) return -1;
2783
2784 Int_t nen=fUTCdata->GetEntries();
2785
2786 if (!nen) return -1;
2787
2788 Int_t dbmjd=0;
2789 Int_t dbleap=0;
2790 Double_t dbdut=0;
2791
2792 fUTCdata->SetBranchAddress("mjd",&dbmjd);
2793 fUTCdata->SetBranchAddress("lsec",&dbleap);
2794 fUTCdata->SetBranchAddress("dut",&dbdut);
2795
2796 // Data of the first entry
2797 fUTCdata->GetEntry(0);
2798 Int_t ien=mjd-dbmjd;
2799
2800 if (ien<0 || ien>=nen) return -1; // Specified mjd not in range of database
2801
2802 fUTCdata->GetEntry(ien);
2803 if (dbmjd==mjd) // Specified mjd is found in database
2804 {
2805 leap=dbleap;
2806 dut=dbdut;
2807 }
2808 else
2809 {
2810 ien=-1;
2811 leap=0;
2812 dut=0;
2813 }
2814
2815 return ien;
2816}
2817
2818Int_t NcTimestamp::SetUTCparameters(TString utc,Int_t leap,Double_t dut)
2819{
2880
2881 fUtc=0;
2882 if (utc=="U") fUtc=-3;
2883 fLeap=0;
2884 fDut=0;
2885
2886 Int_t ibad=0;
2887
2888 if (utc!="N" && utc!="M" && utc!="A" && utc!="U") ibad=1;
2889
2890 if (utc=="N" || ((utc=="A" || utc=="U") && !fUTCdata)) ibad=1;
2891
2892 if (utc=="M" && fabs(dut)>0.9) ibad=1;
2893
2894 if (ibad)
2895 {
2896 FillTAI();
2897 return fUtc;
2898 }
2899
2900 // From here only utc="M", utc="A" or utc="U"
2901
2902 if (utc=="M")
2903 {
2904 fUtc=1;
2905 fLeap=leap;
2906 fDut=dut;
2907
2908 FillTAI();
2909 return fUtc;
2910 }
2911
2912 // Automatic setting of the UTC parameters from the loaded data files
2913 Int_t nen=fUTCdata->GetEntries();
2914
2915 if (nen<=0) // No entries in the IERS data TTree
2916 {
2917 FillTAI();
2918 return fUtc;
2919 }
2920
2921 Int_t mjd=0;
2922
2923 fUTCdata->SetBranchAddress("mjd",&mjd);
2924 fUTCdata->SetBranchAddress("lsec",&leap);
2925 fUTCdata->SetBranchAddress("dut",&dut);
2926
2927 // Get the starting mjd of the IERS daily data
2928 // and determine the entry for the current MJD info
2929 fUTCdata->GetEntry(0);
2930 Int_t ien=fMJD-mjd;
2931 if (ien>=0 && ien<nen)
2932 {
2933 fUTCdata->GetEntry(ien);
2934 if (mjd==fMJD)
2935 {
2936 fUtc=-1;
2937 if (utc=="U") fUtc=-2;
2938 fLeap=leap;
2939 fDut=dut;
2940 }
2941 }
2942
2943 FillTAI();
2944
2945 return fUtc;
2946}
2947
2948TTree* NcTimestamp::LoadUTCparameterFiles(TString leapfile,TString dutfile)
2949{
2998
2999 // Expand the input file pathnames
3000 leapfile=gSystem->ExpandPathName(leapfile.Data());
3001 dutfile=gSystem->ExpandPathName(dutfile.Data());
3002
3003 if (fUTCdata)
3004 {
3005 delete fUTCdata;
3006 fUTCdata=0;
3007 }
3008
3009 // The Leap Second input data file
3010 ifstream fleap;
3011 fleap.clear();
3012 fleap.open(leapfile.Data());
3013 if (!fleap.good())
3014 {
3015 cout << " *NcTimestamp::LoadUTCparameterFiles* Data file for Leap Seconds not found ***" << endl;
3016 cout << " File name provided was : " << leapfile.Data() << endl;
3017 return 0;
3018 }
3019
3020 // The dUT=UT1-UTC input data file
3021 ifstream fdut;
3022 fdut.clear();
3023 fdut.open(dutfile.Data());
3024 if (!fdut.good())
3025 {
3026 cout << " *NcTimestamp::LoadUTCparameterFiles* Data file for dUT=UT-UTC not found ***" << endl;
3027 cout << " File name provided was : " << dutfile.Data() << endl;
3028 return 0;
3029 }
3030
3031 // Determine the number of characters in the Leap Second input file
3032 // to reserve sufficient array storage of all Leap Second entries
3033 fleap.seekg(0,fleap.end); // Position at end of file
3034 Int_t ndim=fleap.tellg();
3035
3036 // The storage arrays for the Leap second data
3037 Int_t* lmjd=new Int_t[ndim];
3038 Int_t* leap=new Int_t[ndim];
3039
3041 // Read the Leap Second data //
3043
3044 fleap.seekg(0); // Position at begin of file
3045
3046 // Read title lines until the first data line is found
3047 string line;
3048 Int_t i=0;
3049 while (getline(fleap,line))
3050 {
3051 if (line.find("1972")!=line.npos) break;
3052 i++;
3053 }
3054
3055 // Go to the beginning of the file and skip the title lines preceding the data lines
3056 fleap.seekg(0);
3057 for (Int_t j=0; j<i; j++)
3058 {
3059 getline(fleap,line);
3060 }
3061
3062 // Read the data
3063 Float_t rmjd=0;
3064 Int_t lsec=0;
3065 Float_t x; // Dummy variable for skipping non-requested data columns
3066 i=0;
3067 while (fleap >> rmjd >> x >> x >> x >> lsec)
3068 {
3069 lmjd[i]=int(rmjd);
3070 leap[i]=lsec;
3071 i++;
3072 }
3073
3074 // The number of actual Leap Second entries
3075 Int_t nleap=i;
3076
3078 // Read the dUT=UT1-UTC //
3080
3081 fdut.seekg(0); // Position at begin of file
3082
3083 // Read title lines until the first data line is found
3084 i=0;
3085 while (getline(fdut,line))
3086 {
3087 if (line.find("1962")!=line.npos) break;
3088 i++;
3089 }
3090
3091 // Go to the beginning of the file and skip the title lines preceding the data lines
3092 fdut.seekg(0);
3093 for (Int_t j=0; j<i; j++)
3094 {
3095 getline(fdut,line);
3096 }
3097
3098 // Read the dUT daily data and fill the TTree structure
3099 Int_t mjd=0;
3100 Double_t dut=0;
3101
3102 // The produced output structure
3103 fUTCdata=new TTree("UTCdata","Daily UTC leap second and dUT=UT-UTC parameter data");
3104
3105 // Prevent this Tree to be automatically coupled to a user defined output file
3106 fUTCdata->SetDirectory(0);
3107
3108 // The output variables for the Tree
3109 fUTCdata->Branch("mjd",&mjd,"mjd/I");
3110 fUTCdata->Branch("lsec",&lsec,"lsec/I");
3111 fUTCdata->Branch("dut",&dut,"dut/D");
3112
3113 while (fdut >> x >> x >> x >> mjd >> x >> x >> dut >> x >> x >> x >> x >> x >> x >> x >> x >> x)
3114 {
3115 lsec=0;
3116 // Retrieve the corresponding Leap Second info
3117 for (Int_t j=nleap-1; j>=0; j--)
3118 {
3119 if (mjd>=lmjd[j])
3120 {
3121 lsec=leap[j];
3122 break;
3123 }
3124 }
3125 fUTCdata->Fill();
3126 }
3127
3128 delete[] lmjd;
3129 delete[] leap;
3130
3131 // Retrieve the UTC parameters for the current timestamp
3132 if (!fUtc) // Reference time is UTC
3133 {
3134 SetUTCparameters("A",0,0);
3135 AddSec(fDut);
3136 }
3137 else // Reference time is UT1
3138 {
3139 SetUTCparameters("U",0,0);
3140 }
3141
3142 return fUTCdata;
3143}
3144
3146{
3154
3155 return fUTCdata;
3156}
3157
3158void NcTimestamp::Add(Int_t d,Int_t s,Int_t ns,Int_t ps)
3159{
3185
3186 AddCalc(d,s,ns,ps);
3187}
3188
3189void NcTimestamp::Add(Double_t hours)
3190{
3203
3204 AddCalc(hours);
3205}
3206
3207void NcTimestamp::AddSec(Double_t seconds)
3208{
3221
3222 AddSecCalc(seconds);
3223}
3224
3225void NcTimestamp::AddCalc(Int_t d,Int_t s,Int_t ns,Int_t ps,Bool_t utcpar)
3226{
3256
3257 Int_t days=0;
3258 Int_t secs=0;
3259 Int_t nsec=0;
3260 // Use Get functions to ensure updated Julian parameters.
3261 GetMJD(days,secs,nsec);
3262 Int_t psec=GetPs();
3263
3264 psec+=ps%1000;
3265 nsec+=ps/1000;
3266 while (psec<0)
3267 {
3268 nsec-=1;
3269 psec+=1000;
3270 }
3271 while (psec>999)
3272 {
3273 nsec+=1;
3274 psec-=1000;
3275 }
3276
3277 nsec+=ns%1000000000;
3278 secs+=ns/1000000000;
3279 while (nsec<0)
3280 {
3281 secs-=1;
3282 nsec+=1000000000;
3283 }
3284 while (nsec>999999999)
3285 {
3286 secs+=1;
3287 nsec-=1000000000;
3288 }
3289
3290 secs+=s%(24*3600);
3291 days+=s/(24*3600);
3292 while (secs<0)
3293 {
3294 days-=1;
3295 secs+=24*3600;
3296 }
3297 while (secs>=24*3600)
3298 {
3299 days+=1;
3300 secs-=24*3600;
3301 }
3302
3303 days+=d;
3304
3305 TString utc="N";
3306 if (fUtc==1) utc="M";
3307 if (fUtc==-1) utc="A";
3308 if (fUtc==-2) utc="U";
3309 if (fUtc==-3) utc="U";
3310 Int_t leap=fLeap;
3311 Double_t dut=fDut;
3312 SetMJD(days,secs,nsec,psec);
3313
3314 if (utcpar) SetUTCparameters(utc,leap,dut);
3315}
3316
3317void NcTimestamp::AddCalc(Double_t hours,Bool_t utcpar)
3318{
3337
3338 Int_t d,s,ns,ps;
3339 Double_t h=fabs(hours);
3340 d=int(h/24.);
3341 h-=double(d)*24.;
3342 h*=3600.;
3343 s=int(h);
3344 h-=double(s);
3345 h*=1.e9;
3346 ns=int(h);
3347 h-=double(ns);
3348 ps=int(h*1000.);
3349 if (hours>0) AddCalc(d,s,ns,ps,utcpar);
3350 if (hours<0) AddCalc(-d,-s,-ns,-ps,utcpar);
3351}
3352
3353void NcTimestamp::AddSecCalc(Double_t seconds,Bool_t utcpar)
3354{
3373
3374 Int_t s,ns,ps;
3375 Double_t a=fabs(seconds);
3376 s=int(a);
3377 a-=double(s);
3378 a*=1.e9;
3379 ns=int(a);
3380 a-=double(ns);
3381 ps=int(a*1000.);
3382 if (seconds>0) AddCalc(0,s,ns,ps,utcpar);
3383 if (seconds<0) AddCalc(0,-s,-ns,-ps,utcpar);
3384}
3385
3386Int_t NcTimestamp::GetDifference(NcTimestamp* t,Int_t& d,Int_t& s,Int_t& ns,Int_t& ps,TString type)
3387{
3434
3435 d=0;
3436 s=0;
3437 ns=0;
3438 ps=0;
3439
3440 if (!t || (type!="UT" && type!="TAI")) return 0;
3441
3442 Int_t tUtc=t->fUtc;
3443 if (type=="TAI" && (!fUtc || !tUtc || fUtc==-3 || tUtc==-3)) return 0;
3444
3445 Int_t d1=0;
3446 Int_t s1=0;
3447 Int_t ns1=0;
3448 Int_t ps1=0;
3449
3450 Int_t d2=0;
3451 Int_t s2=0;
3452 Int_t ns2=0;
3453 Int_t ps2=0;
3454
3455 NcTimestamp ts1(*t);
3456 NcTimestamp ts2(*this);
3457
3458 // Check for a mixed use of UT1 and UTC
3459 if (type=="UT")
3460 {
3461 Double_t dut=0;
3462 if (!fUtc && tUtc) // This timestamp is in UTC and the other in UT1
3463 {
3464 dut=t->fDut;
3465 ts1.AddSec(-dut);
3466 }
3467 if (fUtc && !tUtc) // This timestamp is in UT1 and the other in UTC
3468 {
3469 ts2.AddSec(-fDut);
3470 }
3471 }
3472
3473 // Use Get functions to ensure updated Julian and TAI parameters.
3474 if (type=="UT")
3475 {
3476 ts1.GetMJD(d1,s1,ns1);
3477 ps1=ts1.GetPs();
3478 ts2.GetMJD(d2,s2,ns2);
3479 ps2=ts2.GetPs();
3480 }
3481 if (type=="TAI")
3482 {
3483 t->GetTAI(d1,s1,ns1,ps1);
3484 GetTAI(d2,s2,ns2,ps2);
3485 }
3486
3487 d=d1-d2;
3488 s=s1-s2;
3489 ns=ns1-ns2;
3490 ps=ps1-ps2;
3491
3492 if (!d && !s && !ns && !ps) return 0;
3493
3494 Int_t sign=0;
3495
3496 if (d>0) sign=1;
3497 if (d<0) sign=-1;
3498
3499 if (!sign && s>0) sign=1;
3500 if (!sign && s<0) sign=-1;
3501
3502 if (!sign && ns>0) sign=1;
3503 if (!sign && ns<0) sign=-1;
3504
3505 if (!sign && ps>0) sign=1;
3506 if (!sign && ps<0) sign=-1;
3507
3508 // In case the input stamp was earlier, take the reverse difference
3509 // to simplify the algebra.
3510 if (sign<0)
3511 {
3512 d=-d;
3513 s=-s;
3514 ns=-ns;
3515 ps=-ps;
3516 }
3517
3518 // Here we always have a positive time difference
3519 // and can now unambiguously correct for other negative values.
3520 if (ps<0)
3521 {
3522 ns-=1;
3523 ps+=1000;
3524 }
3525
3526 if (ns<0)
3527 {
3528 s-=1;
3529 ns+=1000000000;
3530 }
3531
3532 if (s<0)
3533 {
3534 d-=1;
3535 s+=24*3600;
3536 }
3537
3538 return sign;
3539}
3540
3541Int_t NcTimestamp::GetDifference(NcTimestamp& t,Int_t& d,Int_t& s,Int_t& ns,Int_t& ps,TString type)
3542{
3589
3590 return GetDifference(&t,d,s,ns,ps,type);
3591}
3592
3593Double_t NcTimestamp::GetDifference(NcTimestamp* t,TString u,Int_t mode,TString type)
3594{
3661
3662 if (!t || mode<1 || mode>3 || (type!="UT" && type!="TAI")) return 0;
3663
3664 if (u!="d" && u!="s" && u!="ns" && u!="ps") return 0;
3665
3666
3667 Int_t tUtc=t->fUtc;
3668 if (type=="TAI" && (!fUtc || !tUtc || fUtc==-3 || tUtc==-3)) return 0;
3669
3670 Double_t dt=0;
3671
3672 Int_t d1=0;
3673 Int_t s1=0;
3674 Int_t ns1=0;
3675 Int_t ps1=0;
3676
3677 Int_t d2=0;
3678 Int_t s2=0;
3679 Int_t ns2=0;
3680 Int_t ps2=0;
3681
3682 NcTimestamp ts1(*t);
3683 NcTimestamp ts2(*this);
3684
3685 // Check for a mixed use of UT1 and UTC
3686 if (type=="UT")
3687 {
3688 Double_t dut=0;
3689 if (!fUtc && tUtc) // This timestamp is in UTC and the other in UT1
3690 {
3691 dut=t->fDut;
3692 ts1.AddSec(-dut);
3693 }
3694 if (fUtc && !tUtc) // This timestamp is in UT1 and the other in UTC
3695 {
3696 ts2.AddSec(-fDut);
3697 }
3698 }
3699
3700 // Use Get functions to ensure updated Julian and TAI parameters.
3701 if (type=="UT")
3702 {
3703 ts1.GetMJD(d1,s1,ns1);
3704 ps1=ts1.GetPs();
3705 ts2.GetMJD(d2,s2,ns2);
3706 ps2=ts2.GetPs();
3707 }
3708 if (type=="TAI")
3709 {
3710 t->GetTAI(d1,s1,ns1,ps1);
3711 GetTAI(d2,s2,ns2,ps2);
3712 }
3713
3714 Long_t dd=d1-d2;
3715 Long_t ds=s1-s2;
3716 Long_t dns=ns1-ns2;
3717 Long_t dps=ps1-ps2;
3718
3719 // Time difference for the specified units only
3720 if (mode==3)
3721 {
3722 if (u=="d") dt=dd;
3723 if (u=="s") dt=ds;
3724 if (u=="ns") dt=dns;
3725 if (u=="ps") dt=dps;
3726 return dt;
3727 }
3728
3729 // Suppress elapsed time for the larger units than specified
3730 if (mode==2)
3731 {
3732 if (u=="s") dd=0;
3733 if (u=="ns")
3734 {
3735 dd=0;
3736 ds=0;
3737 }
3738 if (u=="ps")
3739 {
3740 dd=0;
3741 ds=0;
3742 dns=0;
3743 }
3744 }
3745
3746 // Compute the time difference as requested
3747 if (u=="s" || u=="d")
3748 {
3749 // The time difference in (fractional) seconds
3750 dt=double(dd*24*3600+ds)+(double(dns)*1e-9)+(double(dps)*1e-12);
3751 if (u=="d") dt=dt/double(24*3600);
3752 }
3753 if (u=="ns") dt=(double(dd*24*3600+ds)*1e9)+double(dns)+(double(dps)*1e-3);
3754 if (u=="ps") dt=(double(dd*24*3600+ds)*1e12)+(double(dns)*1e3)+double(dps);
3755
3756 return dt;
3757}
3758
3759Double_t NcTimestamp::GetDifference(NcTimestamp& t,TString u,Int_t mode,TString type)
3760{
3827
3828 return GetDifference(&t,u,mode,type);
3829}
3830
3831void 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)
3832{
3909
3910 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)
3911 {
3912 cout << " *NcTimestamp::SetUT* Incompatible argument(s) Day=" << d << " Month=" << m << " Year=" << y
3913 << " hour=" << hh << " min=" << mm << " sec=" << ss << " ns=" << ns << " ps=" << ps << endl;
3914 cout << " ==> TAI related time recording is disabled and JD=0 has been set." << endl;
3915 SetJD(0,"N");
3916 return;
3917 }
3918
3919 Int_t day=GetDayOfYear(d,m,y);
3920 Int_t secs=hh*3600+mm*60+ss;
3921 SetUT(y,day-1,secs,ns,ps,utc,leap,dut);
3922}
3923
3924void 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)
3925{
3989
3990 Int_t ss=int(s);
3991 s-=double(ss);
3992 Int_t ns=s*1.e9;
3993 s-=double(ns)*1.e-9;
3994 Int_t ps=s*1.e12;
3995 SetUT(y,m,d,hh,mm,ss,ns,ps,utc,leap,dut);
3996}
3997
3998void NcTimestamp::SetUT(Int_t y,Int_t m,Int_t d,TString time,TString utc,Int_t leap,Double_t dut)
3999{
4061
4062 Long64_t iword=0;
4063 Int_t hh=0;
4064 Int_t mm=0;
4065 Int_t ss=0;
4066 Int_t ns=0;
4067 Int_t ps=0;
4068 time.ReplaceAll(":","");
4069
4070 // Unpack the hhmmss integer part
4071 iword=time.Atoll();
4072 hh=iword/10000;
4073 iword=iword%10000;
4074 mm=iword/100;
4075 iword=iword%100;
4076 ss=iword;
4077
4078 // Unpack the fractional part in ns and ps
4079 time.Remove(0,7); // Remove the integer part, including the decimal "."
4080 Int_t length=time.Length();
4081 time.Append('0',12-length); // Increase the string to represent the integer number of ns
4082 iword=time.Atoll();
4083 ns=iword/1000;
4084 ps=iword%1000;
4085 SetUT(y,m,d,hh,mm,ss,ns,ps,utc,leap,dut);
4086}
4087
4088void NcTimestamp::SetUT(TString date,TString time,Int_t mode,TString utc,Int_t leap,Double_t dut)
4089{
4155
4156 Int_t iword=0;
4157 Int_t utdate=0;
4158 Int_t year=0;
4159 Int_t month=0;
4160 Int_t day=0;
4161 TString datex=date;
4162 datex.ReplaceAll("-","");
4163 datex.ReplaceAll("/","");
4164 utdate=datex.Atoi();
4165 iword=utdate;
4166 if (mode==0)
4167 {
4168 day=iword/1000000;
4169 iword=iword%1000000;
4170 month=iword/10000;
4171 iword=iword%10000;
4172 year=iword;
4173 }
4174 if (mode==1)
4175 {
4176 year=iword/10000;
4177 iword=iword%10000;
4178 month=iword/100;
4179 iword=iword%100;
4180 day=iword;
4181 }
4182 if (mode==2)
4183 {
4184 month=iword/1000000;
4185 iword=iword%1000000;
4186 day=iword/10000;
4187 iword=iword%10000;
4188 year=iword;
4189 }
4190 if (mode==3)
4191 {
4192 year=iword/10000;
4193 iword=iword%10000;
4194 day=iword/100;
4195 iword=iword%100;
4196 month=iword;
4197 }
4198
4199 if (day<1 || day>31 || month<1 || month>12)
4200 {
4201 cout << " *NcTimestamp::SetUT* Incompatible argument(s) Date: " << date << " Time: " << time << " mode: " << mode << endl;
4202 cout << " ==> TAI related time recording is disabled and JD=0 has been set." << endl;
4203 SetJD(0,"N");
4204 }
4205 else
4206 {
4207 SetUT(year,month,day,time,utc,leap,dut);
4208 }
4209}
4210
4211void 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)
4212{
4294
4295 Double_t jd=GetJD(y,1,1,0,0,0,0);
4296 SetJD(jd);
4297
4298 Int_t mjd,sec,nsec;
4299 GetMJD(mjd,sec,nsec);
4300 SetMJD(mjd,0,0,0);
4301 SetUTCparameters(utc,leap,dut); // Update the UTC parameters and corresonding TAI time recording
4302 Add(d,s,ns,ps);
4303
4304 // Determine UT1 using dut=UT1-UTC if UTC was provided as input
4305 if (utc!="U") AddSec(fDut);
4306}
4307
4308void NcTimestamp::GetUT(Int_t& hh,Int_t& mm,Int_t& ss,Int_t& ns,Int_t& ps)
4309{
4317
4318 Int_t mjd,sec,nsec,psec;
4319
4320 GetMJD(mjd,sec,nsec);
4321 psec=GetPs();
4322
4323 hh=sec/3600;
4324 sec=sec%3600;
4325 mm=sec/60;
4326 ss=sec%60;
4327 ns=nsec;
4328 ps=psec;
4329}
4330
4332{
4340
4341 Int_t hh,mm,ss,ns,ps;
4342
4343 GetUT(hh,mm,ss,ns,ps);
4344
4345 Double_t ut=Convert(hh,mm,ss,ns,ps);
4346
4347 return ut;
4348}
4349
4350void NcTimestamp::GetGMST(Int_t& hh,Int_t& mm,Int_t& ss,Int_t& ns,Int_t& ps)
4351{
4361
4362 Int_t mjd,sec,nsec,psec;
4363
4364 // The current UT based timestamp data
4365 GetMJD(mjd,sec,nsec);
4366 psec=fJps;
4367
4368 // The basis for the daily corrections in units of Julian centuries w.r.t. J2000.
4369 // Note : Epoch J2000 starts at 01-jan-2000 12:00:00 UT.
4370 Double_t tau=(GetJD()-2451545.)/36525.;
4371
4372 // Syncronise sidereal time with current timestamp
4373 NcTimestamp sid;
4374 sid.SetMJD(mjd,sec,nsec,psec);
4375
4376 // Add offset for GMST start value defined as 06:41:50.54841 at 01-jan 00:00:00 UT
4377 sec=6*3600+41*60+50;
4378 nsec=548410000;
4379 psec=0;
4380 sid.Add(0,sec,nsec,psec);
4381
4382 // Daily correction for precession and polar motion
4383 Double_t addsec=8640184.812866*tau+0.093104*pow(tau,2)-6.2e-6*pow(tau,3);
4384 sec=int(addsec);
4385 addsec-=double(sec);
4386 nsec=int(addsec*1.e9);
4387 addsec-=double(nsec)*1.e-9;
4388 psec=int(addsec*1.e12);
4389 sid.Add(0,sec,nsec,psec);
4390
4391 sid.GetMJD(mjd,sec,nsec);
4392 psec=sid.GetPs();
4393
4394 hh=sec/3600;
4395 sec=sec%3600;
4396 mm=sec/60;
4397 ss=sec%60;
4398 ns=nsec;
4399 ps=psec;
4400}
4401
4403{
4412
4413 Int_t hh,mm,ss,ns,ps;
4414
4415 GetGMST(hh,mm,ss,ns,ps);
4416
4417 Double_t gst=Convert(hh,mm,ss,ns,ps);
4418
4419 return gst;
4420}
4421
4423{
4443
4444 Double_t da=Almanac();
4445
4446 // Convert to fractional hours
4447 da/=3600.;
4448
4449 Double_t gast=GetGMST()+da;
4450
4451 while (gast<0)
4452 {
4453 gast+=24.;
4454 }
4455 while (gast>24.)
4456 {
4457 gast-=24.;
4458 }
4459
4460 return gast;
4461}
4462
4463Double_t NcTimestamp::GetLT(Double_t offset)
4464{
4477
4478 // Current UT time in fractional hours
4479 Double_t h=GetUT();
4480
4481 h+=offset;
4482
4483 while (h<0)
4484 {
4485 h+=24.;
4486 }
4487 while (h>24)
4488 {
4489 h-=24.;
4490 }
4491
4492 return h;
4493}
4494
4495Double_t NcTimestamp::GetLAT(Double_t offset)
4496{
4516
4517 // Current UT time in fractional hours
4518 Double_t h=GetUT();
4519
4520 // Equation of Time
4521 Double_t eot; // LAT-LMT
4522 Almanac(0,0,0,0,"Sun",0,0,0,&eot,10);
4523 eot/=3600.; // Convert to fractional hours
4524
4525 h+=offset+eot;
4526
4527 while (h<0)
4528 {
4529 h+=24.;
4530 }
4531 while (h>24)
4532 {
4533 h-=24.;
4534 }
4535
4536 return h;
4537}
4538
4539Double_t NcTimestamp::GetLMST(Double_t offset)
4540{
4553
4554 // Current GMST time in fractional hours
4555 Double_t h=GetGMST();
4556
4557 h+=offset;
4558
4559 while (h<0)
4560 {
4561 h+=24.;
4562 }
4563 while (h>24)
4564 {
4565 h-=24.;
4566 }
4567
4568 return h;
4569}
4570
4571Double_t NcTimestamp::GetLAST(Double_t offset)
4572{
4585
4586 // Current GAST time in fractional hours
4587 Double_t h=GetGAST();
4588
4589 h+=offset;
4590
4591 while (h<0)
4592 {
4593 h+=24.;
4594 }
4595 while (h>24)
4596 {
4597 h-=24.;
4598 }
4599
4600 return h;
4601}
4602
4603void 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)
4604{
4669
4670 SetUT(y,m,d,hh,mm,ss,ns,ps,utc,leap,dut);
4671 Add(-dt);
4672}
4673
4674void 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)
4675{
4732
4733 SetUT(y,m,d,hh,mm,s,utc,leap,dut);
4734 Add(-dt);
4735}
4736
4737void NcTimestamp::SetLT(Double_t dt,Int_t y,Int_t m,Int_t d,TString time,TString utc,Int_t leap,Double_t dut)
4738{
4793
4794 SetUT(y,m,d,time,utc,leap,dut);
4795 Add(-dt);
4796}
4797
4798void NcTimestamp::SetLT(Double_t dt,TString date,TString time,Int_t mode,TString utc,Int_t leap,Double_t dut)
4799{
4856
4857 SetUT(date,time,mode,utc,leap,dut);
4858 Add(-dt);
4859}
4860
4861void 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)
4862{
4931
4932 SetUT(y,d,s,ns,ps,utc,leap,dut);
4933 Add(-dt);
4934}
4935
4936
4936Double_t NcTimestamp::GetJD(Double_t e,TString mode) const
4937{
4949
4950 Double_t jd=0;
4951
4952 if (mode=="J" || mode=="j") jd=(e-2000.0)*365.25+2451545.0;
4953
4954 if (mode=="B" || mode=="b") jd=(e-1900.0)*365.242198781+2415020.31352;
4955
4956 return jd;
4957}
4958
4959Double_t NcTimestamp::GetMJD(Double_t e,TString mode) const
4960{
4972
4973 Double_t mjd=GetJD(e,mode)-2400000.5;
4974
4975 return mjd;
4976}
4977
4978Double_t NcTimestamp::GetTJD(Double_t e,TString mode) const
4979{
4991
4992 Double_t tjd=GetJD(e,mode)-2440000.5;
4993
4994 return tjd;
4995}
4996
4997Double_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)
4998{
5107
5108 Double_t pi=acos(-1.);
5109
5110 Double_t td; // Time difference in fractional Julian days w.r.t. the start of J2000.
5111 Double_t tc; // Time difference in fractional Julian centuries w.r.t. the start of J2000.
5112 Double_t tm; // Time difference in fractional Julian millennia w.r.t. the start of J2000.
5113 const Int_t nvals=11;
5114 Double_t val[nvals]; // Array to hold the additional (orbital) parameters
5115
5116 // Initialize the solar system body related values
5117 if (el) *el=720;
5118 if (eb) *eb=720;
5119 if (dr) *dr=-1;
5120 for (Int_t i=0; i<nvals; i++)
5121 {
5122 val[i]=720;
5123 }
5124 val[0]=-1; // Semi major axis of the orbit
5125 val[1]=-1; // Eccentricity of the orbit
5126 val[10]=0; // Equation of Time, this will always be calculated correctly if requested
5127
5128 // Initialize the requested additional observable value
5129 if (value)
5130 {
5131 *value=0;
5132 if (j>=0 && j<nvals) *value=val[j];
5133 }
5134
5135 td=GetJD()-2451545.0;
5136 tc=td/36525.;
5137 tm=tc/10.;
5138
5139 // Fundamental solar system variables (in arcseconds) w.r.t. the J2000.0 equinox.
5140 // The expressions are taken from the USNO circular 179.
5141 // epsilon : Mean obliquity of the ecliptic
5142 // l : Mean anomaly of the Moon
5143 // lp : Mean anomaly of the Sun
5144 // f : Mean argument of latitude of the moon
5145 // d : Mean elongation of the Moon from the Sun
5146 // om : Mean longitude of the Moon's mean ascending node
5147 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);
5148 Double_t l=485868.249036+1717915923.2178*tc+31.8792*pow(tc,2)+0.051635*pow(tc,3)-0.00024470*pow(tc,4);
5149 Double_t lp=1287104.79305+129596581.0481*tc-0.5532*pow(tc,2)+0.000136*pow(tc,3)-0.00001149*pow(tc,4);
5150 Double_t f=335779.526232+1739527262.8478*tc-12.7512*pow(tc,2)-0.001037*pow(tc,3)+0.00000417*pow(tc,4);
5151 Double_t d=1072260.70369+1602961601.2090*tc-6.3706*pow(tc,2)+0.006593*pow(tc,3)-0.00003169*pow(tc,4);
5152 Double_t om=450160.398036-6962890.5431*tc+7.4722*pow(tc,2)+0.007702*pow(tc,3)-0.00005939*pow(tc,4);
5153
5154 // General precession in longitude (in arcseconds) w.r.t. J2000.0
5155 // according to Jean Meeus Ch.21 (page 136)
5156 Double_t prec=5029.0966*tc+1.11113*pow(tc,2)-0.000006*pow(tc,3);
5157
5158 if (eps) *eps=epsilon;
5159 if (dl) *dl=prec;
5160
5161 // Convert to radians for use with goniometric functions
5162 Double_t fac=pi/(180.*3600.);
5163 epsilon*=fac;
5164 l*=fac;
5165 lp*=fac;
5166 f*=fac;
5167 d*=fac;
5168 om*=fac;
5169
5170 //The IAU 2000A nutation series expansion.
5171 Double_t phi[28]={om,2.*(f-d+om),2.*(f+om),2.*om,lp,lp+2.*(f-d+om),l,
5172 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,
5173 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),
5174 2.*(d-l),2.*(l+d+om),l+2.*(f-d+om),2.*f+om-l,2.*l,2.*f,lp+om};
5175 Double_t s[28]={-17.2064161,-1.3170907,-0.2276413, 0.2074554, 0.1475877,-0.0516821, 0.0711159,
5176 -0.0387298,-0.0301461, 0.0215829, 0.0128227, 0.0123457, 0.0156994, 0.0063110,
5177 -0.0057976,-0.0059641,-0.0051613, 0.0045893, 0.0063384,-0.0038571, 0.0032481,
5178 -0.0047722,-0.0031046, 0.0028593, 0.0020441, 0.0029243, 0.0025887,-0.0014053};
5179 Double_t sd[28]={-0.0174666,-0.0001675,-0.0000234, 0.0000207,-0.0003633, 0.0001226, 0.0000073,
5180 -0.0000367,-0.0000036,-0.0000494, 0.0000137, 0.0000011, 0.0000010, 0.0000063,
5181 -0.0000063,-0.0000011,-0.0000042, 0.0000050, 0.0000011,-0.0000001, 0.0000000,
5182 0.0000000,-0.0000001, 0.0000000, 0.0000021, 0.0000000, 0.0000000,-0.0000025};
5183 Double_t cp[28]={ 0.0033386,-0.0013696, 0.0002796,-0.0000698, 0.0011817,-0.0000524,-0.0000872,
5184 0.0000380, 0.0000816, 0.0000111, 0.0000181, 0.0000019,-0.0000168, 0.0000027,
5185 -0.0000189, 0.0000149, 0.0000129, 0.0000031,-0.0000150, 0.0000158, 0.0000000,
5186 -0.0000018, 0.0000131,-0.0000001, 0.0000010,-0.0000074,-0.0000066, 0.0000079};
5187 Double_t c[28]= { 9.2052331, 0.5730336, 0.0978459,-0.0897492, 0.0073871, 0.0224386,-0.0006750,
5188 0.0200728, 0.0129025,-0.0095929,-0.0068982,-0.0053311,-0.0001235,-0.0033228,
5189 0.0031429, 0.0025543, 0.0026366,-0.0024236,-0.0001220, 0.0016452,-0.0013870,
5190 0.0000477, 0.0013238,-0.0012338,-0.0010758,-0.0000609,-0.0000550, 0.0008551};
5191 Double_t cd[28]={ 0.0009086,-0.0003015,-0.0000485, 0.0000470,-0.0000184,-0.0000677, 0.0000000,
5192 0.0000018,-0.0000063, 0.0000299,-0.0000009, 0.0000032, 0.0000000, 0.0000000,
5193 0.0000000,-0.0000011, 0.0000000,-0.0000010, 0.0000000,-0.0000011, 0.0000000,
5194 0.0000000,-0.0000011, 0.0000010, 0.0000000, 0.0000000, 0.0000000,-0.0000002};
5195 Double_t sp[28]={ 0.0015377,-0.0004587, 0.0001374,-0.0000291,-0.0001924,-0.0000174, 0.0000358,
5196 0.0000318, 0.0000367, 0.0000132, 0.0000039,-0.0000004, 0.0000082,-0.0000009,
5197 -0.0000075, 0.0000066, 0.0000078, 0.0000020, 0.0000029, 0.0000068, 0.0000000,
5198 -0.0000025, 0.0000059,-0.0000003,-0.0000003, 0.0000013, 0.0000011,-0.0000045};
5199
5200 Double_t dp=0,de=0,da=0;
5201 for (Int_t i=0; i<28; i++)
5202 {
5203 dp+=(s[i]+sd[i]*tc)*sin(phi[i])+cp[i]*cos(phi[i]);
5204 de+=(c[i]+cd[i]*tc)*cos(phi[i])+sp[i]*sin(phi[i]);
5205 }
5206
5207 da=dp*cos(epsilon)+0.00264096*sin(om)+0.00006352*sin(2.*om)
5208 +0.00001175*sin(2.*f-2.*d+3.*om)+0.00001121*sin(2.*f-2.*d+om)
5209 -0.00000455*sin(2.*f-2.*d+2.*om)+0.00000202*sin(2.*f+3.*om)+0.00000198*sin(2.*f+om)
5210 -0.00000172*sin(3.*om)-0.00000087*tc*sin(om);
5211
5212 if (dpsi) *dpsi=dp;
5213 if (deps) *deps=de;
5214
5215 // Convert to seconds
5216 da/=15.;
5217
5219 // Determination of the Equation of Time via a recursive invokation //
5221 if (j==10)
5222 {
5223 Double_t xdpsi,xdeps,xeps,xlambda,xbeta;
5224 Almanac(&xdpsi,&xdeps,&xeps,0,"Sun",&xlambda,&xbeta);
5225
5226 // Convert from arcsec to degrees
5227 xdpsi/=3600.;
5228 xdeps/=3600.;
5229 xeps/=3600.;
5230
5231 // Correct for nutation to get the true values
5232 xeps+=xdeps;
5233 xlambda+=xdpsi;
5234
5235 while (xlambda<0) { xlambda+=360.; }
5236 while (xlambda>360) { xlambda-=360.; }
5237
5238 // Convert to radians for gonio
5239 Double_t epsr=xeps*pi/180.;
5240 Double_t lambdar=xlambda*pi/180.;
5241 Double_t betar=xbeta*pi/180.;
5242
5243 // True Right Ascension of the Sun (see Ch.13 p.93 of J. Meeus)
5244 Double_t x=sin(lambdar)*cos(epsr)-tan(betar)*sin(epsr);
5245 Double_t y=cos(lambdar);
5246 Double_t alpha=0;
5247 if (x || y) alpha=atan2(x,y)*180./pi;
5248
5249 while (alpha<0) { alpha+=360.; }
5250 while (alpha>360) { alpha-=360.; }
5251
5252 // Mean longitude of the Sun (see Ch.28 p.183 of J. Meeus)
5253 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.;
5254
5255 while (L0<0) { L0+=360.; }
5256 while (L0>360) { L0-=360.; }
5257
5258 // Determine the Equation of Time in degrees (see Ch.28 p.183 of J. Meeus)
5259 Double_t eot=L0-0.0057183-alpha+xdpsi*cos(xeps*pi/180.);
5260
5261 // The Equation of Time never exceeds 20 minutes (= 5 degrees)
5262 while (eot<-5) { eot+=360.; }
5263 while (eot>5) { eot-=360.; }
5264
5265 // Convert the Equation of Time from degrees to seconds
5266 eot*=240.;
5267
5268 val[10]=eot;
5269 if (value) *value=eot;
5270 }
5271
5273 // Determination of the mean orbital elements and true ecliptic coordinates //
5274 // of a requested solar system body, for the mean equinox of the date. //
5276
5277 // The definitions and expressions are the ones used in the book of Jean Meeus
5278 // "Astronomical Algorithms" (2nd edition of August 2009), esp. chapters 31-33.
5279
5280 // The various observables are :
5281 // a : Semi major axis (in AU) of the orbit
5282 // e : Eccentricity of the orbit
5283 // inc : Inclination (in degrees) of the orbit with the ecliptic
5284 // omega : Mean ecliptic longitude (in degrees) of the ascending node
5285 // lp : Mean orbital longitude (in degrees) of the perihelion
5286 // l : Mean orbital longitude (in degrees) of the body
5287 // omega2 : Orbital argument (in degrees) of the perihelion
5288 // m : Mean orbital anomaly (in degrees) of the body
5289 // ec : Equation of the center (in degrees)
5290 // nu : True anomaly (in degrees) of the body
5291 // ltrue : Heliocentric longitude of the body
5292 // btrue : Heliocentric latitude of the body
5293 // r : Distance between the body and the sun
5294 // lambda : Geocentric ecliptic longitude
5295 // beta : Geocentric ecliptic latitude
5296
5297 Double_t a=0;
5298 Double_t e=0;
5299 Double_t inc=0;
5300 Double_t omega=0;
5301 Double_t omega2=0;
5302 Double_t m=0;
5303 Double_t ec=0;
5304 Double_t nu=0;
5305 Double_t ltrue=0;
5306 Double_t btrue=0;
5307 Double_t r=0;
5308 Double_t lambda=0;
5309 Double_t beta=0;
5310
5311 // Polynomial coefficients for a (in AU)of the 8 major planets
5312 Double_t aa0[8]={0.387098310,0.723329820,1.000001018,1.523679342,5.202603209,9.554909192,19.218446062,30.110386869};
5313 Double_t aa1[8]={0,0,0,0,0.0000001913,-0.0000021390,-0.0000000372,-0.0000001663};
5314 Double_t aa2[8]={0,0,0,0,0,0.000000004,0.00000000098,0.00000000069};
5315 Double_t aa3[8]={0,0,0,0,0,0,0,0};
5316 // Polynomial coefficients for e of the 8 major planets
5317 Double_t ea0[8]={0.20563175,0.00677192,0.01670863,0.09340065,0.04849793,0.05554814,0.04638122,0.00945575};
5318 Double_t ea1[8]={0.000020407,-0.000047765,-0.000042037,0.000090484,0.000163225,-0.000346641,-0.000027293,0.000006033};
5319 Double_t ea2[8]={-0.0000000283,0.0000000981,-0.0000001267,-0.0000000806,-0.0000004714,-0.0000006436,0.0000000789,0};
5320 Double_t ea3[8]={-0.00000000018,0.00000000046,0.00000000014,-0.00000000025,-0.00000000201,0.00000000340,0.00000000024,-0.00000000005};
5321 // Polynomial coefficients for inc (in degrees) of the 8 major planets
5322 Double_t ia0[8]={7.004986,3.394662,0,1.849726,1.303267,2.488879,0.773197,1.769953};
5323 Double_t ia1[8]={0.0018215,0.0010037,0,-0.0006011,-0.0054965,-0.0037362,0.0007744,-0.0093082};
5324 Double_t ia2[8]={-0.00001810,-0.00000088,0,0.00001276,0.00000466,-0.00001519,0.00003749,-0.00000708};
5325 Double_t ia3[8]={0.000000056,-0.000000007,0,-0.000000007,-0.000000002,0.000000087,-0.000000092,0.000000027};
5326 // Polynomial coefficients for omega (in degrees) of the 8 major planets
5327 Double_t oa0[8]={48.330893,76.679920,0,49.558093,100.464407,113.665503,74.005957,131.784057};
5328 Double_t oa1[8]={1.1861883,0.9011206,0,0.7720959,1.0209774,0.8770880,0.5211278,1.1022039};
5329 Double_t oa2[8]={0.00017542,0.00040618,0,0.00001557,0.00040315,-0.00012176,0.00133947,0.00025952};
5330 Double_t oa3[8]={0.000000215,-0.000000093,0,0.000002267,0.000000404,-0.000002249,0.000018484,-0.000000637};
5331 // Polynomial coefficients for lp (in degrees) of the 8 major planets
5332 Double_t pa0[8]={77.456119,131.563703,102.937348,336.060234,14.331207,93.057237,173.005291,48.120276};
5333 Double_t pa1[8]={1.5564776,1.4022288,1.7195366,1.8410449,1.6126352,1.9637613,1.4863790,1.4262957};
5334 Double_t pa2[8]={0.00029544,-0.00107618,0.00045688,0.00013477,0.00103042,0.00083753,0.00021406,0.00038434};
5335 Double_t pa3[8]={0.000000009,-0.000005678,-0.000000018,0.000000536,-0.000004464,0.000004928,0.000000434,0.000000020};
5336 // Polynomial coefficients for l (in degrees) of the 8 major planets
5337 Double_t la0[8]={252.250906,181.979801,100.466457,355.433000,34.351519,50.077444,314.055005,304.348665};
5338 Double_t la1[8]={149474.0722491,58519.2130302,36000.7698278,19141.6964471,3036.3027748,1223.5110686,429.8640561,219.8833092};
5339 Double_t la2[8]={0.00030350,0.00031014,0.00030322,0.00031052,0.00022330,0.00051908,0.00030390,0.00030882};
5340 Double_t la3[8]={0.000000018,0.000000015,0.000000020,0.000000016,0.000000037,-0.000000030,0.000000026,0.000000018};
5341
5342 TString names[10]={"Mercury","Venus","Earth","Mars","Jupiter","Saturn","Uranus","Neptune","Sun","Moon"};
5343
5344 Int_t k=-1;
5345 Int_t geo=1;
5346 for (Int_t jbody=0; jbody<10; jbody++)
5347 {
5348 if (name.Contains("*")) geo=0;
5349 if (name.Contains(names[jbody].Data()))
5350 {
5351 k=jbody;
5352 break;
5353 }
5354 }
5355
5356 if (k<0) return da; // Non-supported solar system body
5357
5358 if (!geo && k==8) return da; // Request for heliocentric data of the Sun itself
5359
5360 if (geo && k==2) return da; // Request for geocentric data of the Earth itself
5361
5362 // In case geocentric data for the Sun are requested, the heliocentric data
5363 // of the Earth are used to construct the corresponding data for the Sun.
5364 Int_t sun=0;
5365 if (k==8)
5366 {
5367 k=2;
5368 sun=1;
5369 }
5370
5371 // In case heliocentric data for the Moon are requested, the corresponding data
5372 // for the Earth are provided in view of negligible differences within the
5373 // accuracy of the algorithms used here.
5374 Int_t moon=0;
5375 if (k==9) moon=1;
5376 if (!geo && k==9) k=2;
5377
5378 lambda=0;
5379 beta=0;
5380
5382 // Determination of the geocentric data for the Moon //
5384
5385 if (geo && k==9)
5386 {
5387 // Low-precision geocentric ecliptic coordinates (in degrees) of the Moon.
5388 // Source : Astronomical Alamanac 2012 page D22.
5389 // Maximal errors : 0.3 degr. in lambda, 0.2 degr. in beta, 0.003 degr. in plax and 0.2 R_Earth in r
5390 // A more accurate method is the series expansion given in the book of Jean Meeus.
5391 lambda=218.32+481267.881*tc
5392 +6.29*sin((135.+477198.87*tc)*pi/180.)-1.27*sin((259.3-413335.36*tc)*pi/180.)
5393 +0.66*sin((235.7+890534.22*tc)*pi/180.)+0.21*sin((269.9+954397.74*tc)*pi/180.)
5394 -0.19*sin((357.5+35999.05*tc)*pi/180.)-0.11*sin((186.5+966404.03*tc)*pi/180.);
5395 beta=5.13*sin((93.3+483202.02*tc)*pi/180.)+0.28*sin((228.2+960400.89*tc)*pi/180.)
5396 -0.28*sin((318.3+6003.15*tc)*pi/180.)-0.17*sin((217.6-407332.21*tc)*pi/180.);
5397 Double_t plax=0.9508
5398 +0.0518*cos((135.+477198.87*tc)*pi/180.)+0.0095*cos((259.3-413335.36*tc)*pi/180.)
5399 +0.0078*cos((235.7+890534.22*tc)*pi/180.)+0.0028*cos((269.9+954397.74*tc)*pi/180.);
5400 r=1./sin(plax*pi/180.);
5401
5402 // Convert r into km using an average Earth radius of 6367.45 km
5403 r*=6367.45;
5404
5405 while (lambda<0) { lambda+=360.; }
5406 while (lambda>360) { lambda-=360.; }
5407
5408 if (el) *el=lambda;
5409 if (eb) *eb=beta;
5410 if (dr) *dr=r;
5411
5412 return da;
5413 }
5414
5416 // Determination of the heliocentric data for the requested solar system body //
5418
5419 a=0;
5420 e=0;
5421 inc=0;
5422 omega=0;
5423 l=0;
5424 lp=0;
5425
5426 a=aa0[k]+aa1[k]*tc+aa2[k]*pow(tc,2)+aa3[k]*pow(tc,3);
5427 e=ea0[k]+ea1[k]*tc+ea2[k]*pow(tc,2)+ea3[k]*pow(tc,3);
5428 inc=ia0[k]+ia1[k]*tc+ia2[k]*pow(tc,2)+ia3[k]*pow(tc,3);
5429 omega=oa0[k]+oa1[k]*tc+oa2[k]*pow(tc,2)+oa3[k]*pow(tc,3);
5430 lp=pa0[k]+pa1[k]*tc+pa2[k]*pow(tc,2)+pa3[k]*pow(tc,3);
5431 l=la0[k]+la1[k]*tc+la2[k]*pow(tc,2)+la3[k]*pow(tc,3);
5432
5433 while (omega<0) { omega+=360.; }
5434 while (omega>360) { omega-=360.; }
5435
5436 m=l-lp;
5437
5438 while (m<0) { m+=360.; }
5439 while (m>360) { m-=360.; }
5440
5441 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.)
5442 +((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.)
5443 +(1097.*pow(e,5)*sin(5.*m*pi/180.)/960.);
5444 ec*=180./pi;
5445
5446 omega2=lp-omega;
5447
5448 while (omega2<0) { omega2+=360.; }
5449 while (omega2>360) { omega2-=360.; }
5450
5451 while (lp<0) { lp+=360.; }
5452 while (lp>360) { lp-=360.; }
5453
5454 while (l<0) { l+=360.; }
5455 while (l>360) { l-=360.; }
5456
5457 nu=m+ec;
5458
5459 while (nu<0) { nu+=360.; }
5460 while (nu>360) { nu-=360.; }
5461
5462 // Store the orbital parameters in the additional values array
5463 if (!sun && !moon)
5464 {
5465 val[0]=a;
5466 val[1]=e;
5467 val[2]=inc;
5468 val[3]=omega;
5469 val[4]=lp;
5470 val[5]=l;
5471 val[6]=omega2;
5472 val[7]=m;
5473 val[8]=ec;
5474 val[9]=nu;
5475 }
5476
5477 // Make requested value available
5478 if (value)
5479 {
5480 *value=0;
5481 if (j>=0 && j<nvals) *value=val[j];
5482 }
5483
5484 r=a*(1.-e*e)/(1.+e*cos(nu*pi/180.));
5485
5486 // Use sine rule to obtain the latitude in radians
5487 Double_t sinb=sin(inc*pi/180.)*sin((l-omega+ec)*pi/180.);
5488 btrue=asin(sinb);
5489
5490 ltrue=omega;
5491 // Use Neper's rule to obtain the extra term of the longitude
5492 Double_t arg=l-omega+ec;
5493 while (arg<0) { arg+=360.; }
5494 while (arg>360) { arg-=360.; }
5495 Double_t extra=0;
5496 if (cos(btrue))
5497 {
5498 Double_t cosl=cos(arg*pi/180.)/cos(btrue);
5499 extra=acos(cosl)*180./pi;
5500 if (arg>180) extra=-extra;
5501 }
5502
5503 btrue*=180./pi;
5504 ltrue+=extra;
5505
5506 // Convert heliocentric Earth data into geocentric Sun data if requested
5507 if (sun)
5508 {
5509 btrue=-btrue;
5510 ltrue+=180.;
5511 }
5512
5513 while (ltrue<0) { ltrue+=360.; }
5514 while (ltrue>360) { ltrue-=360.; }
5515
5516 if (el) *el=ltrue;
5517 if (eb) *eb=btrue;
5518 if (dr) *dr=r;
5519
5520 if (!geo || sun) return da; // Heliocentric (or geocentric Sun) coordinates were requested
5521
5523 // Convert into geocentric ecliptic coordinates //
5525
5526 // The algorithm used here is the one outlined in Ch. 33 of the book of Jean Meeus.
5527 // In view of the accuracy of the current algorithm, the effects of light-time
5528 // and aberration are not taken into account here.
5529
5530 // Determine the heliocentric coordinates of the Earth
5531 // via recursive invokation of this memberfunction
5532 Double_t l0,b0,r0;
5533 Almanac(0,0,0,0,"Earth*",&l0,&b0,&r0);
5534
5535 Double_t x=r*cos(btrue*pi/180.)*cos(ltrue*pi/180.)-r0*cos(b0*pi/180.)*cos(l0*pi/180.);
5536 Double_t y=r*cos(btrue*pi/180.)*sin(ltrue*pi/180.)-r0*cos(b0*pi/180.)*sin(l0*pi/180.);
5537 Double_t z=r*sin(btrue*pi/180.)-r0*sin(b0*pi/180.);
5538
5539 lambda=atan2(y,x)*180./pi;
5540 beta=atan2(z,sqrt(x*x+y*y))*180./pi;
5541 r=sqrt(x*x+y*y+z*z);
5542
5543 while (lambda<0) { lambda+=360.; }
5544 while (lambda>360) { lambda-=360.; }
5545
5546 if (el) *el=lambda;
5547 if (eb) *eb=beta;
5548 if (dr) *dr=r;
5549
5550 return da;
5551}
5552
5553void NcTimestamp::SetEpoch(Double_t e,TString mode,TString utc,Int_t leap,Double_t dut)
5554{
5610
5611 Double_t jd=GetJD(e,mode);
5612 SetJD(jd,utc,leap,dut);
5613}
5614
5615Double_t NcTimestamp::GetEpoch(TString mode)
5616{
5626
5627 Double_t e=0;
5628 if (mode=="B" || mode=="b") e=GetBE();
5629 if (mode=="J" || mode=="j") e=GetJE();
5630 return e;
5631}
5632
5633TString NcTimestamp::GetDayTimeString(TString mode,Int_t ndig,Double_t offset,TString* date,TString* time,Bool_t full)
5634{
5678
5679 Bool_t set=kFALSE;
5680
5681 TString sdate=mode;
5682 sdate+=" information unavailable";
5683
5684 TString stime=mode;
5685 stime+=" information unavailable";
5686
5687 TString daytime=mode;
5688 daytime+=" information unavailable";
5689
5690 TString month[12]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
5691 TString day[7]={"Mon","Tue","Wed","Thu","Fri","Sat","Sun"};
5692
5693 UInt_t y=0;
5694 UInt_t m=0;
5695 UInt_t d=0;
5696 UInt_t wd=0;
5697 Int_t hh,mm,ss,ns,ps;
5698 Double_t s=0;
5699 ULong64_t sfrac=0;
5700 Double_t gat=0;
5701 Double_t gast=0;
5702 Bool_t bdate=kFALSE;
5703
5704 Int_t mjd,mjsec,mjns;
5705 GetMJD(mjd,mjsec,mjns);
5706
5707 // Check whether UT1 is the main reference
5708 if (mode=="UT1" && fUtc) mode="UT";
5709
5710 // Check whether UTC is the main reference
5711 if (mode=="UTC" && !fUtc) mode="UT";
5712
5713 // UT related information : UT, GAT, GMST and GAST date and time
5714 if (mode=="UT" || mode=="GAT" || mode=="GMST" || mode=="GAST")
5715 {
5716 if (mjd>=40587 && (mjd<65442 || (mjd==65442 && mjsec<8047)))
5717 {
5718 GetDate(kTRUE,0,&y,&m,&d);
5719 wd=GetDayOfWeek(kTRUE,0);
5720 bdate=kTRUE;
5721 }
5722 if (mode=="UT") GetUT(hh,mm,ss,ns,ps);
5723 if (mode=="GMST") GetGMST(hh,mm,ss,ns,ps);
5724 if (mode=="GAT")
5725 {
5726 // Obtain GAT as LAT without offset
5727 gat=GetLAT(0);
5728 Convert(gat,hh,mm,ss,ns,ps);
5729 }
5730 if (mode=="GAST")
5731 {
5732 gast=GetGAST();
5733 Convert(gast,hh,mm,ss,ns,ps);
5734 }
5735
5736 set=kTRUE;
5737 }
5738
5739 // TAI related information : TAI, UTC, GPS and TT date and time
5740 if (mode=="TAI" || mode=="UTC" || mode=="GPS" || mode=="TT")
5741 {
5742 if (fUtc && fUtc!=-3)
5743 {
5744 // A dummy timestamp is used to obtain the TAI corresponding date indicator
5745 NcTimestamp tx;
5747
5748 // Convert to the corresponding UTC, GPS or TT timestamps
5749 if (mode=="UTC") tx.AddSec(-fLeap);
5750 if (mode=="GPS") tx.AddSec(-19);
5751 if (mode=="TT") tx.AddSec(32.184);
5752
5753 Int_t tmjd,tsec,tns;
5754 tx.GetMJD(tmjd,tsec,tns);
5755
5756 if (tmjd>=40587 && (tmjd<65442 || (tmjd==65442 && tsec<8047)))
5757 {
5758 tx.GetDate(kTRUE,0,&y,&m,&d);
5759 wd=tx.GetDayOfWeek(kTRUE,0);
5760 bdate=kTRUE;
5761 }
5762 GetTAI(hh,mm,ss,ns,ps,mode);
5763
5764 set=kTRUE;
5765 }
5766 }
5767
5768 // Local time information
5769 if (mode=="LMT" || mode=="LAT" || mode=="LMST" || mode=="LAST")
5770 {
5771 // Determine the new date by including the offset
5772 NcTimestamp t2(*this);
5773 t2.Add(offset);
5774 Int_t mjd2,mjsec2,mjns2;
5775 t2.GetMJD(mjd2,mjsec2,mjns2);
5776 if (mjd2>=40587 && (mjd2<65442 || (mjd2==65442 && mjsec2<8047)))
5777 {
5778 t2.GetDate(kTRUE,0,&y,&m,&d);
5779 wd=t2.GetDayOfWeek(kTRUE,0);
5780 bdate=kTRUE;
5781 }
5782 // Determine the local time by including the offset w.r.t. the original timestamp
5783 Double_t hlt=0;
5784 if (mode=="LMT") hlt=GetLT(offset);
5785 if (mode=="LAT") hlt=GetLAT(offset);
5786 if (mode=="LMST") hlt=GetLMST(offset);
5787 if (mode=="LAST") hlt=GetLAST(offset);
5788 Convert(hlt,hh,mm,ss,ns,ps);
5789
5790 set=kTRUE;
5791 }
5792
5793 // No match found with requested date/time system
5794 if (!set)
5795 {
5796 if (date) *date=sdate;
5797 if (time) *time=stime;
5798 return daytime;
5799 }
5800
5801 // Create the date and time info string
5802 sdate="";
5803 stime="";
5804
5805 // The date string
5806 if (bdate)
5807 {
5808 if (full)
5809 {
5810 sdate.Form("%-s %02i-%-s-%-i",day[wd-1].Data(),d,month[m-1].Data(),y);
5811 }
5812 else
5813 {
5814 sdate.Form("%02i-%02i-%-i",d,m,y);
5815 }
5816 }
5817
5818 // The time string
5819 if (hh<10) stime+="0";
5820 stime+=hh;
5821 stime+=":";
5822 if (mm<10) stime+="0";
5823 stime+=mm;
5824 stime+=":";
5825 if (ss<10) stime+="0";
5826 stime+=ss;
5827 if (ndig>0)
5828 {
5829 stime+=".";
5830 s=double(ns)*1e-9+double(ps)*1e-12;
5831 s*=pow(10.,ndig);
5832 sfrac=ULong64_t(s);
5833 ULong64_t isfrac=pow(10,ndig-1);
5834 while (sfrac<isfrac)
5835 {
5836 stime+="0";
5837 isfrac/=10;
5838 }
5839 if (sfrac) stime+=sfrac;
5840 }
5841
5842 // Construct the combined date/time string
5843 daytime=sdate;
5844 daytime+=" ";
5845 daytime+=stime;
5846
5847 // Add the time system indicator
5848 if (mode=="UT")
5849 {
5850 mode="UT1";
5851 if (!fUtc) mode="UTC";
5852 }
5853 if (sdate=="") sdate="---";
5854 if (full)
5855 {
5856 sdate+=" ";
5857 sdate+=mode;
5858 stime+=" ";
5859 stime+=mode;
5860 daytime+=" ";
5861 daytime+=mode;
5862 }
5863
5864 if (date) *date=sdate;
5865 if (time) *time=stime;
5866
5867 return daytime;
5868}
5869
5871{
5880
5881 // Retrieve the current system clock time
5882 Set();
5883
5884 // Store this time as UTC
5885 FillJulian();
5886 Int_t ret=SetUTCparameters("A",0,0);
5887
5888 // Use the UTC parameters (if any) to determine UT1
5889 if (ret && ret!=-3)
5890 {
5891 AddSec(fDut); // Correct UTC for dUT=UT1-UTC to obtain UT1 as main reference
5892 }
5893 else
5894 {
5895 SetUTCparameters("N",0,0); // Keep the system clock time as main (UTC) reference
5896 }
5897 FillTAI();
5898}
5899
5901{
5907
5908 Bool_t ut1=kTRUE;
5909 if (!fUtc) ut1=kFALSE;
5910
5911 return ut1;
5912}
5913
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)
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)