HOPS
HOPS class reference
MHO_Clock.hh
Go to the documentation of this file.
1 #ifndef MHO_Clock_HH__
2 #define MHO_Clock_HH__
3 
4 #include <chrono>
5 #include <iomanip>
6 #include <math.h>
7 #include <sstream>
8 #include <string>
9 
10 //these can someday be replaced with STL versions in C++20
11 #include "date/date.h"
12 #include "date/tz.h"
13 
14 #include "MHO_Message.hh"
15 #include "MHO_Tokenizer.hh"
16 #include "legacy_hops_date.hh"
17 
18 #define J2000_TAI_EPOCH "2000-01-01 11:59:27.816"
19 #define ISO8601_UTC_FORMAT "%FT%TZ"
20 #define HOPS_TIMESTAMP_PREFIX "HOPS-J2000"
21 #define HOPS_TIME_DELIM "|"
22 #define HOPS_TIME_UNIT "ns"
23 #define NANOSEC_TO_SEC 1e-9
24 #define SEC_TO_NANOSEC 1000000000
25 #define JD_TO_SEC 86400.0
26 #define MINUTE_TO_SEC 60.0
27 #define HOUR_TO_SEC 3600.0
28 
29 namespace hops
30 {
31 
43 {
44  public:
45  using duration = std::chrono::nanoseconds;
46  using rep = duration::rep;
47  using period = duration::period;
48  using time_point = std::chrono::time_point< hops_clock, std::chrono::nanoseconds >;
49  static const bool is_steady = false;
50 
57  static time_point now();
58 
65  template< typename Duration >
66  static std::chrono::time_point< date::utc_clock, typename std::common_type< Duration, std::chrono::nanoseconds >::type >
67  to_utc(const std::chrono::time_point< hops_clock, Duration >&) NOEXCEPT;
68 
75  template< typename Duration >
76  static std::chrono::time_point< hops_clock, typename std::common_type< Duration, std::chrono::nanoseconds >::type >
77  from_utc(const std::chrono::time_point< date::utc_clock, Duration >&) NOEXCEPT;
78 
85  template< typename Duration >
86  static std::chrono::time_point< date::tai_clock, typename std::common_type< Duration, std::chrono::nanoseconds >::type >
87  to_tai(const std::chrono::time_point< hops_clock, Duration >&) NOEXCEPT;
88 
95  template< typename Duration >
96  static std::chrono::time_point< hops_clock, typename std::common_type< Duration, std::chrono::nanoseconds >::type >
97  from_tai(const std::chrono::time_point< date::tai_clock, Duration >&) NOEXCEPT;
98 
105  template< typename Duration >
106  static std::chrono::time_point< date::gps_clock, typename std::common_type< Duration, std::chrono::nanoseconds >::type >
107  to_gps(const std::chrono::time_point< hops_clock, Duration >&) NOEXCEPT;
108 
115  template< typename Duration >
116  static std::chrono::time_point< hops_clock, typename std::common_type< Duration, std::chrono::nanoseconds >::type >
117  from_gps(const std::chrono::time_point< date::gps_clock, Duration >&) NOEXCEPT;
118 
125  template< typename Duration >
126  static std::chrono::time_point< std::chrono::system_clock,
127  typename std::common_type< Duration, std::chrono::nanoseconds >::type >
128  to_sys(const std::chrono::time_point< hops_clock, Duration >&) NOEXCEPT;
129 
136  template< typename Duration >
137  static std::chrono::time_point< hops_clock, typename std::common_type< Duration, std::chrono::nanoseconds >::type >
138  from_sys(const std::chrono::time_point< std::chrono::system_clock, Duration >&) NOEXCEPT;
139 
146  template< typename Duration >
147  static std::chrono::time_point< date::local_t, typename std::common_type< Duration, std::chrono::nanoseconds >::type >
148  to_local(const std::chrono::time_point< hops_clock, Duration >&) NOEXCEPT;
149 
156  template< typename Duration >
157  static std::chrono::time_point< hops_clock, typename std::common_type< Duration, std::chrono::nanoseconds >::type >
158  from_local(const std::chrono::time_point< date::local_t, Duration >&) NOEXCEPT;
159 
167  static time_point from_iso8601_format(const std::string& timestamp);
168 
176  static std::string to_iso8601_format(const time_point& tp);
177 
178 
186  static time_point from_hops_format(const std::string& timestamp);
187 
195  static std::string to_hops_format(const time_point& tp);
196 
197 
206 
215 
224  static time_point from_vdif_format(int& vdif_epoch, int& vdif_seconds);
225 
235  static void to_vdif_format(const time_point& tp, int& vdif_epoch, int& vdif_second);
236 
246  static time_point from_mjd(const time_point& mjd_epoch, const double& epoch_offset, const double& mjd);
247 
257  static double to_mjd(const time_point& mjd_epoch, const double& epoch_offset, const time_point& tp);
258 
266  static time_point from_vex_format(const std::string& timestamp);
267 
276  static std::string to_vex_format(const time_point& tp, bool truncate_to_nearest_second = false);
277 
287  static time_point from_year_fpday(int year, double floating_point_days);
288 
298  static void to_year_fpday(const time_point& tp, int& year, double& floating_point_days);
299 
303  static date::utc_time< std::chrono::nanoseconds > get_hops_epoch_utc()
304  {
305  std::string frmt = "%F %T";
306  std::string j2000 = J2000_TAI_EPOCH;
307  date::tai_time< std::chrono::nanoseconds > j2000_tai_epoch;
308  std::istringstream ss(j2000);
309  std::istream stream(ss.rdbuf());
310  date::from_stream(stream, frmt.c_str(), j2000_tai_epoch);
311  return std::chrono::time_point_cast< std::chrono::nanoseconds >(date::tai_clock::to_utc(j2000_tai_epoch));
312  }
313 
318 
322  static std::chrono::seconds get_leap_seconds_between(const time_point& t_start, const time_point& t_end)
323  {
324  auto t_start_utc = to_utc(t_start);
325  auto t_end_utc = to_utc(t_end);
326  auto lp_info0 = date::get_leap_second_info(t_start_utc);
327  auto lp_info1 = date::get_leap_second_info(t_end_utc);
328  int delta = lp_info1.elapsed.count() - lp_info0.elapsed.count();
329  return std::chrono::seconds(delta);
330  }
331 
332  private:
333 
334  static date::days day_of_year(date::sys_days sd)
335  {
336  using namespace date;
337  auto y = date::year_month_day{sd}.year();
338  return sd - date::sys_days{y / jan / 0};
339  }
340 
341  static date::sys_days get_year_month_day(date::year y, date::days ord_day)
342  {
343  using namespace date;
344  return date::sys_days{y / jan / 0} + ord_day;
345  }
346 
347  struct vex_date
348  {
349  int year;
350  int day_of_year;
351  int hours;
352  int minutes;
353  double seconds;
354  };
355 
356  static vex_date extract_vex_date(const std::string& timestamp);
357 
358  static std::string vex_date_to_iso8601_string(vex_date vdate);
359 
360  static vex_date vex_date_from_legacy(const legacy_hops_date& legacy_date);
361 
362  static std::string remove_trailing_zeros(std::string value)
363  {
364  std::size_t nzeros_on_end = 0;
365  for(auto rit = value.rbegin(); rit != value.rend(); rit++)
366  {
367  if(*rit != '0')
368  {
369  break;
370  }
371  nzeros_on_end++;
372  }
373  std::size_t useful_length = value.size() - nzeros_on_end;
374  std::string ret_val;
375  for(std::size_t i = 0; i < useful_length; i++)
376  {
377  ret_val.push_back(value[i]);
378  }
379  return ret_val;
380  }
381 };
382 
386 template< class Duration > using hops_time = std::chrono::time_point< hops_clock, Duration >;
387 
394 template< class Duration >
395 inline date::utc_time< typename std::common_type< Duration, std::chrono::nanoseconds >::type >
397 {
398 
399  using CD = typename std::common_type< Duration, std::chrono::nanoseconds >::type;
400  date::utc_time< std::chrono::nanoseconds > hops_epoch_start = get_hops_epoch_utc();
401  return date::utc_time< CD >(t.time_since_epoch() + hops_epoch_start.time_since_epoch());
402 }
403 
410 template< class Duration >
412 hops_clock::from_utc(const date::utc_time< Duration >& t) NOEXCEPT
413 {
414  using CD = typename std::common_type< Duration, std::chrono::nanoseconds >::type;
415  date::utc_time< std::chrono::nanoseconds > hops_epoch_start = get_hops_epoch_utc();
416  return hops_time< CD >(t.time_since_epoch() - hops_epoch_start.time_since_epoch());
417 }
418 
425 template< class Duration >
426 inline date::tai_time< typename std::common_type< Duration, std::chrono::nanoseconds >::type >
428 {
429  return date::tai_clock::from_utc(to_utc(t));
430 }
431 
438 template< class Duration >
440 hops_clock::from_tai(const date::tai_time< Duration >& t) NOEXCEPT
441 {
442  return from_utc(date::tai_clock::to_utc(t));
443 }
444 
451 template< class Duration >
452 inline date::gps_time< typename std::common_type< Duration, std::chrono::nanoseconds >::type >
454 {
455  return date::gps_clock::from_utc(to_utc(t));
456 }
457 
464 template< class Duration >
466 hops_clock::from_gps(const date::gps_time< Duration >& t) NOEXCEPT
467 {
468  return from_utc(date::gps_clock::to_utc(t));
469 }
470 
477 template< class Duration >
478 inline date::sys_time< typename std::common_type< Duration, std::chrono::nanoseconds >::type >
480 {
481  return date::utc_clock::to_sys(to_utc(t));
482 }
483 
490 template< class Duration >
492 hops_clock::from_sys(const date::sys_time< Duration >& t) NOEXCEPT
493 {
494  return from_utc(date::utc_clock::from_sys(t));
495 }
496 
503 {
504  return from_utc(date::utc_clock::now());
505 }
506 
513 template< class Duration >
514 inline date::local_time< typename std::common_type< Duration, std::chrono::nanoseconds >::type >
516 {
517  using CD = typename std::common_type< Duration, std::chrono::nanoseconds >::type;
518  date::utc_time< CD > hops_epoch_start = std::chrono::time_point_cast< CD >(get_hops_epoch_utc());
519  date::utc_time< CD > ut_time{t.time_since_epoch() +
520  std::chrono::time_point_cast< Duration >(hops_epoch_start).time_since_epoch()};
521  return date::utc_clock::to_local(ut_time);
522 }
523 
530 template< class Duration >
532 hops_clock::from_local(const date::local_time< Duration >& t) NOEXCEPT
533 {
534  using CD = typename std::common_type< Duration, std::chrono::nanoseconds >::type;
535  date::utc_time< CD > t2 = date::utc_clock::from_local(t);
536  date::utc_time< CD > hops_epoch_start = std::chrono::time_point_cast< CD >(get_hops_epoch_utc());
537  return hops_time< CD >{t2.time_since_epoch() -
538  std::chrono::time_point_cast< Duration >(hops_epoch_start).time_since_epoch()};
539 }
540 
552 template< class CharT, class Traits, class Duration >
553 std::basic_ostream< CharT, Traits >& to_stream(std::basic_ostream< CharT, Traits >& os, const CharT* fmt,
554  const hops_time< Duration >& t)
555 {
556  const std::string abbrev("HOPS");
557  CONSTDATA std::chrono::seconds offset{0};
558  return date::to_stream(os, fmt, hops_clock::to_local(t), &abbrev, &offset);
559 }
560 
574 template< class Duration, class CharT, class Traits, class Alloc = std::allocator< CharT > >
575 std::basic_istream< CharT, Traits >&
576 from_stream(std::basic_istream< CharT, Traits >& is, const CharT* fmt, hops_time< Duration >& tp,
577  std::basic_string< CharT, Traits, Alloc >* abbrev = nullptr, std::chrono::minutes* offset = nullptr)
578 {
579  date::local_time< Duration > lp;
580  from_stream(is, fmt, lp, abbrev, offset);
581  if(!is.fail())
582  tp = hops_clock::from_local(lp);
583  return is;
584 }
585 
586 template< class CharT, class Traits, class Duration >
587 std::basic_ostream< CharT, Traits >& operator<<(std::basic_ostream< CharT, Traits >& os, const hops_time< Duration >& t)
588 {
589  const CharT fmt[] = {'%', 'F', 'T', '%', 'T', 'Z', CharT{}};
590  return to_stream(os, fmt, t);
591 }
592 
599 inline hops_clock::time_point hops_clock::from_iso8601_format(const std::string& timestamp)
600 {
601  using namespace date;
602  using namespace std::chrono;
603  std::string frmt = ISO8601_UTC_FORMAT;
604  std::istringstream ss(timestamp);
605  std::istream tmp_stream(ss.rdbuf());
607  from_stream(tmp_stream, frmt.c_str(), hops_tp);
608  return hops_tp;
609 }
610 
617 inline std::string hops_clock::to_iso8601_format(const time_point& tp)
618 {
619  std::stringstream ss;
620  ss << tp;
621  return ss.str();
622 }
623 
630 inline hops_clock::time_point hops_clock::from_hops_format(const std::string& timestamp)
631 {
632  using namespace date;
633  using namespace std::chrono;
634 
635  MHO_Tokenizer tokenizer;
636  tokenizer.SetDelimiter(std::string(HOPS_TIME_DELIM));
637  std::vector< std::string > tokens;
638  tokenizer.SetString(&timestamp);
639  tokenizer.GetTokens(&tokens);
640  if(tokens.size() == 3)
641  {
642  std::string hops_prefix = tokens[0];
643  std::string unit = tokens[1];
644  std::string nanosecond_count = tokens[2];
645  if(hops_prefix == std::string(HOPS_TIMESTAMP_PREFIX) && unit == std::string(HOPS_TIME_UNIT))
646  {
647  std::stringstream ss;
648  ss << nanosecond_count;
649  int64_t ns;
650  ss >> ns;
651  return time_point(std::chrono::nanoseconds(ns));
652  }
653  }
654  msg_error("utility", "hops timestamp string not understood or supported, returning epoch start. " << eom);
655  return time_point(std::chrono::nanoseconds(0));
656 }
657 
664 inline std::string hops_clock::to_hops_format(const time_point& tp)
665 {
666  std::stringstream ss;
667  ss << HOPS_TIMESTAMP_PREFIX;
668  ss << HOPS_TIME_DELIM;
669  ss << HOPS_TIME_UNIT;
670  ss << HOPS_TIME_DELIM;
671  ss << tp.time_since_epoch().count();
672  return ss.str();
673 }
674 
676 {
677  vex_date vdate = vex_date_from_legacy(ldate);
678  std::string vex_as_iso8601 = vex_date_to_iso8601_string(vdate);
679  return hops_clock::from_iso8601_format(vex_as_iso8601);
680 }
681 
683 {
684  using namespace date;
685  using namespace std::chrono;
686 
687  //convert the time point to sys time, and extract the date
688  auto sys_tp = hops_clock::to_sys(tp);
689  auto dp = date::sys_days(floor< date::days >(sys_tp));
690 
691  //get all of the date information
692  date::year_month_day ymd{dp};
693  auto year = ymd.year();
694 
695  //get the ordinal day of the year
696  auto ordinal_day = day_of_year(dp);
697 
698  //get the time
699  date::hh_mm_ss< std::chrono::nanoseconds > time{floor< std::chrono::nanoseconds >(sys_tp - dp)};
700  auto hours = time.hours();
701  auto mins = time.minutes();
702  auto secs = time.seconds();
703  auto nanos = time.subseconds();
704 
705  legacy_hops_date ldate;
706  ldate.year = (int)year;
707  ldate.day = ordinal_day.count();
708  ldate.hour = hours.count();
709  ldate.minute = mins.count();
710  //note there may be loss of precision when converting to/from the actual legacy struct (single precision)
711  ldate.second = (double)secs.count() + ((double)(nanos.count())) * NANOSEC_TO_SEC;
712 
713  return ldate;
714 }
715 
716 
717 //needed for ad_hoc flag files (time-stamps are given in floating-point days)
718 inline hops_clock::time_point hops_clock::from_year_fpday(int year, double floating_point_days)
719 {
720  int integer_days = (int) floating_point_days;
721  double fractional_day = floating_point_days - integer_days;
722  int integer_hours = (int) 24*fractional_day;
723  double fractional_hour = 24*fractional_day - integer_hours;
724  int integer_minutes = (int) 60*fractional_hour;
725  double fractional_seconds = (60*fractional_hour - integer_minutes)*60;
726 
727  //we co-opt the legacy date format to handle this format
728  legacy_hops_date ldate;
729  ldate.year = (short) year;
730  ldate.day = (short) integer_days + 1; //note: ordinal day count starts at 1
731  ldate.hour = (short) integer_hours;
732  ldate.minute = (short) integer_minutes;
733  ldate.second = fractional_seconds;
734 
735  return from_legacy_hops_date(ldate);
736 }
737 
738 inline void hops_clock::to_year_fpday(const hops_clock::time_point& tp, int& year, double& floating_point_days)
739 {
740  using namespace date;
741  using namespace std::chrono;
742 
743  //convert the time point to sys time, and extract the date
744  auto sys_tp = hops_clock::to_sys(tp);
745  auto dp = sys_days(floor< date::days >(sys_tp));
746 
747  //get all of the date information
748  year_month_day ymd{dp};
749  auto year_value = ymd.year();
750  //get the ordinal day of the year
751  auto ordinal_day = day_of_year(dp); //note: count starts at 1
752  int integer_days = ordinal_day.count() - 1;
753  //get the time and convert to fractional day
754  hh_mm_ss< std::chrono::nanoseconds > time{floor< std::chrono::nanoseconds >(sys_tp - dp)};
755  int ihours = time.hours().count();
756  int imins = time.minutes().count();
757  int isecs = time.seconds().count();
758  int inanos = time.subseconds().count();
759 
760  double frac_day = (inanos*NANOSEC_TO_SEC + isecs + MINUTE_TO_SEC*imins + HOUR_TO_SEC*ihours)/(JD_TO_SEC);
761  floating_point_days = integer_days + frac_day;
762 }
763 
764 
765 inline hops_clock::time_point hops_clock::from_mjd(const time_point& mjd_epoch, const double& epoch_offset, const double& mjd)
766 {
767  double delta = (mjd - epoch_offset);
768  delta *= JD_TO_SEC;
769  std::chrono::duration< double > duration_seconds(delta);
770 
771  auto mjd_epoch_utc = to_utc(mjd_epoch);
772  auto utc_time_point = mjd_epoch_utc + std::chrono::duration_cast< std::chrono::nanoseconds >(duration_seconds);
773  auto hops_time_point = from_utc(utc_time_point);
774  return hops_time_point;
775 }
776 
777 inline double hops_clock::to_mjd(const time_point& mjd_epoch, const double& epoch_offset, const time_point& tp)
778 {
779  auto mjd_epoch_utc = to_utc(mjd_epoch);
780  auto tp_utc = to_utc(tp);
781 
782  double delta = (tp_utc - mjd_epoch_utc).count();
783  delta *= NANOSEC_TO_SEC; //convert to seconds
784  delta /= JD_TO_SEC; //convert to days
785  delta += epoch_offset; //subtract epoch offset
786  return delta;
787 }
788 
789 inline hops_clock::time_point hops_clock::from_vex_format(const std::string& timestamp)
790 {
791  vex_date vdate = hops_clock::extract_vex_date(timestamp);
792  //convert the vex date info to an ISO-8601-style year-month-day type format
793  std::string vex_as_iso8601 = vex_date_to_iso8601_string(vdate);
794  return hops_clock::from_iso8601_format(vex_as_iso8601);
795 }
796 
797 inline std::string hops_clock::to_vex_format(const time_point& tp, bool truncate_to_nearest_second)
798 {
799  using namespace date;
800  using namespace std::chrono;
801 
802  //convert the time point to sys time, and extract the date
803  auto sys_tp = hops_clock::to_sys(tp);
804  auto dp = sys_days(floor< date::days >(sys_tp));
805 
806  //get all of the date information
807  year_month_day ymd{dp};
808  auto year = ymd.year();
809  // auto month = ymd.month();
810  // auto day = ymd.day();
811 
812  //get the ordinal day of the year
813  auto ordinal_day = day_of_year(dp);
814 
815  //get the time
816  hh_mm_ss< std::chrono::nanoseconds > time{floor< std::chrono::nanoseconds >(sys_tp - dp)};
817  auto hours = time.hours();
818  auto mins = time.minutes();
819  auto secs = time.seconds();
820  auto nanos = time.subseconds();
821 
822  //we need to make sure that year, day-of-year, hour, minute, and integer sec
823  //are all preprended with the proper number of zeros
824 
825  std::stringstream ss;
826  ss << year;
827  ss << "y";
828  ss << std::setfill('0') << std::setw(3) << ordinal_day.count();
829  ss << "d";
830  ss << std::setfill('0') << std::setw(2) << hours.count();
831  ss << "h";
832  ss << std::setfill('0') << std::setw(2) << mins.count();
833  ss << "m";
834  ss << std::setfill('0') << std::setw(2) << secs.count();
835 
836  if(!truncate_to_nearest_second)
837  {
838  std::stringstream nss;
839  nss << std::setfill('0') << std::setw(9) << nanos.count();
840  std::string snano_sec;
841  nss >> snano_sec;
842  std::string trimmed_nanosec = remove_trailing_zeros(snano_sec);
843  if(trimmed_nanosec.size() != 0)
844  {
845  ss << ".";
846  ss << trimmed_nanosec;
847  }
848  }
849  ss << "s";
850 
851  return ss.str();
852 }
853 
854 inline void hops_clock::to_vdif_format(const time_point& tp, int& vdif_epoch, int& vdif_seconds)
855 {
856  using namespace date;
857  using namespace std::chrono;
858 
859  //convert the time point to sys time, and extract the date
860  auto sys_tp = hops_clock::to_sys(tp);
861  auto dp = sys_days(floor< date::days >(sys_tp));
862 
863  //get all of the date information so we can figure out the epoch
864  year_month_day ymd{dp};
865  auto year = ymd.year();
866  auto month = ymd.month();
867  auto day = ymd.day();
868 
869  //(we have two 6 month epochs per year, and count from start of century)
870  int iyear = static_cast< int >(year);
871  unsigned int imonth = static_cast< unsigned int >(month);
872  int epoch = (iyear % 100) * 2;
873 
874  //now figure out if we are using the Jan 1st epoch, or the July 1st epoch
875  if(imonth < 7)
876  {
877  imonth = 1;
878  }
879  else
880  {
881  epoch += 1;
882  imonth = 7;
883  }
884  //set the day to the first of the month
885  day = date::day(1);
886  int hours = 0;
887  int minutes = 0;
888  int integer_sec = 0;
889 
890  //now figure out the epoch date
891  //may want to eliminate string conversion in favor of something faster
892  std::stringstream ss;
893  ss << iyear;
894  ss << "-";
895  ss << std::setfill('0') << std::setw(2) << imonth;
896  ss << "-";
897  ss << std::setfill('0') << std::setw(2) << static_cast< unsigned int >(day);
898  ss << "T";
899  ss << std::setfill('0') << std::setw(2) << hours;
900  ss << ":";
901  ss << std::setfill('0') << std::setw(2) << minutes;
902  ss << ":";
903  ss << std::setfill('0') << std::setw(2) << integer_sec;
904  ss << "Z";
905  std::string epoch_iso8601 = ss.str();
906  auto epoch_tp = from_iso8601_format(epoch_iso8601);
907  int secs = std::chrono::duration_cast< std::chrono::seconds >(tp - epoch_tp).count();
908 
909  vdif_epoch = epoch;
910  vdif_seconds = secs;
911 }
912 
913 inline hops_clock::time_point hops_clock::from_vdif_format(int& vdif_epoch, int& vdif_seconds)
914 {
915  using namespace date;
916  using namespace std::chrono;
917 
918  int start_year = 2000;
919  int n_years = std::floor(vdif_epoch / 2);
920  int iyear = start_year + n_years;
921 
922  std::cout << "n_years = " << n_years << " iyear = " << iyear << std::endl;
923 
924  unsigned int imonth = 1;
925  if(vdif_epoch % 2 == 1)
926  {
927  imonth = 7;
928  } //second half of the year
929  unsigned int iday = 1;
930  int hours = 0;
931  int minutes = 0;
932  int integer_sec = 0;
933 
934  //now figure out the epoch date
935  //may want to eliminate string conversion in favor of something faster
936  std::stringstream ss;
937  ss << iyear;
938  ss << "-";
939  ss << std::setfill('0') << std::setw(2) << imonth;
940  ss << "-";
941  ss << std::setfill('0') << std::setw(2) << iday;
942  ss << "T";
943  ss << std::setfill('0') << std::setw(2) << hours;
944  ss << ":";
945  ss << std::setfill('0') << std::setw(2) << minutes;
946  ss << ":";
947  ss << std::setfill('0') << std::setw(2) << integer_sec;
948  ss << "Z";
949  std::string epoch_iso8601 = ss.str();
950  std::cout << "epoch = " << epoch_iso8601 << std::endl;
951  auto epoch_tp = from_iso8601_format(epoch_iso8601);
952  auto tp = epoch_tp + std::chrono::seconds(vdif_seconds);
953  return tp;
954 }
955 
956 inline hops_clock::vex_date hops_clock::extract_vex_date(const std::string& timestamp)
957 {
958  vex_date vdate;
959  if(timestamp.size() == 0)
960  {
961  msg_error("utilities", "cannot extract vex date from empty string." << eom);
962  return vdate;
963  }
964 
965  MHO_Tokenizer tokenizer;
966  std::vector< std::string > tokens;
967  std::stringstream ss;
968  std::string rest;
969  std::string syear, sord_day, shour, smin, ssec;
970 
971  tokenizer.SetDelimiter(std::string("y"));
972  tokenizer.SetString(&timestamp);
973  tokenizer.GetTokens(&tokens);
974 
975  syear = tokens[0];
976  ss << syear;
977  ss >> vdate.year;
978  rest = tokens[1];
979 
980  tokenizer.SetDelimiter(std::string("d"));
981  tokenizer.SetString(&rest);
982  tokenizer.GetTokens(&tokens);
983 
984  sord_day = tokens[0];
985  ss.str(std::string());
986  ss.clear();
987  ss << sord_day;
988  ss >> vdate.day_of_year;
989  rest = tokens[1];
990 
991  tokenizer.SetDelimiter(std::string("h"));
992  tokenizer.SetString(&rest);
993  tokenizer.GetTokens(&tokens);
994 
995  shour = tokens[0];
996  ss.str(std::string());
997  ss.clear();
998  ss << shour;
999  ss >> vdate.hours;
1000  rest = tokens[1];
1001 
1002  tokenizer.SetDelimiter(std::string("m"));
1003  tokenizer.SetString(&rest);
1004  tokenizer.GetTokens(&tokens);
1005 
1006  smin = tokens[0];
1007  ss.str(std::string());
1008  ss.clear();
1009  ss << smin;
1010  ss >> vdate.minutes;
1011  rest = tokens[1];
1012 
1013  tokenizer.SetDelimiter(std::string("s"));
1014  tokenizer.SetString(&rest);
1015  tokenizer.GetTokens(&tokens);
1016 
1017  ssec = tokens[0];
1018  ss.str(std::string());
1019  ss.clear();
1020  ss << std::setprecision(15) << ssec;
1021  ss >> vdate.seconds;
1022 
1023  return vdate;
1024 }
1025 
1026 inline std::string hops_clock::vex_date_to_iso8601_string(hops_clock::vex_date vdate)
1027 {
1028  using namespace date;
1029  using namespace std::chrono;
1030 
1031  std::stringstream ss;
1032  ss << vdate.year;
1033  ss << "-";
1034 
1035  date::year y(vdate.year);
1036  date::days ord_day(vdate.day_of_year);
1037  date::sys_days ymd = get_year_month_day(y, ord_day);
1038 
1039  //convert day-of-year to month-day
1040  auto month = date::year_month_day{ymd}.month();
1041  auto mday = date::year_month_day{ymd}.day();
1042  ss << std::setfill('0') << std::setw(2) << (unsigned)month;
1043  ss << "-";
1044  ss << std::setfill('0') << std::setw(2) << (unsigned)mday;
1045 
1046  ss << "T";
1047  ss << std::setfill('0') << std::setw(2) << vdate.hours;
1048  ss << ":";
1049  ss << std::setfill('0') << std::setw(2) << vdate.minutes;
1050  ss << ":";
1051 
1052  //nss << std::setprecision(9) << vdate.seconds;
1053 
1054  double intpart;
1055  double frac = modf(vdate.seconds, &intpart);
1056  int integer_sec = intpart;
1057 
1058  ss << std::setfill('0') << std::setw(2) << integer_sec;
1059 
1060  //now convert the fraction part into integer nano seconds
1061  int integer_nanosec = frac * SEC_TO_NANOSEC;
1062  std::stringstream nss;
1063  nss << integer_nanosec;
1064  std::string nanoseconds_value = nss.str();
1065  std::string trimmed_int_nanosec = remove_trailing_zeros(nanoseconds_value);
1066  if(trimmed_int_nanosec.size() != 0)
1067  {
1068  ss << ".";
1069  ss << trimmed_int_nanosec;
1070  }
1071  ss << "Z";
1072  return ss.str();
1073 }
1074 
1075 inline hops_clock::vex_date hops_clock::vex_date_from_legacy(const legacy_hops_date& legacy_date)
1076 {
1077  hops_clock::vex_date vdate;
1078  vdate.year = legacy_date.year;
1079  vdate.day_of_year = legacy_date.day;
1080  vdate.hours = legacy_date.hour;
1081  vdate.minutes = legacy_date.minute;
1082  vdate.seconds = legacy_date.second;
1083  return vdate;
1084 }
1085 
1086 } // namespace hops
1087 
1088 #endif
#define ISO8601_UTC_FORMAT
Definition: MHO_Clock.hh:19
#define J2000_TAI_EPOCH
Definition: MHO_Clock.hh:18
#define MINUTE_TO_SEC
Definition: MHO_Clock.hh:26
#define SEC_TO_NANOSEC
Definition: MHO_Clock.hh:24
#define HOPS_TIMESTAMP_PREFIX
Definition: MHO_Clock.hh:20
#define HOPS_TIME_DELIM
Definition: MHO_Clock.hh:21
#define NANOSEC_TO_SEC
Definition: MHO_Clock.hh:23
#define HOPS_TIME_UNIT
Definition: MHO_Clock.hh:22
#define JD_TO_SEC
Definition: MHO_Clock.hh:25
#define HOUR_TO_SEC
Definition: MHO_Clock.hh:27
#define msg_error(xKEY, xCONTENT)
Definition: MHO_Message.hh:244
Class MHO_Tokenizer.
Definition: MHO_Tokenizer.hh:24
void SetString(const std::string *aString)
Definition: MHO_Tokenizer.cc:65
void GetTokens(std::vector< std::string > *tokens)
Definition: MHO_Tokenizer.cc:75
void SetDelimiter(const std::string &aDelim)
Definition: MHO_Tokenizer.cc:70
a clock for hops-time stamps, measures time in (UTC) nanoseconds since J2000 epoch....
Definition: MHO_Clock.hh:43
static date::utc_time< std::chrono::nanoseconds > get_hops_epoch_utc()
returns the hops_clock epoch as a utc_time time_point
Definition: MHO_Clock.hh:303
static time_point get_hops_epoch()
returns the hops_clock epoch as a hops_clock time_point
Definition: MHO_Clock.hh:317
duration::period period
Definition: MHO_Clock.hh:47
static void to_vdif_format(const time_point &tp, int &vdif_epoch, int &vdif_second)
Converts a hops_clock time_point to a VDIF (epoch, second) timestamp.
Definition: MHO_Clock.hh:854
static std::chrono::time_point< date::tai_clock, typename std::common_type< Duration, std::chrono::nanoseconds >::type > to_tai(const std::chrono::time_point< hops_clock, Duration > &) NOEXCEPT
Converts a time point from hops_clock to TAI (International Atomic Time).
static time_point now()
Returns current time as a time_point using hops_clock's epoch.
Definition: MHO_Clock.hh:502
std::chrono::time_point< hops_clock, std::chrono::nanoseconds > time_point
Definition: MHO_Clock.hh:48
static std::chrono::time_point< std::chrono::system_clock, typename std::common_type< Duration, std::chrono::nanoseconds >::type > to_sys(const std::chrono::time_point< hops_clock, Duration > &) NOEXCEPT
Converts a time point from hops_clock to system clock.
static std::chrono::time_point< date::local_t, typename std::common_type< Duration, std::chrono::nanoseconds >::type > to_local(const std::chrono::time_point< hops_clock, Duration > &) NOEXCEPT
Converts a global time point to local time.
static double to_mjd(const time_point &mjd_epoch, const double &epoch_offset, const time_point &tp)
Converts a hops_clock time_point to a Modified Julian date (floating point day) timestamp,...
Definition: MHO_Clock.hh:777
static std::string to_iso8601_format(const time_point &tp)
Converts a time_point to ISO8601 formatted string.
Definition: MHO_Clock.hh:617
static time_point from_year_fpday(int year, double floating_point_days)
Converts a year + floating point day since start of the year to a hops_clock time_point,...
Definition: MHO_Clock.hh:718
static std::chrono::time_point< hops_clock, typename std::common_type< Duration, std::chrono::nanoseconds >::type > from_tai(const std::chrono::time_point< date::tai_clock, Duration > &) NOEXCEPT
Converts a TAI time point to UTC and returns the corresponding Hops clock time.
std::chrono::nanoseconds duration
Definition: MHO_Clock.hh:45
static std::chrono::time_point< hops_clock, typename std::common_type< Duration, std::chrono::nanoseconds >::type > from_sys(const std::chrono::time_point< std::chrono::system_clock, Duration > &) NOEXCEPT
Converts a system time point to UTC and returns the corresponding hops clock time.
static time_point from_hops_format(const std::string &timestamp)
Converts a timestamp string in HOPS format to a time_point object.
Definition: MHO_Clock.hh:630
static time_point from_iso8601_format(const std::string &timestamp)
Converts an ISO8601 formatted timestamp string to a hops_clock time_point object.
Definition: MHO_Clock.hh:599
duration::rep rep
Definition: MHO_Clock.hh:46
static time_point from_vdif_format(int &vdif_epoch, int &vdif_seconds)
Converts a VDIF (epoch, second) timestamp to a hops_clock time_point.
Definition: MHO_Clock.hh:913
static std::string to_vex_format(const time_point &tp, bool truncate_to_nearest_second=false)
Converts a hops_clock time_point to VEX-style formatted string (e.g. 2019y106d18h30m15s)
Definition: MHO_Clock.hh:797
static std::string to_hops_format(const time_point &tp)
Converts a time_point to HOPS format string.
Definition: MHO_Clock.hh:664
static time_point from_vex_format(const std::string &timestamp)
Converts a VEX-style formatted string (e.g. 2019y106d18h30m15s) to a hops_clock time_point.
Definition: MHO_Clock.hh:789
static std::chrono::time_point< hops_clock, typename std::common_type< Duration, std::chrono::nanoseconds >::type > from_gps(const std::chrono::time_point< date::gps_clock, Duration > &) NOEXCEPT
Converts GPS time to Hops clock time.
static std::chrono::seconds get_leap_seconds_between(const time_point &t_start, const time_point &t_end)
calculates the number of leap seconds inserted between two hops time points (UTC based clock)
Definition: MHO_Clock.hh:322
static std::chrono::time_point< date::gps_clock, typename std::common_type< Duration, std::chrono::nanoseconds >::type > to_gps(const std::chrono::time_point< hops_clock, Duration > &) NOEXCEPT
Converts a time point to GPS clock time.
static const bool is_steady
Definition: MHO_Clock.hh:49
static legacy_hops_date to_legacy_hops_date(const time_point &tp)
Converts a hops_clock time_point to a legacy hops data struct.
Definition: MHO_Clock.hh:682
static void to_year_fpday(const time_point &tp, int &year, double &floating_point_days)
Converts a hops_clock time_point to a floating point day since start of the year needed for ad_hoc fl...
Definition: MHO_Clock.hh:738
static time_point from_legacy_hops_date(legacy_hops_date &ldate)
Converts a legacy hops data struct to a hops_clock time_point.
Definition: MHO_Clock.hh:675
static std::chrono::time_point< hops_clock, typename std::common_type< Duration, std::chrono::nanoseconds >::type > from_utc(const std::chrono::time_point< date::utc_clock, Duration > &) NOEXCEPT
Converts UTC time point to hops_clock time point.
static std::chrono::time_point< hops_clock, typename std::common_type< Duration, std::chrono::nanoseconds >::type > from_local(const std::chrono::time_point< date::local_t, Duration > &) NOEXCEPT
Calculates time difference between input local time and Hops epoch in UTC.
static time_point from_mjd(const time_point &mjd_epoch, const double &epoch_offset, const double &mjd)
Converts a Modified Julian date (floating point epoch and day) timestamp to a hops_clock time_point.
Definition: MHO_Clock.hh:765
static std::chrono::time_point< date::utc_clock, typename std::common_type< Duration, std::chrono::nanoseconds >::type > to_utc(const std::chrono::time_point< hops_clock, Duration > &) NOEXCEPT
Converts a time point to UTC using hops_clock and Duration.
short day
Definition: mk4_typedefs.h:17
short year
Definition: mk4_typedefs.h:16
Definition: mk4_typedefs.h:15
t
Definition: picking_aedit.py:14
Definition: MHO_ChannelLabeler.hh:17
std::basic_ostream< CharT, Traits > & operator<<(std::basic_ostream< CharT, Traits > &os, const hops_time< Duration > &t)
Definition: MHO_Clock.hh:587
short hour
Definition: legacy_hops_date.hh:20
std::basic_istream< CharT, Traits > & from_stream(std::basic_istream< CharT, Traits > &is, const CharT *fmt, hops_time< Duration > &tp, std::basic_string< CharT, Traits, Alloc > *abbrev=nullptr, std::chrono::minutes *offset=nullptr)
Reads time and abbreviation from stream using given format, updates hops_time if successful.
Definition: MHO_Clock.hh:576
short minute
Definition: legacy_hops_date.hh:21
short day
Definition: legacy_hops_date.hh:19
std::chrono::time_point< hops_clock, Duration > hops_time
Class hops_time.
Definition: MHO_Clock.hh:386
std::basic_ostream< CharT, Traits > & to_stream(std::basic_ostream< CharT, Traits > &os, const CharT *fmt, const hops_time< Duration > &t)
Converts hops_time to stream format using given fmt and outputs to os.
Definition: MHO_Clock.hh:553
double second
Definition: legacy_hops_date.hh:22
short year
Definition: legacy_hops_date.hh:18
A struct to avoid name collisions between the mk4utils 'data' struct and the 'date' header library.
Definition: legacy_hops_date.hh:17
struct token_struct * tokens
Definition: parse_control_file.c:26
Definition: vex.h:175