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 
185  static time_point from_hops_format(const std::string& timestamp);
186 
194  static std::string to_hops_format(const time_point& tp);
195 
204 
213 
222  static time_point from_vdif_format(int& vdif_epoch, int& vdif_seconds);
223 
233  static void to_vdif_format(const time_point& tp, int& vdif_epoch, int& vdif_second);
234 
244  static time_point from_mjd(const time_point& mjd_epoch, double epoch_offset, double mjd);
245 
255  static double to_mjd(const time_point& mjd_epoch, double epoch_offset, const time_point& tp);
256 
264  static time_point from_vex_format(const std::string& timestamp);
265 
274  static std::string to_vex_format(const time_point& tp, bool truncate_to_nearest_second = false);
275 
285  static time_point from_year_fpday(int year, double floating_point_days);
286 
296  static void to_year_fpday(const time_point& tp, int& year, double& floating_point_days);
297 
301  static date::utc_time< std::chrono::nanoseconds > get_hops_epoch_utc()
302  {
303  std::string frmt = "%F %T";
304  std::string j2000 = J2000_TAI_EPOCH;
305  date::tai_time< std::chrono::nanoseconds > j2000_tai_epoch;
306  std::istringstream ss(j2000);
307  std::istream stream(ss.rdbuf());
308  date::from_stream(stream, frmt.c_str(), j2000_tai_epoch);
309  return std::chrono::time_point_cast< std::chrono::nanoseconds >(date::tai_clock::to_utc(j2000_tai_epoch));
310  }
311 
316 
320  static std::chrono::seconds get_leap_seconds_between(const time_point& t_start, const time_point& t_end)
321  {
322  auto t_start_utc = to_utc(t_start);
323  auto t_end_utc = to_utc(t_end);
324  auto lp_info0 = date::get_leap_second_info(t_start_utc);
325  auto lp_info1 = date::get_leap_second_info(t_end_utc);
326  int delta = lp_info1.elapsed.count() - lp_info0.elapsed.count();
327  return std::chrono::seconds(delta);
328  }
329 
330  private:
331  static date::days day_of_year(date::sys_days sd)
332  {
333  using namespace date;
334  auto y = date::year_month_day{sd}.year();
335  return sd - date::sys_days{y / jan / 0};
336  }
337 
338  static date::sys_days get_year_month_day(date::year y, date::days ord_day)
339  {
340  using namespace date;
341  return date::sys_days{y / jan / 0} + ord_day;
342  }
343 
344  struct vex_date
345  {
346  int year;
347  int day_of_year;
348  int hours;
349  int minutes;
350  double seconds;
351  };
352 
353  static vex_date extract_vex_date(const std::string& timestamp);
354 
355  static std::string vex_date_to_iso8601_string(vex_date vdate);
356 
357  static vex_date vex_date_from_legacy(const legacy_hops_date& legacy_date);
358 
359  static std::string remove_trailing_zeros(std::string value)
360  {
361  std::size_t nzeros_on_end = 0;
362  for(auto rit = value.rbegin(); rit != value.rend(); rit++)
363  {
364  if(*rit != '0')
365  {
366  break;
367  }
368  nzeros_on_end++;
369  }
370  std::size_t useful_length = value.size() - nzeros_on_end;
371  std::string ret_val;
372  for(std::size_t i = 0; i < useful_length; i++)
373  {
374  ret_val.push_back(value[i]);
375  }
376  return ret_val;
377  }
378 };
379 
383 template< class Duration > using hops_time = std::chrono::time_point< hops_clock, Duration >;
384 
391 template< class Duration >
392 inline date::utc_time< typename std::common_type< Duration, std::chrono::nanoseconds >::type >
394 {
395 
396  using CD = typename std::common_type< Duration, std::chrono::nanoseconds >::type;
397  date::utc_time< std::chrono::nanoseconds > hops_epoch_start = get_hops_epoch_utc();
398  return date::utc_time< CD >(t.time_since_epoch() + hops_epoch_start.time_since_epoch());
399 }
400 
407 template< class Duration >
409 hops_clock::from_utc(const date::utc_time< Duration >& t) NOEXCEPT
410 {
411  using CD = typename std::common_type< Duration, std::chrono::nanoseconds >::type;
412  date::utc_time< std::chrono::nanoseconds > hops_epoch_start = get_hops_epoch_utc();
413  return hops_time< CD >(t.time_since_epoch() - hops_epoch_start.time_since_epoch());
414 }
415 
422 template< class Duration >
423 inline date::tai_time< typename std::common_type< Duration, std::chrono::nanoseconds >::type >
425 {
426  return date::tai_clock::from_utc(to_utc(t));
427 }
428 
435 template< class Duration >
437 hops_clock::from_tai(const date::tai_time< Duration >& t) NOEXCEPT
438 {
439  return from_utc(date::tai_clock::to_utc(t));
440 }
441 
448 template< class Duration >
449 inline date::gps_time< typename std::common_type< Duration, std::chrono::nanoseconds >::type >
451 {
452  return date::gps_clock::from_utc(to_utc(t));
453 }
454 
461 template< class Duration >
463 hops_clock::from_gps(const date::gps_time< Duration >& t) NOEXCEPT
464 {
465  return from_utc(date::gps_clock::to_utc(t));
466 }
467 
474 template< class Duration >
475 inline date::sys_time< typename std::common_type< Duration, std::chrono::nanoseconds >::type >
477 {
478  return date::utc_clock::to_sys(to_utc(t));
479 }
480 
487 template< class Duration >
489 hops_clock::from_sys(const date::sys_time< Duration >& t) NOEXCEPT
490 {
491  return from_utc(date::utc_clock::from_sys(t));
492 }
493 
500 {
501  return from_utc(date::utc_clock::now());
502 }
503 
510 template< class Duration >
511 inline date::local_time< typename std::common_type< Duration, std::chrono::nanoseconds >::type >
513 {
514  using CD = typename std::common_type< Duration, std::chrono::nanoseconds >::type;
515  date::utc_time< CD > hops_epoch_start = std::chrono::time_point_cast< CD >(get_hops_epoch_utc());
516  date::utc_time< CD > ut_time{t.time_since_epoch() +
517  std::chrono::time_point_cast< Duration >(hops_epoch_start).time_since_epoch()};
518  return date::utc_clock::to_local(ut_time);
519 }
520 
527 template< class Duration >
529 hops_clock::from_local(const date::local_time< Duration >& t) NOEXCEPT
530 {
531  using CD = typename std::common_type< Duration, std::chrono::nanoseconds >::type;
532  date::utc_time< CD > t2 = date::utc_clock::from_local(t);
533  date::utc_time< CD > hops_epoch_start = std::chrono::time_point_cast< CD >(get_hops_epoch_utc());
534  return hops_time< CD >{t2.time_since_epoch() -
535  std::chrono::time_point_cast< Duration >(hops_epoch_start).time_since_epoch()};
536 }
537 
549 template< class CharT, class Traits, class Duration >
550 std::basic_ostream< CharT, Traits >& to_stream(std::basic_ostream< CharT, Traits >& os, const CharT* fmt,
551  const hops_time< Duration >& t)
552 {
553  const std::string abbrev("HOPS");
554  CONSTDATA std::chrono::seconds offset{0};
555  return date::to_stream(os, fmt, hops_clock::to_local(t), &abbrev, &offset);
556 }
557 
571 template< class Duration, class CharT, class Traits, class Alloc = std::allocator< CharT > >
572 std::basic_istream< CharT, Traits >&
573 from_stream(std::basic_istream< CharT, Traits >& is, const CharT* fmt, hops_time< Duration >& tp,
574  std::basic_string< CharT, Traits, Alloc >* abbrev = nullptr, std::chrono::minutes* offset = nullptr)
575 {
576  date::local_time< Duration > lp;
577  from_stream(is, fmt, lp, abbrev, offset);
578  if(!is.fail())
579  tp = hops_clock::from_local(lp);
580  return is;
581 }
582 
583 template< class CharT, class Traits, class Duration >
584 std::basic_ostream< CharT, Traits >& operator<<(std::basic_ostream< CharT, Traits >& os, const hops_time< Duration >& t)
585 {
586  const CharT fmt[] = {'%', 'F', 'T', '%', 'T', 'Z', CharT{}};
587  return to_stream(os, fmt, t);
588 }
589 
596 inline hops_clock::time_point hops_clock::from_iso8601_format(const std::string& timestamp)
597 {
598  using namespace date;
599  using namespace std::chrono;
600  std::string frmt = ISO8601_UTC_FORMAT;
601  std::istringstream ss(timestamp);
602  std::istream tmp_stream(ss.rdbuf());
604  from_stream(tmp_stream, frmt.c_str(), hops_tp);
605  return hops_tp;
606 }
607 
614 inline std::string hops_clock::to_iso8601_format(const time_point& tp)
615 {
616  std::stringstream ss;
617  ss << tp;
618  return ss.str();
619 }
620 
627 inline hops_clock::time_point hops_clock::from_hops_format(const std::string& timestamp)
628 {
629  using namespace date;
630  using namespace std::chrono;
631 
632  MHO_Tokenizer tokenizer;
633  tokenizer.SetDelimiter(std::string(HOPS_TIME_DELIM));
634  std::vector< std::string > tokens;
635  tokenizer.SetString(&timestamp);
636  tokenizer.GetTokens(&tokens);
637  if(tokens.size() == 3)
638  {
639  std::string hops_prefix = tokens[0];
640  std::string unit = tokens[1];
641  std::string nanosecond_count = tokens[2];
642  if(hops_prefix == std::string(HOPS_TIMESTAMP_PREFIX) && unit == std::string(HOPS_TIME_UNIT))
643  {
644  std::stringstream ss;
645  ss << nanosecond_count;
646  int64_t ns;
647  ss >> ns;
648  return time_point(std::chrono::nanoseconds(ns));
649  }
650  }
651  msg_error("utility", "hops timestamp string not understood or supported, returning epoch start. " << eom);
652  return time_point(std::chrono::nanoseconds(0));
653 }
654 
661 inline std::string hops_clock::to_hops_format(const time_point& tp)
662 {
663  std::stringstream ss;
664  ss << HOPS_TIMESTAMP_PREFIX;
665  ss << HOPS_TIME_DELIM;
666  ss << HOPS_TIME_UNIT;
667  ss << HOPS_TIME_DELIM;
668  ss << tp.time_since_epoch().count();
669  return ss.str();
670 }
671 
673 {
674  vex_date vdate = vex_date_from_legacy(ldate);
675  std::string vex_as_iso8601 = vex_date_to_iso8601_string(vdate);
676  return hops_clock::from_iso8601_format(vex_as_iso8601);
677 }
678 
680 {
681  using namespace date;
682  using namespace std::chrono;
683 
684  //convert the time point to sys time, and extract the date
685  auto sys_tp = hops_clock::to_sys(tp);
686  auto dp = date::sys_days(floor< date::days >(sys_tp));
687 
688  //get all of the date information
689  date::year_month_day ymd{dp};
690  auto year = ymd.year();
691 
692  //get the ordinal day of the year
693  auto ordinal_day = day_of_year(dp);
694 
695  //get the time
696  date::hh_mm_ss< std::chrono::nanoseconds > time{floor< std::chrono::nanoseconds >(sys_tp - dp)};
697  auto hours = time.hours();
698  auto mins = time.minutes();
699  auto secs = time.seconds();
700  auto nanos = time.subseconds();
701 
702  legacy_hops_date ldate;
703  ldate.year = (int)year;
704  ldate.day = ordinal_day.count();
705  ldate.hour = hours.count();
706  ldate.minute = mins.count();
707  //note there may be loss of precision when converting to/from the actual legacy struct (single precision)
708  ldate.second = (double)secs.count() + ((double)(nanos.count())) * NANOSEC_TO_SEC;
709 
710  return ldate;
711 }
712 
713 //needed for ad_hoc flag files (time-stamps are given in floating-point days)
714 inline hops_clock::time_point hops_clock::from_year_fpday(int year, double floating_point_days)
715 {
716  int integer_days = (int)floating_point_days;
717  double fractional_day = floating_point_days - integer_days;
718  int integer_hours = (int)24 * fractional_day;
719  double fractional_hour = 24 * fractional_day - integer_hours;
720  int integer_minutes = (int)60 * fractional_hour;
721  double fractional_seconds = (60 * fractional_hour - integer_minutes) * 60;
722 
723  //we co-opt the legacy date format to handle this format
724  legacy_hops_date ldate;
725  ldate.year = (short)year;
726  ldate.day = (short)integer_days + 1; //note: ordinal day count starts at 1
727  ldate.hour = (short)integer_hours;
728  ldate.minute = (short)integer_minutes;
729  ldate.second = fractional_seconds;
730 
731  return from_legacy_hops_date(ldate);
732 }
733 
734 inline void hops_clock::to_year_fpday(const hops_clock::time_point& tp, int& year, double& floating_point_days)
735 {
736  using namespace date;
737  using namespace std::chrono;
738 
739  //convert the time point to sys time, and extract the date
740  auto sys_tp = hops_clock::to_sys(tp);
741  auto dp = date::sys_days(floor< date::days >(sys_tp));
742 
743  //get all of the date information
744  date::year_month_day ymd{dp};
745  auto year_value = ymd.year();
746  //get the ordinal day of the year
747  auto ordinal_day = day_of_year(dp); //note: count starts at 1
748  int integer_days = ordinal_day.count() - 1;
749  //get the time and convert to fractional day
750  date::hh_mm_ss< std::chrono::nanoseconds > time{floor< std::chrono::nanoseconds >(sys_tp - dp)};
751  int ihours = time.hours().count();
752  int imins = time.minutes().count();
753  int isecs = time.seconds().count();
754  int inanos = time.subseconds().count();
755 
756  double frac_day = (inanos * NANOSEC_TO_SEC + isecs + MINUTE_TO_SEC * imins + HOUR_TO_SEC * ihours) / (JD_TO_SEC);
757  floating_point_days = integer_days + frac_day;
758 }
759 
760 inline hops_clock::time_point hops_clock::from_mjd(const time_point& mjd_epoch, double epoch_offset, double mjd)
761 {
762  double delta = (mjd - epoch_offset);
763  delta *= JD_TO_SEC;
764  std::chrono::duration< double > duration_seconds(delta);
765 
766  auto mjd_epoch_utc = to_utc(mjd_epoch);
767  auto utc_time_point = mjd_epoch_utc + std::chrono::duration_cast< std::chrono::nanoseconds >(duration_seconds);
768  auto hops_time_point = from_utc(utc_time_point);
769  return hops_time_point;
770 }
771 
772 inline double hops_clock::to_mjd(const time_point& mjd_epoch, double epoch_offset, const time_point& tp)
773 {
774  auto mjd_epoch_utc = to_utc(mjd_epoch);
775  auto tp_utc = to_utc(tp);
776 
777  double delta = (tp_utc - mjd_epoch_utc).count();
778  delta *= NANOSEC_TO_SEC; //convert to seconds
779  delta /= JD_TO_SEC; //convert to days
780  delta += epoch_offset; //subtract epoch offset
781  return delta;
782 }
783 
784 inline hops_clock::time_point hops_clock::from_vex_format(const std::string& timestamp)
785 {
786  vex_date vdate = hops_clock::extract_vex_date(timestamp);
787  //convert the vex date info to an ISO-8601-style year-month-day type format
788  std::string vex_as_iso8601 = vex_date_to_iso8601_string(vdate);
789  return hops_clock::from_iso8601_format(vex_as_iso8601);
790 }
791 
792 inline std::string hops_clock::to_vex_format(const time_point& tp, bool truncate_to_nearest_second)
793 {
794  using namespace date;
795  using namespace std::chrono;
796 
797  //convert the time point to sys time, and extract the date
798  auto sys_tp = hops_clock::to_sys(tp);
799  auto dp = date::sys_days(floor< date::days >(sys_tp));
800 
801  //get all of the date information
802  date::year_month_day ymd{dp};
803  auto year = ymd.year();
804  // auto month = ymd.month();
805  // auto day = ymd.day();
806 
807  //get the ordinal day of the year
808  auto ordinal_day = day_of_year(dp);
809 
810  //get the time
811  date::hh_mm_ss< std::chrono::nanoseconds > time{floor< std::chrono::nanoseconds >(sys_tp - dp)};
812  auto hours = time.hours();
813  auto mins = time.minutes();
814  auto secs = time.seconds();
815  auto nanos = time.subseconds();
816 
817  //we need to make sure that year, day-of-year, hour, minute, and integer sec
818  //are all preprended with the proper number of zeros
819 
820  std::stringstream ss;
821  ss << year;
822  ss << "y";
823  ss << std::setfill('0') << std::setw(3) << ordinal_day.count();
824  ss << "d";
825  ss << std::setfill('0') << std::setw(2) << hours.count();
826  ss << "h";
827  ss << std::setfill('0') << std::setw(2) << mins.count();
828  ss << "m";
829  ss << std::setfill('0') << std::setw(2) << secs.count();
830 
831  if(!truncate_to_nearest_second)
832  {
833  std::stringstream nss;
834  nss << std::setfill('0') << std::setw(9) << nanos.count();
835  std::string snano_sec;
836  nss >> snano_sec;
837  std::string trimmed_nanosec = remove_trailing_zeros(snano_sec);
838  if(trimmed_nanosec.size() != 0)
839  {
840  ss << ".";
841  ss << trimmed_nanosec;
842  }
843  }
844  ss << "s";
845 
846  return ss.str();
847 }
848 
849 inline void hops_clock::to_vdif_format(const time_point& tp, int& vdif_epoch, int& vdif_seconds)
850 {
851  using namespace date;
852  using namespace std::chrono;
853 
854  //convert the time point to sys time, and extract the date
855  auto sys_tp = hops_clock::to_sys(tp);
856  auto dp = date::sys_days(floor< date::days >(sys_tp));
857 
858  //get all of the date information so we can figure out the epoch
859  date::year_month_day ymd{dp};
860  auto year = ymd.year();
861  auto month = ymd.month();
862  auto day = ymd.day();
863 
864  //(we have two 6 month epochs per year, and count from start of century)
865  int iyear = static_cast< int >(year);
866  unsigned int imonth = static_cast< unsigned int >(month);
867  int epoch = (iyear % 100) * 2;
868 
869  //now figure out if we are using the Jan 1st epoch, or the July 1st epoch
870  if(imonth < 7)
871  {
872  imonth = 1;
873  }
874  else
875  {
876  epoch += 1;
877  imonth = 7;
878  }
879  //set the day to the first of the month
880  day = date::day(1);
881  int hours = 0;
882  int minutes = 0;
883  int integer_sec = 0;
884 
885  //now figure out the epoch date
886  //may want to eliminate string conversion in favor of something faster
887  std::stringstream ss;
888  ss << iyear;
889  ss << "-";
890  ss << std::setfill('0') << std::setw(2) << imonth;
891  ss << "-";
892  ss << std::setfill('0') << std::setw(2) << static_cast< unsigned int >(day);
893  ss << "T";
894  ss << std::setfill('0') << std::setw(2) << hours;
895  ss << ":";
896  ss << std::setfill('0') << std::setw(2) << minutes;
897  ss << ":";
898  ss << std::setfill('0') << std::setw(2) << integer_sec;
899  ss << "Z";
900  std::string epoch_iso8601 = ss.str();
901  auto epoch_tp = from_iso8601_format(epoch_iso8601);
902  int secs = std::chrono::duration_cast< std::chrono::seconds >(tp - epoch_tp).count();
903 
904  vdif_epoch = epoch;
905  vdif_seconds = secs;
906 }
907 
908 inline hops_clock::time_point hops_clock::from_vdif_format(int& vdif_epoch, int& vdif_seconds)
909 {
910  using namespace date;
911  using namespace std::chrono;
912 
913  int start_year = 2000;
914  int n_years = std::floor(vdif_epoch / 2);
915  int iyear = start_year + n_years;
916 
917  std::cout << "n_years = " << n_years << " iyear = " << iyear << std::endl;
918 
919  unsigned int imonth = 1;
920  if(vdif_epoch % 2 == 1)
921  {
922  imonth = 7;
923  } //second half of the year
924  unsigned int iday = 1;
925  int hours = 0;
926  int minutes = 0;
927  int integer_sec = 0;
928 
929  //now figure out the epoch date
930  //may want to eliminate string conversion in favor of something faster
931  std::stringstream ss;
932  ss << iyear;
933  ss << "-";
934  ss << std::setfill('0') << std::setw(2) << imonth;
935  ss << "-";
936  ss << std::setfill('0') << std::setw(2) << iday;
937  ss << "T";
938  ss << std::setfill('0') << std::setw(2) << hours;
939  ss << ":";
940  ss << std::setfill('0') << std::setw(2) << minutes;
941  ss << ":";
942  ss << std::setfill('0') << std::setw(2) << integer_sec;
943  ss << "Z";
944  std::string epoch_iso8601 = ss.str();
945  std::cout << "epoch = " << epoch_iso8601 << std::endl;
946  auto epoch_tp = from_iso8601_format(epoch_iso8601);
947  auto tp = epoch_tp + std::chrono::seconds(vdif_seconds);
948  return tp;
949 }
950 
951 inline hops_clock::vex_date hops_clock::extract_vex_date(const std::string& timestamp)
952 {
953  vex_date vdate;
954  if(timestamp.size() == 0)
955  {
956  msg_error("utilities", "cannot extract vex date from empty string." << eom);
957  return vdate;
958  }
959 
960  MHO_Tokenizer tokenizer;
961  std::vector< std::string > tokens;
962  std::stringstream ss;
963  std::string rest;
964  std::string syear, sord_day, shour, smin, ssec;
965 
966  tokenizer.SetDelimiter(std::string("y"));
967  tokenizer.SetString(&timestamp);
968  tokenizer.GetTokens(&tokens);
969 
970  syear = tokens[0];
971  ss << syear;
972  ss >> vdate.year;
973  rest = tokens[1];
974 
975  tokenizer.SetDelimiter(std::string("d"));
976  tokenizer.SetString(&rest);
977  tokenizer.GetTokens(&tokens);
978 
979  sord_day = tokens[0];
980  ss.str(std::string());
981  ss.clear();
982  ss << sord_day;
983  ss >> vdate.day_of_year;
984  rest = tokens[1];
985 
986  tokenizer.SetDelimiter(std::string("h"));
987  tokenizer.SetString(&rest);
988  tokenizer.GetTokens(&tokens);
989 
990  shour = tokens[0];
991  ss.str(std::string());
992  ss.clear();
993  ss << shour;
994  ss >> vdate.hours;
995  rest = tokens[1];
996 
997  tokenizer.SetDelimiter(std::string("m"));
998  tokenizer.SetString(&rest);
999  tokenizer.GetTokens(&tokens);
1000 
1001  smin = tokens[0];
1002  ss.str(std::string());
1003  ss.clear();
1004  ss << smin;
1005  ss >> vdate.minutes;
1006  rest = tokens[1];
1007 
1008  tokenizer.SetDelimiter(std::string("s"));
1009  tokenizer.SetString(&rest);
1010  tokenizer.GetTokens(&tokens);
1011 
1012  ssec = tokens[0];
1013  ss.str(std::string());
1014  ss.clear();
1015  ss << std::setprecision(15) << ssec;
1016  ss >> vdate.seconds;
1017 
1018  return vdate;
1019 }
1020 
1021 inline std::string hops_clock::vex_date_to_iso8601_string(hops_clock::vex_date vdate)
1022 {
1023  using namespace date;
1024  using namespace std::chrono;
1025 
1026  std::stringstream ss;
1027  ss << vdate.year;
1028  ss << "-";
1029 
1030  date::year y(vdate.year);
1031  date::days ord_day(vdate.day_of_year);
1032  date::sys_days ymd = get_year_month_day(y, ord_day);
1033 
1034  //convert day-of-year to month-day
1035  auto month = date::year_month_day{ymd}.month();
1036  auto mday = date::year_month_day{ymd}.day();
1037  ss << std::setfill('0') << std::setw(2) << (unsigned)month;
1038  ss << "-";
1039  ss << std::setfill('0') << std::setw(2) << (unsigned)mday;
1040 
1041  ss << "T";
1042  ss << std::setfill('0') << std::setw(2) << vdate.hours;
1043  ss << ":";
1044  ss << std::setfill('0') << std::setw(2) << vdate.minutes;
1045  ss << ":";
1046 
1047  //nss << std::setprecision(9) << vdate.seconds;
1048 
1049  double intpart;
1050  double frac = modf(vdate.seconds, &intpart);
1051  int integer_sec = intpart;
1052 
1053  ss << std::setfill('0') << std::setw(2) << integer_sec;
1054 
1055  //now convert the fraction part into integer nano seconds
1056  //zero-pad to 9 digits so leading zeros (e.g. 256 ns -> "000000256") are
1057  //preserved; without this the round-trip through to_vex_format/ISO8601
1058  //rescales sub-second precision by powers of 10
1059  int integer_nanosec = frac * SEC_TO_NANOSEC;
1060  std::stringstream nss;
1061  nss << std::setfill('0') << std::setw(9) << integer_nanosec;
1062  std::string nanoseconds_value = nss.str();
1063  std::string trimmed_int_nanosec = remove_trailing_zeros(nanoseconds_value);
1064  if(trimmed_int_nanosec.size() != 0)
1065  {
1066  ss << ".";
1067  ss << trimmed_int_nanosec;
1068  }
1069  ss << "Z";
1070  return ss.str();
1071 }
1072 
1073 inline hops_clock::vex_date hops_clock::vex_date_from_legacy(const legacy_hops_date& legacy_date)
1074 {
1075  hops_clock::vex_date vdate;
1076  vdate.year = legacy_date.year;
1077  vdate.day_of_year = legacy_date.day;
1078  vdate.hours = legacy_date.hour;
1079  vdate.minutes = legacy_date.minute;
1080  vdate.seconds = legacy_date.second;
1081  return vdate;
1082 }
1083 
1084 } // namespace hops
1085 
1086 #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:238
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:301
static time_point get_hops_epoch()
returns the hops_clock epoch as a hops_clock time_point
Definition: MHO_Clock.hh:315
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:849
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:499
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 std::string to_iso8601_format(const time_point &tp)
Converts a time_point to ISO8601 formatted string.
Definition: MHO_Clock.hh:614
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:714
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:627
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:596
duration::rep rep
Definition: MHO_Clock.hh:46
static double to_mjd(const time_point &mjd_epoch, 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:772
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:908
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:792
static std::string to_hops_format(const time_point &tp)
Converts a time_point to HOPS format string.
Definition: MHO_Clock.hh:661
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:784
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:320
static time_point from_mjd(const time_point &mjd_epoch, double epoch_offset, double mjd)
Converts a Modified Julian date (floating point epoch and day) timestamp to a hops_clock time_point.
Definition: MHO_Clock.hh:760
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:679
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:734
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:672
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 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_AdhocFlagging.hh:18
std::basic_ostream< CharT, Traits > & operator<<(std::basic_ostream< CharT, Traits > &os, const hops_time< Duration > &t)
Definition: MHO_Clock.hh:584
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:573
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:383
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:550
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