GammaLib 2.1.0.dev
Loading...
Searching...
No Matches
GTime.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * GTime.cpp - Time class *
3 * ----------------------------------------------------------------------- *
4 * copyright (C) 2010-2021 by Juergen Knoedlseder *
5 * ----------------------------------------------------------------------- *
6 * *
7 * This program is free software: you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation, either version 3 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
19 * *
20 ***************************************************************************/
21/**
22 * @file GTime.cpp
23 * @brief Time class implementation
24 * @author Juergen Knoedlseder
25 */
26
27/* __ Includes ___________________________________________________________ */
28#ifdef HAVE_CONFIG_H
29#include <config.h>
30#endif
31#include <ctime>
32#include <cstring> // std::memcpy
33#include <cstdio>
34#include "GTools.hpp"
35#include "GMath.hpp"
36#include "GException.hpp"
37#include "GTime.hpp"
38#include "GTimeReference.hpp"
39
40/* __ Constants __________________________________________________________ */
41const double mjd_ref = 55197.000766018518519; //!< MJD of time=0
42const double jd_ref = mjd_ref + 2400000.5; //!< JD of time=0
43
44/* __ Method name definitions ____________________________________________ */
45#define G_CONSTRUCT "GTime::GTime(double&, std::string&)"
46#define G_SECS_GET "GTime::secs(std::string&)"
47#define G_SECS_SET "GTime::secs(double&, std::string&)"
48#define G_UTC "GTime::utc(std::string&)"
49#define G_UTC_GET "GTime::utc(int&)"
50
51/* __ Macros _____________________________________________________________ */
52
53/* __ Coding definitions _________________________________________________ */
54
55/* __ Debug definitions __________________________________________________ */
56
57
58/*==========================================================================
59 = =
60 = Constructors/destructors =
61 = =
62 ==========================================================================*/
63
64/***********************************************************************//**
65 * @brief Void constructor
66 ***************************************************************************/
68{
69 // Initialise private members
71
72 // Return
73 return;
74}
75
76
77/***********************************************************************//**
78 * @brief Copy constructor
79 *
80 * @param[in] time Time.
81 ***************************************************************************/
82GTime::GTime(const GTime& time)
83{
84 // Initialise private members
86
87 // Copy members
88 copy_members(time);
89
90 // Return
91 return;
92}
93
94
95/***********************************************************************//**
96 * @brief Time constructor
97 *
98 * @param[in] time Time value in TT (seconds or days).
99 * @param[in] unit Time unit string.
100 *
101 * @exception GException::invalid_argument
102 * Invalid time unit specified.
103 *
104 * Constructs a GTime object by setting the time in the native reference
105 * in the TT time system in units of seconds (default) or days.
106 ***************************************************************************/
107GTime::GTime(const double& time, const std::string& unit)
108{
109 // Initialise private members
110 init_members();
111
112 // Set time according to timeunit string
113 std::string timeunit = gammalib::tolower(unit);
114 if (timeunit == "d" || timeunit == "day" || timeunit == "days") {
115 days(time);
116 }
117 else if (timeunit == "s" || timeunit == "sec" || timeunit == "secs") {
118 secs(time);
119 }
120 else {
121 std::string msg = "Invalid time unit \""+unit+"\" specified. Please "
122 "specify one of \"d\", \"day\", \"days\", \"s\", "
123 "\"sec\" or \"secs\"";
125 }
126
127 // Return
128 return;
129}
130
131
132/***********************************************************************//**
133 * @brief Time constructor
134 *
135 * @param[in] time Time in given reference system.
136 * @param[in] ref Reference system.
137 *
138 * Constructs a GTime object by setting the time to a value given in a
139 * specific reference system.
140 ***************************************************************************/
141GTime::GTime(const double& time, const GTimeReference& ref)
142{
143 // Initialise private members
144 init_members();
145
146 // Set time
147 set(time, ref);
148
149 // Return
150 return;
151}
152
153
154/***********************************************************************//**
155 * @brief Time constructor
156 *
157 * @param[in] time Time string in given reference system.
158 * @param[in] ref Reference system.
159 *
160 * Constructs a GTime object by setting the time to a string value. See the
161 * set(std::string&, GTimeReference&) method for valid time strings.
162 ***************************************************************************/
163GTime::GTime(const std::string& time, const GTimeReference& ref)
164{
165 // Initialise private members
166 init_members();
167
168 // Set time
169 set(time, ref);
170
171 // Return
172 return;
173}
174
175
176/***********************************************************************//**
177 * @brief Time constructor
178 *
179 * @param[in] time Time string.
180 *
181 * Constructs a GTime object by setting the time to a string value. See the
182 * set(const std::string& time) method for valid time strings.
183 ***************************************************************************/
184GTime::GTime(const std::string& time)
185{
186 // Initialise private members
187 init_members();
188
189 // Set time
190 set(time);
191
192 // Return
193 return;
194}
195
196
197/***********************************************************************//**
198 * @brief Destructor
199 ***************************************************************************/
201{
202 // Free members
203 free_members();
204
205 // Return
206 return;
207}
208
209
210/*==========================================================================
211 = =
212 = Operators =
213 = =
214 ==========================================================================*/
215
216/***********************************************************************//**
217 * @brief Assignment operator
218 *
219 * @param[in] time Time.
220 * @return Time.
221 ***************************************************************************/
223{
224 // Execute only if object is not identical
225 if (this != &time) {
226
227 // Free members
228 free_members();
229
230 // Initialise private members for clean destruction
231 init_members();
232
233 // Copy members
234 copy_members(time);
235
236 } // endif: object was not identical
237
238 // Return
239 return *this;
240}
241
242
243/*==========================================================================
244 = =
245 = Public methods =
246 = =
247 ==========================================================================*/
248
249/***********************************************************************//**
250 * @brief Clear time
251 ***************************************************************************/
252void GTime::clear(void)
253{
254 // Free members
255 free_members();
256
257 // Initialise members
258 init_members();
259
260 // Return
261 return;
262}
263
264
265/***********************************************************************//**
266 * @brief Clone time
267 *
268 * @return Pointer to deep copy of time.
269 ***************************************************************************/
270GTime* GTime::clone(void) const
271{
272 // Clone this image
273 return new GTime(*this);
274}
275
276
277/***********************************************************************//**
278 * @brief Return time in Julian Days (TT)
279 *
280 * @return Time in Julian Days (TT) (days).
281 *
282 * Returns the time in Julian Days (JD) in the Terrestrial Time (TT) system.
283 ***************************************************************************/
284double GTime::jd(void) const
285{
286 // Convert time from MET to JD
287 double jd = m_time * gammalib::sec2day + jd_ref;
288
289 // Return Julian Days
290 return jd;
291}
292
293
294/***********************************************************************//**
295 * @brief Return time in Julian Days for time system
296 *
297 * @param[in] timesys Time system (one of "TT", "TAI", "UTC")
298 * @return Time in Julian Days (days).
299 *
300 * Returns the time in Julian Days (JD) for the specified time system.
301 ***************************************************************************/
302double GTime::jd(const std::string& timesys) const
303{
304 // Convert time to Julian Days
305 double jd = secs(timesys) * gammalib::sec2day + jd_ref;
306
307 // Return Julian Days
308 return jd;
309}
310
311
312/***********************************************************************//**
313 * @brief Return time in Modified Julian Days (TT)
314 *
315 * @return Time in Modified Julian Days (TT) (days).
316 *
317 * Returns the time in Modified Julian Days (MJD) in the Terrestrial Time
318 * (TT) system.
319 ***************************************************************************/
320double GTime::mjd(void) const
321{
322 // Convert time to Modified Julian Days
323 double mjd = m_time * gammalib::sec2day + mjd_ref;
324
325 // Return Modified Julian Days
326 return mjd;
327}
328
329
330/***********************************************************************//**
331 * @brief Return time in Modified Julian Days for time system
332 *
333 * @param[in] timesys Time system (one of "TT", "TAI", "UTC")
334 * @return Time in Modified Julian Days (days).
335 *
336 * Returns the time in Modified Julian Days (JD) for the specified time
337 * system.
338 ***************************************************************************/
339double GTime::mjd(const std::string& timesys) const
340{
341 // Convert time to Modified Julian Days
342 double mjd = secs(timesys) * gammalib::sec2day + mjd_ref;
343
344 // Return Modified Julian Days
345 return mjd;
346}
347
348
349/***********************************************************************//**
350 * @brief Return time in seconds in native reference for time system
351 *
352 * @param[in] timesys Time system (one of "TT", "TAI", "UTC")
353 * @return Time (seconds).
354 ***************************************************************************/
355double GTime::secs(const std::string& timesys) const
356{
357 // Initialise time
358 double time;
359
360 // If system is TT then return the stored time ...
361 if (timesys == "TT") {
362 time = m_time;
363 }
364
365 // ... otherwise if the system if TAI then subtract an offset ...
366 else if (timesys == "TAI") {
367 time = m_time - gammalib::tai2tt;
368 }
369
370 // ... otherwise if the system is UTC then convert the time from TT to TAI
371 // and subtract the leap seconds. The repeated calling of the leap second
372 // method is a kluge to converge as the argument is given in the UTC system
373 // but upon start we're in the TAI system.
374 else if (timesys == "UTC") {
375 time = m_time - gammalib::tai2tt; // Time in TAI
376 double mjd = time * gammalib::sec2day + mjd_ref;
377 double leaps = leap_seconds(mjd);
378 leaps = leap_seconds(mjd - leaps * gammalib::sec2day);
379 leaps = leap_seconds(mjd - leaps * gammalib::sec2day);
380 time -= leaps;
381 }
382
383 // ... otherwise throw an exception
384 else {
385 std::string msg = "Unknown time system \""+timesys+"\". Either specify "
386 "\"TT\", \"TAI\" or \"UTC\".";
388 }
389
390 // Return time
391 return time;
392}
393
394
395/***********************************************************************//**
396 * @brief Return time in days in native reference (TT)
397 *
398 * @return Time in native reference (days).
399 ***************************************************************************/
400double GTime::days(void) const
401{
402 // Return time
403 return (m_time * gammalib::sec2day);
404}
405
406
407/***********************************************************************//**
408 * @brief Return time in days in native reference for time system
409 *
410 * @param[in] timesys Time system (one of "TT", "TAI", "UTC")
411 * @return Time in native reference (days).
412 ***************************************************************************/
413double GTime::days(const std::string& timesys) const
414{
415 // Return time
416 return (secs(timesys) * gammalib::sec2day);
417}
418
419
420/***********************************************************************//**
421 * @brief Return Julian epoch in native reference (TT)
422 *
423 * @return Julian epoch (years).
424 ***************************************************************************/
425double GTime::julian_epoch(void) const
426{
427 // Compute Julian epoch
428 double julian_epoch = 2000.0 + (jd() - 2451545.0) / 365.25;
429
430 // Return Julian epoch
431 return (julian_epoch);
432}
433
434
435/***********************************************************************//**
436 * @brief Return Julian epoch in native reference for time system
437 *
438 * @param[in] timesys Time system (one of "TT", "TAI", "UTC")
439 * @return Julian epoch (years).
440 ***************************************************************************/
441double GTime::julian_epoch(const std::string& timesys) const
442{
443 // Compute Julian epoch
444 double julian_epoch = 2000.0 + (jd(timesys) - 2451545.0) / 365.25;
445
446 // Return Julian epoch
447 return (julian_epoch);
448}
449
450
451/***********************************************************************//**
452 * @brief Return time as string in UTC time system
453 *
454 * @param[in] precision Digits of precision to show in the seconds field
455 * @return Time as string in UTC time system.
456 *
457 * Returns time in the format YYYY-MM-DDThh:mm:ss(.ss...), where YYYY is a
458 * four-digit year, MM a two-digit month, DD a two-digit day of month, hh two
459 * digits of hour (0 through 23), mm two digits of minutes, and ss(.ss...)
460 * two digits of second (ISO 8601 time standard). In case that
461 * @p precision > 0 digits in the second after the comma will be returned.
462 *
463 * The method is only valid for dates from year 1972 on.
464 ***************************************************************************/
465std::string GTime::utc(const int& precision) const
466{
467 // Check argument
468 if (precision < 0) {
469 std::string msg = "Invalid precision \""+gammalib::str(precision)+"\""
470 " encountered. Please specify a precision >= 0.";
472 }
473
474 // Define number of days per month
475 static int daymonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
476
477 // Get MJD in TAI time system
478 double mjd = this->mjd() - gammalib::tai2tt * gammalib::sec2day;
479
480 // Correct for leap seconds (repeat is a kluge to converge as the
481 // argument is given in the UTC system but upon start we're in the TAI
482 // system
483 double leaps = leap_seconds(mjd) * gammalib::sec2day;
484 leaps = leap_seconds(mjd - leaps) * gammalib::sec2day;
485 leaps = leap_seconds(mjd - leaps) * gammalib::sec2day;
486 mjd -= leaps;
487
488 // Split in day and fraction
489 int day = (int)mjd;
490 double fraction = mjd - (double)day;
491
492 // Get margin for computation. We add the margin to the seconds and
493 // subtract it later to avoid rounding to 60 seconds
494 double margin = 0.5;
495 if (precision > 0) {
496 switch (precision) {
497 case 1:
498 margin = 0.05;
499 break;
500 case 2:
501 margin = 0.005;
502 break;
503 case 3:
504 margin = 0.0005;
505 break;
506 default:
507 for (int i = 0; i < precision; ++i) {
508 margin *= 0.1;
509 }
510 break;
511 }
512 }
513
514 // Compute time in day
515 double second = fraction * gammalib::sec_in_day + margin;
516 int hour = (int)second / 3600;
517 second -= hour * 3600.0;
518 int minute = (int)second / 60;
519 second -= minute * 60.0;
520 if (hour > 23) {
521 hour -= 24;
522 day++;
523 }
524 second -= margin;
525 if (second < 0.0) {
526 second = 0.0;
527 }
528
529 // Compute year and day in the year
530 int year = 1972; // Set year to 1972
531 day -= 41317; // Subtract MJD of 1-1-1972
532 day++; // Day 0 is 1 January
533 int days = days_in_year(year);
534 while (day > days) {
535 day -= days;
536 year++;
537 days = days_in_year(year);
538 }
539 while (day < 0) {
540 year--;
541 days = days_in_year(year);
542 day += days;
543 }
544
545 // Adjust number of days per month for leap years
546 if (is_leap_year(year)) {
547 daymonth[1] = 29;
548 }
549 else {
550 daymonth[1] = 28;
551 }
552
553 // Compute month and day in the month
554 int month = 0;
555 while (month < 12) {
556 if (day <= daymonth[month]) {
557 break;
558 }
559 day -= daymonth[month];
560 month++;
561 }
562 month++;
563
564 // Calculate the width of the seconds' pattern, plus two for the integer
565 // seconds, plus one if a decimal is needed
566 int sec_width = precision + 2;
567 if (precision > 0) {
568 sec_width += 1;
569 }
570
571 // Format pattern for variable seconds precision
572 char utc_pattern[50];
573 sprintf(utc_pattern, "%%4.4d-%%2.2d-%%2.2dT%%2.2d:%%2.2d:%%0%d.0%df",
574 sec_width, precision);
575
576 // Create string
577 char utc[32];
578 sprintf(utc, utc_pattern,
579 year, month, day, hour, minute, second);
580
581 // Return
582 return (std::string(utc));
583}
584
585
586/***********************************************************************//**
587 * @brief Return Greenwich mean sidereal time in hours in a day
588 *
589 * @return Greenwich mean sidereal time (hours).
590 *
591 * See http://aa.usno.navy.mil/faq/docs/GAST.php
592 ***************************************************************************/
593double GTime::gmst(void) const
594{
595 // Get days since 1 January 2000, 12h in Universal Time
596 double d = days("UTC") + 3652.50076602;
597
598 // Compute Greenwich mean sidereal time in hours
599 double gmst = 18.697374558 + 24.06570982441908 * d;
600
601 // Put into [0,24]
602 gmst -= floor(gmst/24.0) * 24.0;
603
604 // Return Greenwich mean sidereal time in hours
605 return gmst;
606}
607
608
609/***********************************************************************//**
610 * @brief Return Greenwich apparent sidereal time in hours in a day
611 *
612 * @return Greenwich apparent sidereal time (hours).
613 *
614 * See http://aa.usno.navy.mil/faq/docs/GAST.php
615 ***************************************************************************/
616double GTime::gast(void) const
617{
618 // Get days since 1 January 2000, 12h in Universal Time
619 double d = days("UTC") + 3652.50076602;
620
621 // Compute longitude of the ascending node of the Moon in degrees
622 double Omega = 125.04 - 0.052954 * d;
623
624 // Compute mean longitude of the Sun in degrees
625 double L = 280.47 + 0.98565 * d;
626
627 // Compute nutation in longitude in hours
628 double DeltaPsi = -0.000319 * std::sin(Omega * gammalib::deg2rad) -
629 0.000024 * std::sin(2.0 * L * gammalib::deg2rad);
630
631 // Compute the obliquity in degrees
632 double epsilon = 23.4393 - 0.0000004 * d;
633
634 // Compute equation of equinoxes
635 double eqeq = DeltaPsi * std::cos(epsilon * gammalib::deg2rad);
636
637 // Compute Greenwich apparent sidereal time in hours
638 double gast = gmst() + eqeq;
639
640 // Put into [0,24]
641 gast -= floor(gast/24.0) * 24.0;
642
643 // Return Greenwich apparent sidereal time in hours
644 return gast;
645}
646
647
648/***********************************************************************//**
649 * @brief Return local mean sidereal time in hours in a day
650 *
651 * @param[in] geolon Geographic longitude West of Greenwich (degrees).
652 * @return Local mean sidereal time (hours).
653 *
654 * See http://aa.usno.navy.mil/faq/docs/GAST.php
655 ***************************************************************************/
656double GTime::lmst(const double& geolon) const
657{
658 // Compute local mean siderial time
659 double lmst = gmst() - geolon/15.0;
660
661 // Put into [0,24]
662 lmst -= floor(lmst/24.0) * 24.0;
663
664 // Return local mean sidereal time in hours
665 return lmst;
666}
667
668
669/***********************************************************************//**
670 * @brief Return local apparent sidereal time in hours in a day
671 *
672 * @param[in] geolon Geographic longitude West of Greenwich (degrees).
673 * @return Local apparent sidereal time (hours).
674 *
675 * See http://aa.usno.navy.mil/faq/docs/GAST.php
676 ***************************************************************************/
677double GTime::last(const double& geolon) const
678{
679 // Compute local apparent siderial time
680 double last = gast() - geolon/15.0;
681
682 // Put into [0,24]
683 last -= floor(last/24.0) * 24.0;
684
685 // Return local mean sidereal time in hours
686 return last;
687}
688
689
690/***********************************************************************//**
691 * @brief Return time in specified reference
692 *
693 * @return Time in specified reference.
694 *
695 * Convert the time from the native reference system into the specified
696 * reference system.
697 ***************************************************************************/
698double GTime::convert(const GTimeReference& ref) const
699{
700 // Retrieve time in native reference (TT in seconds)
701 double time = m_time;
702
703 // Compute time offset in seconds
704 double offset = (mjd_ref - ref.mjdref()) * gammalib::sec_in_day;
705
706 // Add time offset in seconds
707 time += offset;
708
709 // Subtract leap seconds in case that time is requested in UTC time
710 // system
711 if (gammalib::toupper(ref.timesys()) == "UTC") {
712
713 // Get MJD in TAI time system
714 double mjd = this->mjd() - gammalib::tai2tt * gammalib::sec2day;
715
716 // Get leap seconds (repeat is a kluge to converge as the
717 // argument is given in the UTC system but upon start we're in the TAI
718 // system
719 double leaps = leap_seconds(mjd);
720 leaps = leap_seconds(mjd - leaps * gammalib::sec2day);
721 leaps = leap_seconds(mjd - leaps * gammalib::sec2day);
722
723 // Subtract leap seconds and TAI offset
724 time -= (leaps + gammalib::tai2tt);
725
726 } // endif: UTC time system has been requested
727
728 // ... otherwise, if time is requested in TAI system then subtract the
729 // TAI offset
730 else if (gammalib::toupper(ref.timesys()) == "TAI") {
731 time -= gammalib::tai2tt;
732 }
733
734 // Convert to specified time unit
735 double to_unit = ref.unitseconds();
736 if (to_unit != 1.0) {
737 time /= to_unit;
738 }
739
740 // Return time
741 return time;
742}
743
744
745/***********************************************************************//**
746 * @brief Set time in Julian Days in native reference (TT)
747 *
748 * @param[in] time Time in Julian Days (TT) (days).
749 ***************************************************************************/
750void GTime::jd(const double& time)
751{
752 // Convert time from Julian Days to seconds in native reference
754
755 // Return
756 return;
757}
758
759
760/***********************************************************************//**
761 * @brief Set time in Julian Days in native reference for time system
762 *
763 * @param[in] time Time in Julian Days (days).
764 * @param[in] timesys Time system (one of "TT", "TAI", "UTC")
765 ***************************************************************************/
766void GTime::jd(const double& time, const std::string& timesys)
767{
768 // Convert time from Julian Days to seconds in native reference
769 double seconds = (time - jd_ref) * gammalib::sec_in_day;
770
771 // Set time according to the specified time system
772 secs(seconds, timesys);
773
774 // Return
775 return;
776}
777
778
779/***********************************************************************//**
780 * @brief Set time in Modified Julian Days in native reference (TT)
781 *
782 * @param[in] time Time in Modified Julian Days (TT) (days).
783 ***************************************************************************/
784void GTime::mjd(const double& time)
785{
786 // Convert time from Modified Julian Days to native (seconds)
788
789 // Return
790 return;
791}
792
793
794/***********************************************************************//**
795 * @brief Set time in Modified Julian Days in native reference for time
796 * system
797 *
798 * @param[in] time Time in Modified Julian Days (days).
799 * @param[in] timesys Time system (one of "TT", "TAI", "UTC")
800 ***************************************************************************/
801void GTime::mjd(const double& time, const std::string& timesys)
802{
803 // Convert time from Modified Julian Days to seconds in native reference
804 double seconds = (time - mjd_ref) * gammalib::sec_in_day;
805
806 // Set time according to the specified time system
807 secs(seconds, timesys);
808
809 // Return
810 return;
811}
812
813
814/***********************************************************************//**
815 * @brief Set time in seconds in native reference for time system
816 *
817 * @param[in] seconds Time in native reference (seconds).
818 * @param[in] timesys Time system (one of "TT", "TAI", "UTC")
819 ***************************************************************************/
820void GTime::secs(const double& seconds, const std::string& timesys)
821{
822 // If system is TT then simply set time ...
823 if (timesys == "TT") {
824 m_time = seconds;
825 }
826
827 // ... otherwise if the system if TAI then add an offset ...
828 else if (timesys == "TAI") {
829 m_time = seconds + gammalib::tai2tt;
830 }
831
832 // ... otherwise if the system is UTC then convert the time from TT to TAI
833 // and add the leap seconds ...
834 else if (timesys == "UTC") {
835 double mjd = seconds * gammalib::sec2day + mjd_ref; // Time in UTC
836 double leaps = leap_seconds(mjd);
837 m_time = seconds + gammalib::tai2tt + leaps;
838 }
839
840 // ... otherwise throw an exception
841 else {
842 std::string msg = "Unknown time system \""+timesys+"\". Either specify "
843 "\"TT\", \"TAI\" or \"UTC\".";
845 }
846
847 // Return
848 return;
849}
850
851
852/***********************************************************************//**
853 * @brief Set time in days in native reference (TT)
854 *
855 * @param[in] days Time (TT) (days).
856 ***************************************************************************/
857void GTime::days(const double& days)
858{
859 // Set time
861
862 // Return
863 return;
864}
865
866
867/***********************************************************************//**
868 * @brief Set time in days in native reference for time system
869 *
870 * @param[in] days Time (TT) (days).
871 * @param[in] timesys Time system (one of "TT", "TAI", "UTC")
872 ***************************************************************************/
873void GTime::days(const double& days, const std::string& timesys)
874{
875 // Convert time from days to seconds in native reference
876 double seconds = days * gammalib::sec_in_day;
877
878 // Set time according to the specified time system
879 secs(seconds, timesys);
880
881 // Return
882 return;
883}
884
885
886/***********************************************************************//**
887 * @brief Set time as string in UTC time system
888 *
889 * @param[in] time Time string (UTC).
890 *
891 * @exception GException::invalid_argument
892 * Invalid time string specified.
893 *
894 * The time has to be given in the format YYYY-MM-DDThh:mm:ss.s, where
895 * YYYY is a four-digit year, MM a two-digit month, DD a two-digit day of
896 * month, hh two digits of hour (0 through 23), mm two digits of minutes,
897 * ss two digits of second and s one or more digits representing a
898 * decimal fraction of a second (ISO 8601 time standard).
899 *
900 * The method is only valid for dates from year 1972 on.
901 ***************************************************************************/
902void GTime::utc(const std::string& time)
903{
904 // Define number of days per month
905 static int daymonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
906
907 // Analyse the UTC string
908 long year = 0;
909 int month = 0;
910 long day = 0;
911 long hour = 0;
912 long minute = 0;
913 double second = 0.0;
914 int n = sscanf(time.c_str(), "%ld-%d-%ldT%ld:%ld:%lg",
915 &year, &month, &day, &hour, &minute, &second);
916
917 // Adjust number of days per month for leap years
918 if (is_leap_year(year)) {
919 daymonth[1] = 29;
920 }
921 else {
922 daymonth[1] = 28;
923 }
924
925 // Check time string
926 if (n != 3 && n != 6) {
927 std::string msg = "Invalid time string \""+time+"\" encountered. "
928 "Please specify the time in the format YYYY-MM-DD "
929 "or YYYY-MM-DDThh:mm:ss.s.";
931 }
932 if (year < 1000 || year > 9999) {
933 std::string msg = "Invalid year "+gammalib::str(year)+" specified. "
934 "The year needs to be a four-digit year.";
936 }
937 if (month < 1 || month > 12) {
938 std::string msg = "Invalid month "+gammalib::str(month)+" specified. "
939 "The month needs to be comprised between 01 and 12";
941 }
942 if (day < 1 || day > daymonth[month-1]) {
943 std::string msg = "Invalid day "+gammalib::str(day)+" specified. "
944 "The day for month "+gammalib::str(month)+" needs "
945 "to be comprised between 01 and "+
946 gammalib::str(daymonth[month-1])+".";
948 }
949 if (hour < 0 || hour > 23) {
950 std::string msg = "Invalid hour "+gammalib::str(hour)+" specified. "
951 "The hour needs to be comprised between 00 and 23";
953 }
954 if (minute < 0 || minute > 59) {
955 std::string msg = "Invalid minute "+gammalib::str(minute)+" specified. "
956 "The minute needs to be comprised between 00 and 59";
958 }
959 if (second < 0 || second >= 60.0) {
960 std::string msg = "Invalid second "+gammalib::str(second)+" specified. "
961 "The second needs to be comprised between 00 and <60";
963 }
964
965 // Compute MJD day
966 month--;
967 for (int i = 0; i < month; ++i) { // Add days passed per month
968 day += daymonth[i];
969 }
970 day += (year - 1972) * 365 - 1; // Add days passed per year
971 day += (year - 1969) / 4; // Add leap days passed (every 4 years)
972 day -= (year - 1901) / 100; // Add leap days passed (not every 100 years)
973 day += (year - 1601) / 400; // Add leap days passed (every 400 years)
974 day += 41317; // Add MJD at 1972
975
976 // Compute MJD fraction (UTC)
977 double fraction = ((double)hour * 3600.0 + (double)minute * 60.0 + second) *
979
980 // Compute MJD (UTC)
981 double mjd = (double)day + fraction;
982
983 // Get conversion from UTC to TAI to TT
984 double correction = leap_seconds(mjd) + gammalib::tai2tt;
985
986 // Convert MJD from UTC to TT
987 mjd += correction * gammalib::sec2day;
988
989 // Set time
990 this->mjd(mjd);
991
992 // Return
993 return;
994}
995
996
997/***********************************************************************//**
998 * @brief Set time given in specified reference
999 *
1000 * @param[in] time Time in given reference system.
1001 * @param[in] ref Reference system.
1002 *
1003 * Set the time to a value given in a specific reference system.
1004 ***************************************************************************/
1005void GTime::set(const double& time, const GTimeReference& ref)
1006{
1007 // Convert time to specified time unit
1008 m_time = time * ref.unitseconds();
1009
1010 // Compute time offset in seconds
1011 double offset = (mjd_ref - ref.mjdref()) * gammalib::sec_in_day;
1012
1013 // Subtract time offset in seconds
1014 m_time -= offset;
1015
1016 // Add leap seconds in case that time was given in UTC time system
1017 if (gammalib::toupper(ref.timesys()) == "UTC") {
1018
1019 // Add leap seconds and offset between TAI and TT time system
1020 m_time += leap_seconds(this->mjd());
1022
1023 } // endif: Time was given in UTC time system
1024
1025 // ... otherwise if system is TAI system then add TAI offset
1026 else if (gammalib::toupper(ref.timesys()) == "TAI") {
1028 }
1029
1030 // Return
1031 return;
1032}
1033
1034
1035/***********************************************************************//**
1036 * @brief Set time from string
1037 *
1038 * @param[in] time Time string.
1039 * @param[in] ref Reference system.
1040 *
1041 * Sets the time from a string for a given reference system. The following
1042 * strings are valid:
1043 *
1044 * "2016-10-05T15:08:56" (UTC string)
1045 * "1800.0" (MET seconds in specified reference system)
1046 * "1800.0 (TT)" (MET seconds in specified reference, TT system)
1047 * "1800.0 (UTC)" (MET seconds in specified reference, UTC time system)
1048 * "1800.0 (TAI)" (MET seconds in specified reference, TAI time system)
1049 * "MJD 54609" (Modified Julian Days, TT system)
1050 * "MJD 54609 (TT)" (Modified Julian Days, TT system)
1051 * "MJD 54609 (UTC)" (Modified Julian Days, UTC system)
1052 * "MJD 54609 (TAI)" (Modified Julian Days, TAI system)
1053 * "JD 54609" (Julian Days, TT system)
1054 * "JD 54609 (TT)" (Julian Days, TT system)
1055 * "JD 54609 (UTC)" (Julian Days, UTC system)
1056 * "JD 54609 (TAI)" (Julian Days, TAI system)
1057 *
1058 * If any other string is encountered, the numerical value is interpreted as
1059 * time is seconds using the TT system.
1060 *
1061 * Note that the TT, UTC or TAI attributes overwrite the values contained in
1062 * the specified reference system. The reference system is only used to
1063 * convert MET times in seconds.
1064 ***************************************************************************/
1065void GTime::set(const std::string& time, const GTimeReference& ref)
1066{
1067 // Strip any whitespace from string and convert it to upper case
1068 std::string str = gammalib::toupper(gammalib::strip_whitespace(time));
1069
1070 // First check if the string is a UTC string
1071 long year = 0;
1072 int month = 0;
1073 long day = 0;
1074 long hour = 0;
1075 long minute = 0;
1076 double second = 0.0;
1077 int n = sscanf(str.c_str(), "%ld-%d-%ldT%ld:%ld:%lg",
1078 &year, &month, &day, &hour, &minute, &second);
1079 if (n == 3 || n == 6) {
1080 utc(str);
1081 }
1082
1083 // ... otherwise check for Modified Julian Days
1084 else if (str.find("MJD") == 0) {
1085 double timeval = extract_timeval(str);
1086 std::string timesys = extract_timesys(str);
1087 if (timesys.empty()) {
1088 timesys = "TT";
1089 }
1090 mjd(timeval, timesys);
1091 }
1092
1093 // ... otherwise check for Julian Days
1094 else if (str.find("JD") == 0) {
1095 double timeval = extract_timeval(str);
1096 std::string timesys = extract_timesys(str);
1097 if (timesys.empty()) {
1098 timesys = "TT";
1099 }
1100 jd(timeval, timesys);
1101 }
1102
1103 // ... otherwise take time as seconds and use the specified reference
1104 // system. If no TT, UTC or TAI arrtibutes are specified use the value
1105 // specified by the reference system.
1106 else {
1107 double timeval = extract_timeval(str);
1108 std::string timesys = extract_timesys(str);
1109 if (timesys.empty()) {
1110 timesys = ref.timesys();
1111 }
1112 GTimeReference timeref(ref.mjdref(), ref.timeunit(), timesys, ref.timeref());
1113 set(timeval, timeref);
1114 }
1115
1116 // Return
1117 return;
1118}
1119
1120
1121/***********************************************************************//**
1122 * @brief Set time to current time
1123 *
1124 * Sets time to current time.
1125 ***************************************************************************/
1126void GTime::now(void)
1127{
1128 // Allocate variables
1129 struct std::tm timeStruct;
1130 std::time_t now;
1131 char buffer[100];
1132
1133 // Get time
1134 now = std::time(NULL);
1135 #ifdef HAVE_GMTIME_R
1136 std::gmtime_r(&now, &timeStruct);
1137 #else
1138 std::memcpy(&timeStruct, gmtime(&now), sizeof(struct tm));
1139 #endif
1140
1141 // Write message type, time and task name to buffer
1142 std::sprintf(buffer, "%04d-%02d-%02dT%02d:%02d:%02d",
1143 timeStruct.tm_year + 1900,
1144 timeStruct.tm_mon + 1,
1145 timeStruct.tm_mday,
1146 timeStruct.tm_hour,
1147 timeStruct.tm_min,
1148 timeStruct.tm_sec);
1149
1150 // Build string from buffer
1151 std::string date = buffer;
1152
1153 // Set UTC time
1154 utc(date);
1155
1156 // Return
1157 return;
1158}
1159
1160
1161/***********************************************************************//**
1162 * @brief Returns native time reference
1163 *
1164 * @return Native time reference.
1165 *
1166 * Returns the native GammaLib time reference. The GammaLib native time
1167 * reference (i.e. time=0) is defined as January 1, 2010, 00:00:00 (TT).
1168 * The time system is Terrestrial Time (TT). Time is stored in seconds.
1169 ***************************************************************************/
1171{
1172 // Allocate native time reference
1173 GTimeReference reference(mjd_ref, "s", "TT", "LOCAL");
1174
1175 // Return reference
1176 return reference;
1177}
1178
1179
1180/***********************************************************************//**
1181 * @brief Print time
1182 *
1183 * @param[in] chatter Chattiness.
1184 * @return String containing time in seconds in native reference.
1185 *
1186 * Prints time in seconds in the native reference.
1187 ***************************************************************************/
1188std::string GTime::print(const GChatter& chatter) const
1189{
1190 // Initialise result string
1191 std::string result;
1192
1193 // Continue only if chatter is not silent
1194 if (chatter != SILENT) {
1195
1196 // Append time
1197 result.append(gammalib::str(m_time)+" s (TT)");
1198
1199 } // endif: chatter was not silent
1200
1201 // Return
1202 return result;
1203}
1204
1205
1206/*==========================================================================
1207 = =
1208 = Private methods =
1209 = =
1210 ==========================================================================*/
1211
1212/***********************************************************************//**
1213 * @brief Initialise class members
1214 ***************************************************************************/
1216{
1217 // Initialise members
1218 m_time = 0.0;
1219
1220 // Return
1221 return;
1222}
1223
1224
1225/***********************************************************************//**
1226 * @brief Copy class members
1227 *
1228 * @param[in] time Time.
1229 ***************************************************************************/
1231{
1232 // Copy time
1233 m_time = time.m_time;
1234
1235 // Return
1236 return;
1237}
1238
1239
1240/***********************************************************************//**
1241 * @brief Delete class members
1242 ***************************************************************************/
1244{
1245 // Return
1246 return;
1247}
1248
1249
1250/***********************************************************************//**
1251 * @brief Returns number of leap seconds for a given MJD
1252 *
1253 * @param[in] mjd Modified Julian Day in UTC time system.
1254 * @return Number of lead seconds.
1255 *
1256 * Return the number of leap seconds for a given MJD specified in the UTC
1257 * time system. This method returns valid number of leap seconds for the
1258 * years 1972-2017.
1259 *
1260 * See http://www.nist.gov/pml/div688/grp50/leapsecond.cfm for a table of
1261 * leap seconds.
1262 ***************************************************************************/
1263double GTime::leap_seconds(const double& mjd) const
1264{
1265 // Leap second table from 1972 on
1266 // see http://www.nist.gov/pml/div688/grp50/leapsecond.cfm
1267 // The first entry is 1-Jan-1972
1268 const long leapsmjd[] = {41317, // 1972-01-01
1269 41498, // 1972-06-30
1270 41682, // 1972-12-31
1271 42047, // 1973-12-31
1272 42412, // 1974-12-31
1273 42777, // 1975-12-31
1274 43143, // 1976-12-31
1275 43508, // 1977-12-31
1276 43873, // 1978-12-31
1277 44238, // 1979-12-31
1278 44785, // 1981-06-30
1279 45150, // 1982-06-30
1280 45515, // 1983-06-30
1281 46246, // 1985-06-30
1282 47160, // 1987-12-31
1283 47891, // 1989-12-31
1284 48256, // 1990-12-31
1285 48803, // 1992-06-30
1286 49168, // 1993-06-30
1287 49533, // 1994-06-30
1288 50082, // 1995-12-31
1289 50629, // 1997-06-30
1290 51178, // 1998-12-31
1291 53735, // 2005-12-31
1292 54831, // 2008-12-31
1293 56108, // 2012-06-30
1294 57203, // 2015-06-30
1295 57753}; // 2016-12-31
1296 const double leapsecs[] = {10.0, 11.0, 12.0, 13.0, 14.0,
1297 15.0, 16.0, 17.0, 18.0, 19.0,
1298 20.0, 21.0, 22.0, 23.0, 24.0,
1299 25.0, 26.0, 27.0, 28.0, 29.0,
1300 30.0, 31.0, 32.0, 33.0, 34.0,
1301 35.0, 36.0, 37.0};
1302 const int n_leapsecs = sizeof(leapsmjd)/sizeof(long);
1303
1304 // Extract MJD day and MJD fraction
1305 long day = (long)mjd;
1306
1307 // Find the leap second MJD that is equal or larger to the specified
1308 // day
1309 int i = n_leapsecs - 1;
1310 while ((day <= leapsmjd[i]) && i > 0) {
1311 i--;
1312 }
1313
1314 // Return leap seconds
1315 return (leapsecs[i]);
1316}
1317
1318
1319/***********************************************************************//**
1320 * @brief Extract time value from time string
1321 *
1322 * @param[in] time Time string.
1323 * @return Time value.
1324 *
1325 * Extracts the time value from a time string. The method strips any prefix
1326 * such as "MJD" or "JD" and any suffix starting with a left parentheses "("
1327 * and converts the remainder into a double precision value.
1328 ***************************************************************************/
1329double GTime::extract_timeval(const std::string& time) const
1330{
1331 // Find time
1332 size_t length = time.length();
1333 size_t start = time.find_first_of("0123456789+-.");
1334 size_t stop = time.find("(");
1335
1336 // If there is a stop position then set length to stop
1337 if (stop != std::string::npos) {
1338 length = stop;
1339 }
1340
1341 // Reduce length by start
1342 if (start != std::string::npos) {
1343 length -= start;
1344 }
1345
1346 // Get substring containing the time value
1347 std::string value = time.substr(start, length);
1348
1349 // Convert value into double precision
1350 double result = gammalib::todouble(value);
1351
1352 // Return result
1353 return result;
1354}
1355
1356
1357/***********************************************************************//**
1358 * @brief Extract time system from time string
1359 *
1360 * @param[in] time Time string.
1361 * @return Time system.
1362 *
1363 * Extracts the time system from a time string. Valid time systems are:
1364 *
1365 * "(TT)" (TT system)
1366 * "(UTC)" (UTC system)
1367 * "(TAI)" (TAI system)
1368 *
1369 * If no time system is found a blank string is returned.
1370 ***************************************************************************/
1371std::string GTime::extract_timesys(const std::string& time) const
1372{
1373 // Initialise time system with blank string
1374 std::string timesys = "";
1375
1376 // Strip any whitespace from string and convert it to upper case
1377 std::string str = gammalib::toupper(gammalib::strip_whitespace(time));
1378
1379 // Check for UTC
1380 if (str.find("(UTC)") != std::string::npos) {
1381 timesys = "UTC";
1382 }
1383 else if (str.find("(TAI)") != std::string::npos) {
1384 timesys = "TAI";
1385 }
1386 else if (str.find("(TT)") != std::string::npos) {
1387 timesys = "TT";
1388 }
1389
1390 // Return time system
1391 return timesys;
1392}
Exception handler interface definition.
Mathematical function definitions.
#define G_CONSTRUCT
Definition GModelPar.cpp:36
Time reference class interface definition.
#define G_UTC_GET
Definition GTime.cpp:49
const double jd_ref
JD of time=0.
Definition GTime.cpp:42
#define G_UTC
Definition GTime.cpp:48
#define G_SECS_GET
Definition GTime.cpp:46
const double mjd_ref
MJD of time=0.
Definition GTime.cpp:41
#define G_SECS_SET
Definition GTime.cpp:47
Time class interface definition.
Gammalib tools definition.
GChatter
Definition GTypemaps.hpp:33
@ SILENT
Definition GTypemaps.hpp:34
Implements a time reference.
double unitseconds(void) const
Return the time unit in seconds.
const double & mjdref(void) const
Return MJD reference (units: days)
const std::string & timeunit(void) const
Return time unit.
const std::string & timeref(void) const
Return time reference.
const std::string & timesys(void) const
Return time system.
Time class.
Definition GTime.hpp:55
void clear(void)
Clear time.
Definition GTime.cpp:252
virtual ~GTime(void)
Destructor.
Definition GTime.cpp:200
void copy_members(const GTime &time)
Copy class members.
Definition GTime.cpp:1230
std::string extract_timesys(const std::string &time) const
Extract time system from time string.
Definition GTime.cpp:1371
double extract_timeval(const std::string &time) const
Extract time value from time string.
Definition GTime.cpp:1329
double leap_seconds(void) const
Return number of leap seconds for current time.
Definition GTime.hpp:181
double mjd(void) const
Return time in Modified Julian Days (TT)
Definition GTime.cpp:320
GTimeReference reference(void) const
Returns native time reference.
Definition GTime.cpp:1170
bool is_leap_year(const int &year) const
Signals if year is a leap year.
Definition GTime.hpp:210
double days(void) const
Return time in days in native reference (TT)
Definition GTime.cpp:400
int days_in_year(const int &year) const
Returns number of days in year.
Definition GTime.hpp:225
double gmst(void) const
Return Greenwich mean sidereal time in hours in a day.
Definition GTime.cpp:593
std::string print(const GChatter &chatter=NORMAL) const
Print time.
Definition GTime.cpp:1188
double gast(void) const
Return Greenwich apparent sidereal time in hours in a day.
Definition GTime.cpp:616
double m_time
Time in seconds in native reference (TT)
Definition GTime.hpp:134
double convert(const GTimeReference &ref) const
Return time in specified reference.
Definition GTime.cpp:698
std::string utc(const int &precision=0) const
Return time as string in UTC time system.
Definition GTime.cpp:465
double lmst(const double &geolon) const
Return local mean sidereal time in hours in a day.
Definition GTime.cpp:656
double last(const double &geolon) const
Return local apparent sidereal time in hours in a day.
Definition GTime.cpp:677
void init_members(void)
Initialise class members.
Definition GTime.cpp:1215
void set(const double &time, const GTimeReference &ref)
Set time given in specified reference.
Definition GTime.cpp:1005
GTime * clone(void) const
Clone time.
Definition GTime.cpp:270
double jd(void) const
Return time in Julian Days (TT)
Definition GTime.cpp:284
GTime(void)
Void constructor.
Definition GTime.cpp:67
void free_members(void)
Delete class members.
Definition GTime.cpp:1243
GTime & operator=(const GTime &time)
Assignment operator.
Definition GTime.cpp:222
void now(void)
Set time to current time.
Definition GTime.cpp:1126
double julian_epoch(void) const
Return Julian epoch in native reference (TT)
Definition GTime.cpp:425
const double & secs(void) const
Return time in seconds in native reference (TT)
Definition GTime.hpp:156
std::string str(const unsigned short int &value)
Convert unsigned short integer value into string.
Definition GTools.cpp:508
double todouble(const std::string &arg)
Convert string into double precision value.
Definition GTools.cpp:945
std::string tolower(const std::string &s)
Convert string to lower case.
Definition GTools.cpp:974
const double sec2day
Definition GTools.hpp:50
std::string strip_whitespace(const std::string &arg)
Strip leading and trailing whitespace from string.
Definition GTools.cpp:99
const double deg2rad
Definition GMath.hpp:43
const double tai2tt
Definition GTools.hpp:51
const double sec_in_day
Definition GTools.hpp:49
std::string toupper(const std::string &s)
Convert string to upper case.
Definition GTools.cpp:960