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 
13 //Leap-second / utc-tai-gps-sys clock backend selection.
14 //HOPS_USE_INTERNAL_LEAP_SECONDS (default, set by CMake): use the self-contained
15 //hardcoded leap-second table in hops_leap_seconds.hh, so no libdate-tz link,
16 //no runtime dependency on the host tz database.
17 //otherwise: fall back to the upstream compiled date/tz.h (links libdate-tz and
18 //reads the installed system tz db at runtime).
19 //Both backends expose the same utc_clock/tai_clock/gps_clock/get_leap_second_info functionality
20 //the hops_tz namespace alias below points MHO_Clock at whichever is active.
21 #ifdef HOPS_USE_INTERNAL_LEAP_SECONDS
22  #include "hops_leap_seconds.hh"
23 #else
24  #include "date/tz.h"
25 #endif
26 
27 #include "MHO_Message.hh"
28 #include "MHO_Tokenizer.hh"
29 #include "legacy_hops_date.hh"
30 
31 #define J2000_TAI_EPOCH "2000-01-01 11:59:27.816"
32 #define ISO8601_UTC_FORMAT "%FT%TZ"
33 #define HOPS_TIMESTAMP_PREFIX "HOPS-J2000"
34 #define HOPS_TIME_DELIM "|"
35 #define HOPS_TIME_UNIT "ns"
36 #define NANOSEC_TO_SEC 1e-9
37 #define SEC_TO_NANOSEC 1000000000
38 #define JD_TO_SEC 86400.0
39 #define MINUTE_TO_SEC 60.0
40 #define HOUR_TO_SEC 3600.0
41 
42 //alias the active leap-second/clock backend (see the include block above). The
43 //internal implementation lives in namespace hops; the upstream one in date. Both
44 //provide utc_clock/tai_clock/gps_clock, the utc_time/tai_time/gps_time aliases,
45 //and get_leap_second_info, so MHO_Clock refers to them only through hops_tz.
46 #ifdef HOPS_USE_INTERNAL_LEAP_SECONDS
47 namespace hops_tz = hops;
48 #else
49 namespace hops_tz = date;
50 #endif
51 
52 namespace hops
53 {
54 
66 {
67  public:
68  using duration = std::chrono::nanoseconds;
69  using rep = duration::rep;
70  using period = duration::period;
71  using time_point = std::chrono::time_point< hops_clock, std::chrono::nanoseconds >;
72  static const bool is_steady = false;
73 
80  static time_point now();
81 
88  template< typename Duration >
89  static std::chrono::time_point< hops_tz::utc_clock,
90  typename std::common_type< Duration, std::chrono::nanoseconds >::type >
91  to_utc(const std::chrono::time_point< hops_clock, Duration >&) NOEXCEPT;
92 
99  template< typename Duration >
100  static std::chrono::time_point< hops_clock, typename std::common_type< Duration, std::chrono::nanoseconds >::type >
101  from_utc(const std::chrono::time_point< hops_tz::utc_clock, Duration >&) NOEXCEPT;
102 
109  template< typename Duration >
110  static std::chrono::time_point< hops_tz::tai_clock,
111  typename std::common_type< Duration, std::chrono::nanoseconds >::type >
112  to_tai(const std::chrono::time_point< hops_clock, Duration >&) NOEXCEPT;
113 
120  template< typename Duration >
121  static std::chrono::time_point< hops_clock, typename std::common_type< Duration, std::chrono::nanoseconds >::type >
122  from_tai(const std::chrono::time_point< hops_tz::tai_clock, Duration >&) NOEXCEPT;
123 
130  template< typename Duration >
131  static std::chrono::time_point< hops_tz::gps_clock,
132  typename std::common_type< Duration, std::chrono::nanoseconds >::type >
133  to_gps(const std::chrono::time_point< hops_clock, Duration >&) NOEXCEPT;
134 
141  template< typename Duration >
142  static std::chrono::time_point< hops_clock, typename std::common_type< Duration, std::chrono::nanoseconds >::type >
143  from_gps(const std::chrono::time_point< hops_tz::gps_clock, Duration >&) NOEXCEPT;
144 
151  template< typename Duration >
152  static std::chrono::time_point< std::chrono::system_clock,
153  typename std::common_type< Duration, std::chrono::nanoseconds >::type >
154  to_sys(const std::chrono::time_point< hops_clock, Duration >&) NOEXCEPT;
155 
162  template< typename Duration >
163  static std::chrono::time_point< hops_clock, typename std::common_type< Duration, std::chrono::nanoseconds >::type >
164  from_sys(const std::chrono::time_point< std::chrono::system_clock, Duration >&) NOEXCEPT;
165 
172  template< typename Duration >
173  static std::chrono::time_point< date::local_t, typename std::common_type< Duration, std::chrono::nanoseconds >::type >
174  to_local(const std::chrono::time_point< hops_clock, Duration >&) NOEXCEPT;
175 
182  template< typename Duration >
183  static std::chrono::time_point< hops_clock, typename std::common_type< Duration, std::chrono::nanoseconds >::type >
184  from_local(const std::chrono::time_point< date::local_t, Duration >&) NOEXCEPT;
185 
193  static time_point from_iso8601_format(const std::string& timestamp);
194 
202  static std::string to_iso8601_format(const time_point& tp);
203 
211  static time_point from_hops_format(const std::string& timestamp);
212 
220  static std::string to_hops_format(const time_point& tp);
221 
230 
239 
248  static time_point from_vdif_format(int& vdif_epoch, int& vdif_seconds);
249 
259  static void to_vdif_format(const time_point& tp, int& vdif_epoch, int& vdif_second);
260 
270  static time_point from_mjd(const time_point& mjd_epoch, double epoch_offset, double mjd);
271 
281  static double to_mjd(const time_point& mjd_epoch, double epoch_offset, const time_point& tp);
282 
290  static time_point from_vex_format(const std::string& timestamp);
291 
300  static std::string to_vex_format(const time_point& tp, bool truncate_to_nearest_second = false);
301 
311  static time_point from_year_fpday(int year, double floating_point_days);
312 
322  static void to_year_fpday(const time_point& tp, int& year, double& floating_point_days);
323 
327  static hops_tz::utc_time< std::chrono::nanoseconds > get_hops_epoch_utc()
328  {
329  using namespace std::chrono;
330  //J2000 TAI epoch = 2000-01-01 11:59:27.816 (TAI wall-clock reading,
331  //see J2000_TAI_EPOCH). Build the tai_time numerically from calendar
332  //arithmetic (date::sys_days does not invovle leap seconds, no tz.h)
333  date::sys_days tai_epoch_day{date::year{1958} / date::month{1} / date::day{1}};
334  date::sys_days j2000_day{date::year{2000} / date::month{1} / date::day{1}};
335  auto days_since_tai_epoch = j2000_day - tai_epoch_day; //date::days
336  auto tod = hours{11} + minutes{59} + seconds{27} + milliseconds{816};
337  hops_tz::tai_time< nanoseconds > j2000_tai_epoch{duration_cast< nanoseconds >(days_since_tai_epoch) +
338  duration_cast< nanoseconds >(tod)};
339  return time_point_cast< nanoseconds >(hops_tz::tai_clock::to_utc(j2000_tai_epoch));
340  }
341 
346 
350  static std::chrono::seconds get_leap_seconds_between(const time_point& t_start, const time_point& t_end)
351  {
352  auto t_start_utc = to_utc(t_start);
353  auto t_end_utc = to_utc(t_end);
354  auto lp_info0 = hops_tz::get_leap_second_info(t_start_utc);
355  auto lp_info1 = hops_tz::get_leap_second_info(t_end_utc);
356  int delta = lp_info1.elapsed.count() - lp_info0.elapsed.count();
357  return std::chrono::seconds(delta);
358  }
359 
360  private:
361  static date::days day_of_year(date::sys_days sd)
362  {
363  using namespace date;
364  auto y = date::year_month_day{sd}.year();
365  return sd - date::sys_days{y / jan / 0};
366  }
367 
368  static date::sys_days get_year_month_day(date::year y, date::days ord_day)
369  {
370  using namespace date;
371  return date::sys_days{y / jan / 0} + ord_day;
372  }
373 
374  struct vex_date
375  {
376  int year;
377  int day_of_year;
378  int hours;
379  int minutes;
380  double seconds;
381  };
382 
383  static vex_date extract_vex_date(const std::string& timestamp);
384 
385  static std::string vex_date_to_iso8601_string(vex_date vdate);
386 
387  static vex_date vex_date_from_legacy(const legacy_hops_date& legacy_date);
388 
389  static std::string remove_trailing_zeros(std::string value)
390  {
391  std::size_t nzeros_on_end = 0;
392  for(auto rit = value.rbegin(); rit != value.rend(); rit++)
393  {
394  if(*rit != '0')
395  {
396  break;
397  }
398  nzeros_on_end++;
399  }
400  std::size_t useful_length = value.size() - nzeros_on_end;
401  std::string ret_val;
402  for(std::size_t i = 0; i < useful_length; i++)
403  {
404  ret_val.push_back(value[i]);
405  }
406  return ret_val;
407  }
408 };
409 
413 template< class Duration > using hops_time = std::chrono::time_point< hops_clock, Duration >;
414 
421 template< class Duration >
422 inline hops_tz::utc_time< typename std::common_type< Duration, std::chrono::nanoseconds >::type >
424 {
425 
426  using CD = typename std::common_type< Duration, std::chrono::nanoseconds >::type;
427  hops_tz::utc_time< std::chrono::nanoseconds > hops_epoch_start = get_hops_epoch_utc();
428  return hops_tz::utc_time< CD >(t.time_since_epoch() + hops_epoch_start.time_since_epoch());
429 }
430 
437 template< class Duration >
439 hops_clock::from_utc(const hops_tz::utc_time< Duration >& t) NOEXCEPT
440 {
441  using CD = typename std::common_type< Duration, std::chrono::nanoseconds >::type;
442  hops_tz::utc_time< std::chrono::nanoseconds > hops_epoch_start = get_hops_epoch_utc();
443  return hops_time< CD >(t.time_since_epoch() - hops_epoch_start.time_since_epoch());
444 }
445 
452 template< class Duration >
453 inline hops_tz::tai_time< typename std::common_type< Duration, std::chrono::nanoseconds >::type >
455 {
456  return hops_tz::tai_clock::from_utc(to_utc(t));
457 }
458 
465 template< class Duration >
467 hops_clock::from_tai(const hops_tz::tai_time< Duration >& t) NOEXCEPT
468 {
469  return from_utc(hops_tz::tai_clock::to_utc(t));
470 }
471 
478 template< class Duration >
479 inline hops_tz::gps_time< typename std::common_type< Duration, std::chrono::nanoseconds >::type >
481 {
482  return hops_tz::gps_clock::from_utc(to_utc(t));
483 }
484 
491 template< class Duration >
493 hops_clock::from_gps(const hops_tz::gps_time< Duration >& t) NOEXCEPT
494 {
495  return from_utc(hops_tz::gps_clock::to_utc(t));
496 }
497 
504 template< class Duration >
505 inline date::sys_time< typename std::common_type< Duration, std::chrono::nanoseconds >::type >
507 {
508  return hops_tz::utc_clock::to_sys(to_utc(t));
509 }
510 
517 template< class Duration >
519 hops_clock::from_sys(const date::sys_time< Duration >& t) NOEXCEPT
520 {
521  return from_utc(hops_tz::utc_clock::from_sys(t));
522 }
523 
530 {
531  return from_utc(hops_tz::utc_clock::now());
532 }
533 
540 template< class Duration >
541 inline date::local_time< typename std::common_type< Duration, std::chrono::nanoseconds >::type >
543 {
544  using CD = typename std::common_type< Duration, std::chrono::nanoseconds >::type;
545  hops_tz::utc_time< CD > hops_epoch_start = std::chrono::time_point_cast< CD >(get_hops_epoch_utc());
546  hops_tz::utc_time< CD > ut_time{t.time_since_epoch() +
547  std::chrono::time_point_cast< Duration >(hops_epoch_start).time_since_epoch()};
548  return hops_tz::utc_clock::to_local(ut_time);
549 }
550 
557 template< class Duration >
559 hops_clock::from_local(const date::local_time< Duration >& t) NOEXCEPT
560 {
561  using CD = typename std::common_type< Duration, std::chrono::nanoseconds >::type;
562  hops_tz::utc_time< CD > t2 = hops_tz::utc_clock::from_local(t);
563  hops_tz::utc_time< CD > hops_epoch_start = std::chrono::time_point_cast< CD >(get_hops_epoch_utc());
564  return hops_time< CD >{t2.time_since_epoch() -
565  std::chrono::time_point_cast< Duration >(hops_epoch_start).time_since_epoch()};
566 }
567 
579 template< class CharT, class Traits, class Duration >
580 std::basic_ostream< CharT, Traits >& to_stream(std::basic_ostream< CharT, Traits >& os, const CharT* fmt,
581  const hops_time< Duration >& t)
582 {
583  const std::string abbrev("HOPS");
584  CONSTDATA std::chrono::seconds offset{0};
585  return date::to_stream(os, fmt, hops_clock::to_local(t), &abbrev, &offset);
586 }
587 
601 template< class Duration, class CharT, class Traits, class Alloc = std::allocator< CharT > >
602 std::basic_istream< CharT, Traits >&
603 from_stream(std::basic_istream< CharT, Traits >& is, const CharT* fmt, hops_time< Duration >& tp,
604  std::basic_string< CharT, Traits, Alloc >* abbrev = nullptr, std::chrono::minutes* offset = nullptr)
605 {
606  date::local_time< Duration > lp;
607  from_stream(is, fmt, lp, abbrev, offset);
608  if(!is.fail())
609  tp = hops_clock::from_local(lp);
610  return is;
611 }
612 
613 template< class CharT, class Traits, class Duration >
614 std::basic_ostream< CharT, Traits >& operator<<(std::basic_ostream< CharT, Traits >& os, const hops_time< Duration >& t)
615 {
616  const CharT fmt[] = {'%', 'F', 'T', '%', 'T', 'Z', CharT{}};
617  return to_stream(os, fmt, t);
618 }
619 
626 inline hops_clock::time_point hops_clock::from_iso8601_format(const std::string& timestamp)
627 {
628  using namespace date;
629  using namespace std::chrono;
630  std::string frmt = ISO8601_UTC_FORMAT;
631  std::istringstream ss(timestamp);
632  std::istream tmp_stream(ss.rdbuf());
634  from_stream(tmp_stream, frmt.c_str(), hops_tp);
635  return hops_tp;
636 }
637 
644 inline std::string hops_clock::to_iso8601_format(const time_point& tp)
645 {
646  std::stringstream ss;
647  ss << tp;
648  return ss.str();
649 }
650 
657 inline hops_clock::time_point hops_clock::from_hops_format(const std::string& timestamp)
658 {
659  using namespace date;
660  using namespace std::chrono;
661 
662  MHO_Tokenizer tokenizer;
663  tokenizer.SetDelimiter(std::string(HOPS_TIME_DELIM));
664  std::vector< std::string > tokens;
665  tokenizer.SetString(&timestamp);
666  tokenizer.GetTokens(&tokens);
667  if(tokens.size() == 3)
668  {
669  std::string hops_prefix = tokens[0];
670  std::string unit = tokens[1];
671  std::string nanosecond_count = tokens[2];
672  if(hops_prefix == std::string(HOPS_TIMESTAMP_PREFIX) && unit == std::string(HOPS_TIME_UNIT))
673  {
674  std::stringstream ss;
675  ss << nanosecond_count;
676  int64_t ns;
677  ss >> ns;
678  return time_point(std::chrono::nanoseconds(ns));
679  }
680  }
681  msg_error("utility", "hops timestamp string not understood or supported, returning epoch start. " << eom);
682  return time_point(std::chrono::nanoseconds(0));
683 }
684 
691 inline std::string hops_clock::to_hops_format(const time_point& tp)
692 {
693  std::stringstream ss;
694  ss << HOPS_TIMESTAMP_PREFIX;
695  ss << HOPS_TIME_DELIM;
696  ss << HOPS_TIME_UNIT;
697  ss << HOPS_TIME_DELIM;
698  ss << tp.time_since_epoch().count();
699  return ss.str();
700 }
701 
703 {
704  vex_date vdate = vex_date_from_legacy(ldate);
705  std::string vex_as_iso8601 = vex_date_to_iso8601_string(vdate);
706  return hops_clock::from_iso8601_format(vex_as_iso8601);
707 }
708 
710 {
711  using namespace date;
712  using namespace std::chrono;
713 
714  //convert the time point to sys time, and extract the date
715  auto sys_tp = hops_clock::to_sys(tp);
716  auto dp = date::sys_days(floor< date::days >(sys_tp));
717 
718  //get all of the date information
719  date::year_month_day ymd{dp};
720  auto year = ymd.year();
721 
722  //get the ordinal day of the year
723  auto ordinal_day = day_of_year(dp);
724 
725  //get the time
726  date::hh_mm_ss< std::chrono::nanoseconds > time{floor< std::chrono::nanoseconds >(sys_tp - dp)};
727  auto hours = time.hours();
728  auto mins = time.minutes();
729  auto secs = time.seconds();
730  auto nanos = time.subseconds();
731 
732  legacy_hops_date ldate;
733  ldate.year = (int)year;
734  ldate.day = ordinal_day.count();
735  ldate.hour = hours.count();
736  ldate.minute = mins.count();
737  //note there may be loss of precision when converting to/from the actual legacy struct (single precision)
738  ldate.second = (double)secs.count() + ((double)(nanos.count())) * NANOSEC_TO_SEC;
739 
740  return ldate;
741 }
742 
743 //needed for ad_hoc flag files (time-stamps are given in floating-point days)
744 inline hops_clock::time_point hops_clock::from_year_fpday(int year, double floating_point_days)
745 {
746  int integer_days = (int)floating_point_days;
747  double fractional_day = floating_point_days - integer_days;
748  int integer_hours = (int)24 * fractional_day;
749  double fractional_hour = 24 * fractional_day - integer_hours;
750  int integer_minutes = (int)60 * fractional_hour;
751  double fractional_seconds = (60 * fractional_hour - integer_minutes) * 60;
752 
753  //we co-opt the legacy date format to handle this format
754  legacy_hops_date ldate;
755  ldate.year = (short)year;
756  ldate.day = (short)integer_days + 1; //note: ordinal day count starts at 1
757  ldate.hour = (short)integer_hours;
758  ldate.minute = (short)integer_minutes;
759  ldate.second = fractional_seconds;
760 
761  return from_legacy_hops_date(ldate);
762 }
763 
764 inline void hops_clock::to_year_fpday(const hops_clock::time_point& tp, int& year, double& floating_point_days)
765 {
766  using namespace date;
767  using namespace std::chrono;
768 
769  //convert the time point to sys time, and extract the date
770  auto sys_tp = hops_clock::to_sys(tp);
771  auto dp = date::sys_days(floor< date::days >(sys_tp));
772 
773  //get all of the date information
774  date::year_month_day ymd{dp};
775  auto year_value = ymd.year();
776  //get the ordinal day of the year
777  auto ordinal_day = day_of_year(dp); //note: count starts at 1
778  int integer_days = ordinal_day.count() - 1;
779  //get the time and convert to fractional day
780  date::hh_mm_ss< std::chrono::nanoseconds > time{floor< std::chrono::nanoseconds >(sys_tp - dp)};
781  int ihours = time.hours().count();
782  int imins = time.minutes().count();
783  int isecs = time.seconds().count();
784  int inanos = time.subseconds().count();
785 
786  double frac_day = (inanos * NANOSEC_TO_SEC + isecs + MINUTE_TO_SEC * imins + HOUR_TO_SEC * ihours) / (JD_TO_SEC);
787  floating_point_days = integer_days + frac_day;
788 }
789 
790 inline hops_clock::time_point hops_clock::from_mjd(const time_point& mjd_epoch, double epoch_offset, double mjd)
791 {
792  double delta = (mjd - epoch_offset);
793  delta *= JD_TO_SEC;
794  std::chrono::duration< double > duration_seconds(delta);
795 
796  auto mjd_epoch_utc = to_utc(mjd_epoch);
797  auto utc_time_point = mjd_epoch_utc + std::chrono::duration_cast< std::chrono::nanoseconds >(duration_seconds);
798  auto hops_time_point = from_utc(utc_time_point);
799  return hops_time_point;
800 }
801 
802 inline double hops_clock::to_mjd(const time_point& mjd_epoch, double epoch_offset, const time_point& tp)
803 {
804  auto mjd_epoch_utc = to_utc(mjd_epoch);
805  auto tp_utc = to_utc(tp);
806 
807  double delta = (tp_utc - mjd_epoch_utc).count();
808  delta *= NANOSEC_TO_SEC; //convert to seconds
809  delta /= JD_TO_SEC; //convert to days
810  delta += epoch_offset; //subtract epoch offset
811  return delta;
812 }
813 
814 inline hops_clock::time_point hops_clock::from_vex_format(const std::string& timestamp)
815 {
816  vex_date vdate = hops_clock::extract_vex_date(timestamp);
817  //convert the vex date info to an ISO-8601-style year-month-day type format
818  std::string vex_as_iso8601 = vex_date_to_iso8601_string(vdate);
819  return hops_clock::from_iso8601_format(vex_as_iso8601);
820 }
821 
822 inline std::string hops_clock::to_vex_format(const time_point& tp, bool truncate_to_nearest_second)
823 {
824  using namespace date;
825  using namespace std::chrono;
826 
827  //convert the time point to sys time, and extract the date
828  auto sys_tp = hops_clock::to_sys(tp);
829  auto dp = date::sys_days(floor< date::days >(sys_tp));
830 
831  //get all of the date information
832  date::year_month_day ymd{dp};
833  auto year = ymd.year();
834  // auto month = ymd.month();
835  // auto day = ymd.day();
836 
837  //get the ordinal day of the year
838  auto ordinal_day = day_of_year(dp);
839 
840  //get the time
841  date::hh_mm_ss< std::chrono::nanoseconds > time{floor< std::chrono::nanoseconds >(sys_tp - dp)};
842  auto hours = time.hours();
843  auto mins = time.minutes();
844  auto secs = time.seconds();
845  auto nanos = time.subseconds();
846 
847  //we need to make sure that year, day-of-year, hour, minute, and integer sec
848  //are all preprended with the proper number of zeros
849 
850  std::stringstream ss;
851  ss << year;
852  ss << "y";
853  ss << std::setfill('0') << std::setw(3) << ordinal_day.count();
854  ss << "d";
855  ss << std::setfill('0') << std::setw(2) << hours.count();
856  ss << "h";
857  ss << std::setfill('0') << std::setw(2) << mins.count();
858  ss << "m";
859  ss << std::setfill('0') << std::setw(2) << secs.count();
860 
861  if(!truncate_to_nearest_second)
862  {
863  std::stringstream nss;
864  nss << std::setfill('0') << std::setw(9) << nanos.count();
865  std::string snano_sec;
866  nss >> snano_sec;
867  std::string trimmed_nanosec = remove_trailing_zeros(snano_sec);
868  if(trimmed_nanosec.size() != 0)
869  {
870  ss << ".";
871  ss << trimmed_nanosec;
872  }
873  }
874  ss << "s";
875 
876  return ss.str();
877 }
878 
879 inline void hops_clock::to_vdif_format(const time_point& tp, int& vdif_epoch, int& vdif_seconds)
880 {
881  using namespace date;
882  using namespace std::chrono;
883 
884  //convert the time point to sys time, and extract the date
885  auto sys_tp = hops_clock::to_sys(tp);
886  auto dp = date::sys_days(floor< date::days >(sys_tp));
887 
888  //get all of the date information so we can figure out the epoch
889  date::year_month_day ymd{dp};
890  auto year = ymd.year();
891  auto month = ymd.month();
892  auto day = ymd.day();
893 
894  //(we have two 6 month epochs per year, and count from start of century)
895  int iyear = static_cast< int >(year);
896  unsigned int imonth = static_cast< unsigned int >(month);
897  int epoch = (iyear % 100) * 2;
898 
899  //now figure out if we are using the Jan 1st epoch, or the July 1st epoch
900  if(imonth < 7)
901  {
902  imonth = 1;
903  }
904  else
905  {
906  epoch += 1;
907  imonth = 7;
908  }
909  //set the day to the first of the month
910  day = date::day(1);
911  int hours = 0;
912  int minutes = 0;
913  int integer_sec = 0;
914 
915  //now figure out the epoch date
916  //may want to eliminate string conversion in favor of something faster
917  std::stringstream ss;
918  ss << iyear;
919  ss << "-";
920  ss << std::setfill('0') << std::setw(2) << imonth;
921  ss << "-";
922  ss << std::setfill('0') << std::setw(2) << static_cast< unsigned int >(day);
923  ss << "T";
924  ss << std::setfill('0') << std::setw(2) << hours;
925  ss << ":";
926  ss << std::setfill('0') << std::setw(2) << minutes;
927  ss << ":";
928  ss << std::setfill('0') << std::setw(2) << integer_sec;
929  ss << "Z";
930  std::string epoch_iso8601 = ss.str();
931  auto epoch_tp = from_iso8601_format(epoch_iso8601);
932  int secs = std::chrono::duration_cast< std::chrono::seconds >(tp - epoch_tp).count();
933 
934  vdif_epoch = epoch;
935  vdif_seconds = secs;
936 }
937 
938 inline hops_clock::time_point hops_clock::from_vdif_format(int& vdif_epoch, int& vdif_seconds)
939 {
940  using namespace date;
941  using namespace std::chrono;
942 
943  int start_year = 2000;
944  int n_years = std::floor(vdif_epoch / 2);
945  int iyear = start_year + n_years;
946 
947  std::cout << "n_years = " << n_years << " iyear = " << iyear << std::endl;
948 
949  unsigned int imonth = 1;
950  if(vdif_epoch % 2 == 1)
951  {
952  imonth = 7;
953  } //second half of the year
954  unsigned int iday = 1;
955  int hours = 0;
956  int minutes = 0;
957  int integer_sec = 0;
958 
959  //now figure out the epoch date
960  //may want to eliminate string conversion in favor of something faster
961  std::stringstream ss;
962  ss << iyear;
963  ss << "-";
964  ss << std::setfill('0') << std::setw(2) << imonth;
965  ss << "-";
966  ss << std::setfill('0') << std::setw(2) << iday;
967  ss << "T";
968  ss << std::setfill('0') << std::setw(2) << hours;
969  ss << ":";
970  ss << std::setfill('0') << std::setw(2) << minutes;
971  ss << ":";
972  ss << std::setfill('0') << std::setw(2) << integer_sec;
973  ss << "Z";
974  std::string epoch_iso8601 = ss.str();
975  std::cout << "epoch = " << epoch_iso8601 << std::endl;
976  auto epoch_tp = from_iso8601_format(epoch_iso8601);
977  auto tp = epoch_tp + std::chrono::seconds(vdif_seconds);
978  return tp;
979 }
980 
981 inline hops_clock::vex_date hops_clock::extract_vex_date(const std::string& timestamp)
982 {
983  vex_date vdate;
984  if(timestamp.size() == 0)
985  {
986  msg_error("utilities", "cannot extract vex date from empty string." << eom);
987  return vdate;
988  }
989 
990  MHO_Tokenizer tokenizer;
991  std::vector< std::string > tokens;
992  std::stringstream ss;
993  std::string rest;
994  std::string syear, sord_day, shour, smin, ssec;
995 
996  tokenizer.SetDelimiter(std::string("y"));
997  tokenizer.SetString(&timestamp);
998  tokenizer.GetTokens(&tokens);
999 
1000  syear = tokens[0];
1001  ss << syear;
1002  ss >> vdate.year;
1003  rest = tokens[1];
1004 
1005  tokenizer.SetDelimiter(std::string("d"));
1006  tokenizer.SetString(&rest);
1007  tokenizer.GetTokens(&tokens);
1008 
1009  sord_day = tokens[0];
1010  ss.str(std::string());
1011  ss.clear();
1012  ss << sord_day;
1013  ss >> vdate.day_of_year;
1014  rest = tokens[1];
1015 
1016  tokenizer.SetDelimiter(std::string("h"));
1017  tokenizer.SetString(&rest);
1018  tokenizer.GetTokens(&tokens);
1019 
1020  shour = tokens[0];
1021  ss.str(std::string());
1022  ss.clear();
1023  ss << shour;
1024  ss >> vdate.hours;
1025  rest = tokens[1];
1026 
1027  tokenizer.SetDelimiter(std::string("m"));
1028  tokenizer.SetString(&rest);
1029  tokenizer.GetTokens(&tokens);
1030 
1031  smin = tokens[0];
1032  ss.str(std::string());
1033  ss.clear();
1034  ss << smin;
1035  ss >> vdate.minutes;
1036  rest = tokens[1];
1037 
1038  tokenizer.SetDelimiter(std::string("s"));
1039  tokenizer.SetString(&rest);
1040  tokenizer.GetTokens(&tokens);
1041 
1042  ssec = tokens[0];
1043  ss.str(std::string());
1044  ss.clear();
1045  ss << std::setprecision(15) << ssec;
1046  ss >> vdate.seconds;
1047 
1048  return vdate;
1049 }
1050 
1051 inline std::string hops_clock::vex_date_to_iso8601_string(hops_clock::vex_date vdate)
1052 {
1053  using namespace date;
1054  using namespace std::chrono;
1055 
1056  std::stringstream ss;
1057  ss << vdate.year;
1058  ss << "-";
1059 
1060  date::year y(vdate.year);
1061  date::days ord_day(vdate.day_of_year);
1062  date::sys_days ymd = get_year_month_day(y, ord_day);
1063 
1064  //convert day-of-year to month-day
1065  auto month = date::year_month_day{ymd}.month();
1066  auto mday = date::year_month_day{ymd}.day();
1067  ss << std::setfill('0') << std::setw(2) << (unsigned)month;
1068  ss << "-";
1069  ss << std::setfill('0') << std::setw(2) << (unsigned)mday;
1070 
1071  ss << "T";
1072  ss << std::setfill('0') << std::setw(2) << vdate.hours;
1073  ss << ":";
1074  ss << std::setfill('0') << std::setw(2) << vdate.minutes;
1075  ss << ":";
1076 
1077  //nss << std::setprecision(9) << vdate.seconds;
1078 
1079  double intpart;
1080  double frac = modf(vdate.seconds, &intpart);
1081  int integer_sec = intpart;
1082 
1083  ss << std::setfill('0') << std::setw(2) << integer_sec;
1084 
1085  //now convert the fraction part into integer nano seconds
1086  //zero-pad to 9 digits so leading zeros (e.g. 256 ns -> "000000256") are
1087  //preserved; without this the round-trip through to_vex_format/ISO8601
1088  //rescales sub-second precision by powers of 10
1089  int integer_nanosec = frac * SEC_TO_NANOSEC;
1090  std::stringstream nss;
1091  nss << std::setfill('0') << std::setw(9) << integer_nanosec;
1092  std::string nanoseconds_value = nss.str();
1093  std::string trimmed_int_nanosec = remove_trailing_zeros(nanoseconds_value);
1094  if(trimmed_int_nanosec.size() != 0)
1095  {
1096  ss << ".";
1097  ss << trimmed_int_nanosec;
1098  }
1099  ss << "Z";
1100  return ss.str();
1101 }
1102 
1103 inline hops_clock::vex_date hops_clock::vex_date_from_legacy(const legacy_hops_date& legacy_date)
1104 {
1105  hops_clock::vex_date vdate;
1106  vdate.year = legacy_date.year;
1107  vdate.day_of_year = legacy_date.day;
1108  vdate.hours = legacy_date.hour;
1109  vdate.minutes = legacy_date.minute;
1110  vdate.seconds = legacy_date.second;
1111  return vdate;
1112 }
1113 
1114 } // namespace hops
1115 
1116 #endif
#define ISO8601_UTC_FORMAT
Definition: MHO_Clock.hh:32
#define MINUTE_TO_SEC
Definition: MHO_Clock.hh:39
#define SEC_TO_NANOSEC
Definition: MHO_Clock.hh:37
#define HOPS_TIMESTAMP_PREFIX
Definition: MHO_Clock.hh:33
#define HOPS_TIME_DELIM
Definition: MHO_Clock.hh:34
#define NANOSEC_TO_SEC
Definition: MHO_Clock.hh:36
#define HOPS_TIME_UNIT
Definition: MHO_Clock.hh:35
#define JD_TO_SEC
Definition: MHO_Clock.hh:38
#define HOUR_TO_SEC
Definition: MHO_Clock.hh:40
#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:66
static std::chrono::time_point< hops_tz::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 time_point get_hops_epoch()
returns the hops_clock epoch as a hops_clock time_point
Definition: MHO_Clock.hh:345
duration::period period
Definition: MHO_Clock.hh:70
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:879
static time_point now()
Returns current time as a time_point using hops_clock's epoch.
Definition: MHO_Clock.hh:529
std::chrono::time_point< hops_clock, std::chrono::nanoseconds > time_point
Definition: MHO_Clock.hh:71
static std::chrono::time_point< hops_tz::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 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:644
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:744
std::chrono::nanoseconds duration
Definition: MHO_Clock.hh:68
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:657
static std::chrono::time_point< hops_clock, typename std::common_type< Duration, std::chrono::nanoseconds >::type > from_gps(const std::chrono::time_point< hops_tz::gps_clock, Duration > &) NOEXCEPT
Converts GPS time to Hops clock time.
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:626
duration::rep rep
Definition: MHO_Clock.hh:69
static std::chrono::time_point< hops_clock, typename std::common_type< Duration, std::chrono::nanoseconds >::type > from_utc(const std::chrono::time_point< hops_tz::utc_clock, Duration > &) NOEXCEPT
Converts UTC time point to hops_clock time point.
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:802
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:938
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:822
static std::chrono::time_point< hops_tz::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.
static hops_tz::utc_time< std::chrono::nanoseconds > get_hops_epoch_utc()
returns the hops_clock epoch as a utc_time time_point
Definition: MHO_Clock.hh:327
static std::string to_hops_format(const time_point &tp)
Converts a time_point to HOPS format string.
Definition: MHO_Clock.hh:691
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:814
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:350
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:790
static const bool is_steady
Definition: MHO_Clock.hh:72
static std::chrono::time_point< hops_clock, typename std::common_type< Duration, std::chrono::nanoseconds >::type > from_tai(const std::chrono::time_point< hops_tz::tai_clock, Duration > &) NOEXCEPT
Converts a TAI time point to UTC and returns the corresponding Hops clock time.
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:709
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:764
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:702
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.
Self-contained (link-free) reimplementation of the small slice of the date library's tz facilities th...
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:614
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:603
leap_second_info get_leap_second_info(const utc_time< Duration > &ut)
Leap-second lookup for a utc_time, matching date::get_leap_second_info.
Definition: hops_leap_seconds.hh:171
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:413
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:580
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