Goby3  3.1.5a
2024.05.23
convert.h
Go to the documentation of this file.
1 // Copyright 2018-2021:
2 // GobySoft, LLC (2013-)
3 // Community contributors (see AUTHORS file)
4 // File authors:
5 // Toby Schneider <toby@gobysoft.org>
6 //
7 //
8 // This file is part of the Goby Underwater Autonomy Project Libraries
9 // ("The Goby Libraries").
10 //
11 // The Goby Libraries are free software: you can redistribute them and/or modify
12 // them under the terms of the GNU Lesser General Public License as published by
13 // the Free Software Foundation, either version 2.1 of the License, or
14 // (at your option) any later version.
15 //
16 // The Goby Libraries are distributed in the hope that they will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU Lesser General Public License for more details.
20 //
21 // You should have received a copy of the GNU Lesser General Public License
22 // along with Goby. If not, see <http://www.gnu.org/licenses/>.
23 
24 #ifndef GOBY_TIME_CONVERT_H
25 #define GOBY_TIME_CONVERT_H
26 
27 #include <chrono>
28 #include <sstream>
29 #include <type_traits>
30 
31 #include <boost/date_time.hpp>
32 #include <boost/units/cmath.hpp>
33 
34 #include "goby/time/system_clock.h"
35 #include "goby/time/types.h"
36 
37 namespace goby
38 {
39 namespace time
40 {
47 template <typename ToTimeType, typename FromTimeType,
48  typename std::enable_if<std::is_same<ToTimeType, FromTimeType>{}, int>::type = 0>
49 ToTimeType convert(FromTimeType from_time)
50 {
51  return from_time;
52 };
53 
60 template <typename ToTimeType, typename FromTimeType,
61  typename ToUnitType = typename ToTimeType::unit_type,
62  typename ToValueType = typename ToTimeType::value_type,
63  typename FromUnitType = typename FromTimeType::unit_type,
64  typename FromValueType = typename FromTimeType::value_type,
65  typename std::enable_if<
66  !std::is_same<ToTimeType, FromTimeType>{} &&
67  std::is_same<ToTimeType, boost::units::quantity<ToUnitType, ToValueType>>{} &&
68  std::is_same<FromTimeType, boost::units::quantity<FromUnitType, FromValueType>>{},
69  int>::type = 0>
70 ToTimeType convert(FromTimeType from_time)
71 {
72  return ToTimeType(from_time);
73 };
74 
81 template <typename ToTimeType, typename FromTimeType,
82  typename ToUnitType = typename ToTimeType::unit_type,
83  typename ToValueType = typename ToTimeType::value_type,
84  typename std::enable_if<
85  std::is_same<ToTimeType, boost::units::quantity<ToUnitType, ToValueType>>{} &&
86  (std::is_same<FromTimeType, SystemClock::time_point>{} ||
87  std::is_same<FromTimeType, std::chrono::system_clock::time_point>{}),
88  int>::type = 0>
89 ToTimeType convert(FromTimeType from_time)
90 {
91  std::int64_t microsecs_since_epoch =
92  from_time.time_since_epoch() / std::chrono::microseconds(1);
93  {
94  return ToTimeType(microsecs_since_epoch * boost::units::si::micro *
95  boost::units::si::seconds);
96  }
97 }
98 
105 template <typename ToTimeType, typename FromTimeType,
106  typename FromUnitType = typename FromTimeType::unit_type,
107  typename FromValueType = typename FromTimeType::value_type,
108  typename std::enable_if<
109  (std::is_same<ToTimeType, SystemClock::time_point>{} ||
110  std::is_same<ToTimeType, std::chrono::system_clock::time_point>{}) &&
111  std::is_same<FromTimeType, boost::units::quantity<FromUnitType, FromValueType>>{},
112  int>::type = 0>
113 ToTimeType convert(FromTimeType from_time)
114 {
115  std::int64_t microsecs_since_epoch = MicroTime(from_time).value();
116  auto duration_since_epoch = std::chrono::microseconds(microsecs_since_epoch);
117  return ToTimeType(
118  std::chrono::duration_cast<typename ToTimeType::duration>(duration_since_epoch));
119 }
120 
127 template <typename ToTimeType, typename FromTimeType,
128  typename std::enable_if<!std::is_same<ToTimeType, FromTimeType>{} &&
129  std::is_same<ToTimeType, boost::posix_time::ptime>{},
130  int>::type = 0>
131 ToTimeType convert(FromTimeType from_time)
132 {
133  std::int64_t time_in_value = convert<MicroTime, FromTimeType>(from_time) / MicroTimeUnit();
134 
135  using namespace boost::posix_time;
136  using namespace boost::gregorian;
137 
138  if (time_in_value == -1)
139  return boost::posix_time::ptime(not_a_date_time);
140  else
141  {
142  const int MICROSEC_IN_SEC = 1000000;
143  ptime time_t_epoch(date(1970, 1, 1));
144  std::int64_t m = time_in_value / MICROSEC_IN_SEC / 60;
145  std::int64_t s = (time_in_value / MICROSEC_IN_SEC) - m * 60;
146  std::int64_t micro_s = (time_in_value - (s + m * 60) * MICROSEC_IN_SEC);
147  return time_t_epoch + minutes(m) + seconds(s) + microseconds(micro_s);
148  }
149 }
150 
157 template <typename ToTimeType, typename FromTimeType,
158  typename std::enable_if<!std::is_same<ToTimeType, FromTimeType>{} &&
159  std::is_same<FromTimeType, boost::posix_time::ptime>{},
160  int>::type = 0>
161 ToTimeType convert(FromTimeType from_time)
162 {
163  using namespace boost::posix_time;
164  using namespace boost::gregorian;
165 
166  if (from_time == not_a_date_time)
167  {
168  return convert<ToTimeType, MicroTime>(MicroTime::from_value(-1));
169  }
170  else
171  {
172  const int MICROSEC_IN_SEC = 1000000;
173 
174  date_duration date_diff = from_time.date() - date(1970, 1, 1);
175  time_duration time_diff = from_time.time_of_day();
176 
177  return convert<ToTimeType, MicroTime>(MicroTime::from_value(
178  static_cast<std::int64_t>(date_diff.days()) * 24 * 3600 * MICROSEC_IN_SEC +
179  static_cast<std::int64_t>(time_diff.total_seconds()) * MICROSEC_IN_SEC +
180  static_cast<std::int64_t>(time_diff.fractional_seconds()) /
181  (time_duration::ticks_per_second() / MICROSEC_IN_SEC)));
182  }
183 }
184 
190 template <typename TimeType = SystemClock::time_point>
191 inline std::string str(TimeType value = SystemClock::now<TimeType>())
192 {
193  std::stringstream ss;
194  ss << convert<boost::posix_time::ptime>(value);
195  return ss.str();
196 }
197 
203 template <typename TimeType = SystemClock::time_point>
204 inline std::string file_str(TimeType value = SystemClock::now<TimeType>())
205 {
206  auto rounded_seconds = boost::units::round(convert<SITime, TimeType>(value));
207  return boost::posix_time::to_iso_string(convert<boost::posix_time::ptime>(rounded_seconds));
208 }
209 
216 template <typename ToDurationType, typename FromDurationType,
217  typename std::enable_if<std::is_same<ToDurationType, FromDurationType>{}, int>::type = 0>
218 ToDurationType convert_duration(FromDurationType from_duration)
219 {
220  return from_duration;
221 };
222 
229 template <
230  typename ToDurationType, typename FromDurationType,
231  typename ToUnitType = typename ToDurationType::unit_type,
232  typename ToValueType = typename ToDurationType::value_type,
233  typename FromUnitType = typename FromDurationType::unit_type,
234  typename FromValueType = typename FromDurationType::value_type,
235  typename std::enable_if<
236  !std::is_same<ToDurationType, FromDurationType>{} &&
237  std::is_same<ToDurationType, boost::units::quantity<ToUnitType, ToValueType>>{} &&
238  std::is_same<FromDurationType, boost::units::quantity<FromUnitType, FromValueType>>{},
239  int>::type = 0>
240 ToDurationType convert_duration(FromDurationType from_duration)
241 {
242  return ToDurationType(from_duration);
243 };
244 
251 template <
252  typename ToDurationType, typename FromDurationType,
253  typename ToUnitType = typename ToDurationType::unit_type,
254  typename ToValueType = typename ToDurationType::value_type,
255  typename FromRepType = typename FromDurationType::rep,
256  typename FromPeriodType = typename FromDurationType::period,
257  typename std::enable_if<
258  !std::is_same<ToDurationType, FromDurationType>{} &&
259  std::is_same<ToDurationType, boost::units::quantity<ToUnitType, ToValueType>>{} &&
260  std::is_same<FromDurationType, std::chrono::duration<FromRepType, FromPeriodType>>{},
261  int>::type = 0>
262 ToDurationType convert_duration(FromDurationType from_duration)
263 {
264  return ToDurationType(MicroTime::from_value(
265  std::chrono::duration_cast<std::chrono::microseconds>(from_duration).count()));
266 };
267 
274 template <
275  typename ToDurationType, typename FromDurationType,
276  typename ToRepType = typename ToDurationType::rep,
277  typename ToPeriodType = typename ToDurationType::period,
278  typename FromUnitType = typename FromDurationType::unit_type,
279  typename FromValueType = typename FromDurationType::value_type,
280  typename std::enable_if<
281  !std::is_same<ToDurationType, FromDurationType>{} &&
282  std::is_same<ToDurationType, std::chrono::duration<ToRepType, ToPeriodType>>{} &&
283  std::is_same<FromDurationType, boost::units::quantity<FromUnitType, FromValueType>>{},
284  int>::type = 0>
285 ToDurationType convert_duration(FromDurationType from_duration)
286 {
287  MicroTime microtime_duration(from_duration);
288  return std::chrono::duration_cast<ToDurationType>(
289  std::chrono::microseconds(microtime_duration.value()));
290 };
291 
298 template <typename ToTimeType>
299 ToTimeType
300 convert_from_nmea(const std::string& utc,
301  boost::gregorian::date return_date = boost::gregorian::day_clock::universal_day())
302 {
303  using namespace boost::posix_time;
304  using namespace boost::gregorian;
305 
306  std::string::size_type dot_pos = utc.find('.');
307 
308  // must be at least HHMMSS
309  if (utc.length() < 6)
310  return convert<ToTimeType>(ptime(not_a_date_time));
311  else
312  {
313  std::string s_fs = "0";
314  // has some fractional seconds
315  if (dot_pos != std::string::npos)
316  s_fs = utc.substr(dot_pos + 1); // everything after the "."
317  else
318  dot_pos = utc.size();
319 
320  std::string s_hour = utc.substr(dot_pos - 6, 2), s_min = utc.substr(dot_pos - 4, 2),
321  s_sec = utc.substr(dot_pos - 2, 2);
322 
323  try
324  {
325  int hour = boost::lexical_cast<int>(s_hour);
326  int min = boost::lexical_cast<int>(s_min);
327  int sec = boost::lexical_cast<int>(s_sec);
328  int micro_sec = boost::lexical_cast<int>(s_fs) * pow(10, 6 - s_fs.size());
329 
330  boost::posix_time::time_duration return_duration(
331  boost::posix_time::time_duration(hour, min, sec, 0) + microseconds(micro_sec));
332  boost::posix_time::ptime return_time(return_date, return_duration);
333  return convert<ToTimeType>(return_time);
334  }
335  catch (boost::bad_lexical_cast&)
336  {
337  return convert<ToTimeType>(ptime(not_a_date_time));
338  }
339  }
340 }
341 
348 template <typename ToTimeType>
349 ToTimeType convert_from_nmea(const std::string& utc, const std::string& date)
350 {
351  using namespace boost::posix_time;
352  using namespace boost::gregorian;
353  if (date.length() != 6)
354  return convert<ToTimeType>(ptime(not_a_date_time));
355  else
356  {
357  try
358  {
359  int day = boost::lexical_cast<int>(date.substr(0, 2));
360  int month = boost::lexical_cast<int>(date.substr(2, 2));
361  int year = boost::lexical_cast<int>(date.substr(4, 2));
362 
363  // year that GPS was started
364  if (year >= 78)
365  year += 1900;
366  else
367  year += 2000;
368 
369  boost::gregorian::date d(year, month, day);
370  return convert_from_nmea<ToTimeType>(utc, d);
371  }
372  catch (boost::bad_lexical_cast&)
373  {
374  return convert<ToTimeType>(ptime(not_a_date_time));
375  }
376  }
377 }
378 
379 } // namespace time
380 } // namespace goby
381 
382 template <typename TimeType> TimeType goby::time::SystemClock::now()
383 {
384  return goby::time::convert<TimeType, goby::time::SystemClock::time_point>(now());
385 }
386 
387 #endif
goby::time::SystemClock::now
static time_point now() noexcept
Returns the current system time unless SimulatorSettings::using_sim_time is set to true,...
Definition: system_clock.h:63
system_clock.h
goby::time::convert_from_nmea
ToTimeType convert_from_nmea(const std::string &utc, boost::gregorian::date return_date=boost::gregorian::day_clock::universal_day())
Convert from NMEA0183 time representations (i.e. "HHMMSS[.SSSS]") to any time format supported by the...
Definition: convert.h:300
types.h
goby
The global namespace for the Goby project.
Definition: acomms_constants.h:33
goby::time::str
std::string str(TimeType value=SystemClock::now< TimeType >())
Returns the provided time (or current time if omitted) as a human-readable string.
Definition: convert.h:191
goby::time::convert
ToTimeType convert(FromTimeType from_time)
Convert between time representations (this function works for tautological conversions)
Definition: convert.h:49
goby::time::MicroTimeUnit
decltype(boost::units::si::micro *boost::units::si::seconds) MicroTimeUnit
microsecond unit
Definition: types.h:37
jwt::date
std::chrono::system_clock::time_point date
Definition: jwt.h:79
goby::time::file_str
std::string file_str(TimeType value=SystemClock::now< TimeType >())
Returns the provided time (or current time if omitted) as an ISO string suitable for file names (no s...
Definition: convert.h:204
jwt::json::type
type
Generic JSON types used in JWTs.
Definition: jwt.h:2071
boost::units::si::time
unit< time_dimension, si::system > time
Definition: time.hpp:22
goby::time::convert_duration
ToDurationType convert_duration(FromDurationType from_duration)
Convert between duration representations (this function works for tautological conversions)
Definition: convert.h:218
goby::time::MicroTime
boost::units::quantity< MicroTimeUnit, std::int64_t > MicroTime
quantity of microseconds (using int64)
Definition: types.h:39