Goby3 3.2.3
2025.05.13
Loading...
Searching...
No Matches
convert.h
Go to the documentation of this file.
1// Copyright 2018-2025:
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
35#include "goby/time/types.h"
36
37namespace goby
38{
39namespace time
40{
47template <typename ToTimeType, typename FromTimeType,
48 typename std::enable_if<std::is_same<ToTimeType, FromTimeType>{}, int>::type = 0>
49ToTimeType convert(FromTimeType from_time)
50{
51 return from_time;
52};
53
60template <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>
70ToTimeType convert(FromTimeType from_time)
71{
72 return ToTimeType(from_time);
73};
74
81template <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>
89ToTimeType 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
105template <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>
113ToTimeType 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
127template <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>
131ToTimeType convert(FromTimeType from_time)
132{
133 std::int64_t time_in_value = convert<MicroTime, FromTimeType>(from_time) / MicroTimeUnit();
134
135 if (time_in_value == -1)
136 return boost::posix_time::ptime(boost::posix_time::not_a_date_time);
137 else
138 {
139 const int MICROSEC_IN_SEC = 1000000;
140 boost::posix_time::ptime time_t_epoch(boost::gregorian::date(1970, 1, 1));
141 std::int64_t m = time_in_value / MICROSEC_IN_SEC / 60;
142 std::int64_t s = (time_in_value / MICROSEC_IN_SEC) - m * 60;
143 std::int64_t micro_s = (time_in_value - (s + m * 60) * MICROSEC_IN_SEC);
144 return time_t_epoch + boost::posix_time::minutes(m) + boost::posix_time::seconds(s) +
145 boost::posix_time::microseconds(micro_s);
146 }
147}
148
155template <typename ToTimeType, typename FromTimeType,
156 typename std::enable_if<!std::is_same<ToTimeType, FromTimeType>{} &&
157 std::is_same<FromTimeType, boost::posix_time::ptime>{},
158 int>::type = 0>
159ToTimeType convert(FromTimeType from_time)
160{
161 if (from_time == boost::posix_time::not_a_date_time)
162 {
163 return convert<ToTimeType, MicroTime>(MicroTime::from_value(-1));
164 }
165 else
166 {
167 const int MICROSEC_IN_SEC = 1000000;
168
169 boost::gregorian::date_duration date_diff =
170 from_time.date() - boost::gregorian::date(1970, 1, 1);
171 boost::posix_time::time_duration time_diff = from_time.time_of_day();
172
173 return convert<ToTimeType, MicroTime>(MicroTime::from_value(
174 static_cast<std::int64_t>(date_diff.days()) * 24 * 3600 * MICROSEC_IN_SEC +
175 static_cast<std::int64_t>(time_diff.total_seconds()) * MICROSEC_IN_SEC +
176 static_cast<std::int64_t>(time_diff.fractional_seconds()) /
177 (boost::posix_time::time_duration::ticks_per_second() / MICROSEC_IN_SEC)));
178 }
179}
180
186template <typename TimeType = SystemClock::time_point>
187inline std::string str(TimeType value = SystemClock::now<TimeType>())
188{
189 std::stringstream ss;
190 ss << convert<boost::posix_time::ptime>(value);
191 return ss.str();
192}
193
199template <typename TimeType = SystemClock::time_point>
200inline std::string file_str(TimeType value = SystemClock::now<TimeType>())
201{
202 auto rounded_seconds = boost::units::round(convert<SITime, TimeType>(value));
203 return boost::posix_time::to_iso_string(convert<boost::posix_time::ptime>(rounded_seconds));
204}
205
212template <typename ToDurationType, typename FromDurationType,
213 typename std::enable_if<std::is_same<ToDurationType, FromDurationType>{}, int>::type = 0>
214ToDurationType convert_duration(FromDurationType from_duration)
215{
216 return from_duration;
217};
218
225template <
226 typename ToDurationType, typename FromDurationType,
227 typename ToUnitType = typename ToDurationType::unit_type,
228 typename ToValueType = typename ToDurationType::value_type,
229 typename FromUnitType = typename FromDurationType::unit_type,
230 typename FromValueType = typename FromDurationType::value_type,
231 typename std::enable_if<
232 !std::is_same<ToDurationType, FromDurationType>{} &&
233 std::is_same<ToDurationType, boost::units::quantity<ToUnitType, ToValueType>>{} &&
234 std::is_same<FromDurationType, boost::units::quantity<FromUnitType, FromValueType>>{},
235 int>::type = 0>
236ToDurationType convert_duration(FromDurationType from_duration)
237{
238 return ToDurationType(from_duration);
239};
240
247template <
248 typename ToDurationType, typename FromDurationType,
249 typename ToUnitType = typename ToDurationType::unit_type,
250 typename ToValueType = typename ToDurationType::value_type,
251 typename FromRepType = typename FromDurationType::rep,
252 typename FromPeriodType = typename FromDurationType::period,
253 typename std::enable_if<
254 !std::is_same<ToDurationType, FromDurationType>{} &&
255 std::is_same<ToDurationType, boost::units::quantity<ToUnitType, ToValueType>>{} &&
256 std::is_same<FromDurationType, std::chrono::duration<FromRepType, FromPeriodType>>{},
257 int>::type = 0>
258ToDurationType convert_duration(FromDurationType from_duration)
259{
260 return ToDurationType(MicroTime::from_value(
261 std::chrono::duration_cast<std::chrono::microseconds>(from_duration).count()));
262};
263
270template <
271 typename ToDurationType, typename FromDurationType,
272 typename ToRepType = typename ToDurationType::rep,
273 typename ToPeriodType = typename ToDurationType::period,
274 typename FromUnitType = typename FromDurationType::unit_type,
275 typename FromValueType = typename FromDurationType::value_type,
276 typename std::enable_if<
277 !std::is_same<ToDurationType, FromDurationType>{} &&
278 std::is_same<ToDurationType, std::chrono::duration<ToRepType, ToPeriodType>>{} &&
279 std::is_same<FromDurationType, boost::units::quantity<FromUnitType, FromValueType>>{},
280 int>::type = 0>
281ToDurationType convert_duration(FromDurationType from_duration)
282{
283 MicroTime microtime_duration(from_duration);
284 return std::chrono::duration_cast<ToDurationType>(
285 std::chrono::microseconds(microtime_duration.value()));
286};
287
294template <typename ToTimeType>
295ToTimeType
296convert_from_nmea(const std::string& utc,
297 boost::gregorian::date return_date = boost::gregorian::day_clock::universal_day())
298{
299 using namespace boost::posix_time;
300 using namespace boost::gregorian;
301
302 std::string::size_type dot_pos = utc.find('.');
303
304 // must be at least HHMMSS
305 if (utc.length() < 6)
306 return convert<ToTimeType>(ptime(not_a_date_time));
307 else
308 {
309 std::string s_fs = "0";
310 // has some fractional seconds
311 if (dot_pos != std::string::npos)
312 s_fs = utc.substr(dot_pos + 1); // everything after the "."
313 else
314 dot_pos = utc.size();
315
316 std::string s_hour = utc.substr(dot_pos - 6, 2), s_min = utc.substr(dot_pos - 4, 2),
317 s_sec = utc.substr(dot_pos - 2, 2);
318
319 try
320 {
321 int hour = boost::lexical_cast<int>(s_hour);
322 int min = boost::lexical_cast<int>(s_min);
323 int sec = boost::lexical_cast<int>(s_sec);
324 int micro_sec = boost::lexical_cast<int>(s_fs) * pow(10, 6 - s_fs.size());
325
326 boost::posix_time::time_duration return_duration(
327 boost::posix_time::time_duration(hour, min, sec, 0) + microseconds(micro_sec));
328 boost::posix_time::ptime return_time(return_date, return_duration);
329 return convert<ToTimeType>(return_time);
330 }
331 catch (boost::bad_lexical_cast&)
332 {
333 return convert<ToTimeType>(ptime(not_a_date_time));
334 }
335 }
336}
337
344template <typename ToTimeType>
345ToTimeType convert_from_nmea(const std::string& utc, const std::string& date)
346{
347 using namespace boost::posix_time;
348 using namespace boost::gregorian;
349 if (date.length() != 6)
350 return convert<ToTimeType>(ptime(not_a_date_time));
351 else
352 {
353 try
354 {
355 int day = boost::lexical_cast<int>(date.substr(0, 2));
356 int month = boost::lexical_cast<int>(date.substr(2, 2));
357 int year = boost::lexical_cast<int>(date.substr(4, 2));
358
359 // year that GPS was started
360 if (year >= 78)
361 year += 1900;
362 else
363 year += 2000;
364
365 boost::gregorian::date d(year, month, day);
366 return convert_from_nmea<ToTimeType>(utc, d);
367 }
368 catch (boost::bad_lexical_cast&)
369 {
370 return convert<ToTimeType>(ptime(not_a_date_time));
371 }
372 }
373}
374
375} // namespace time
376} // namespace goby
377
378template <typename TimeType> TimeType goby::time::SystemClock::now()
379{
380 return goby::time::convert<TimeType, goby::time::SystemClock::time_point>(now());
381}
382
383#endif
unit< time_dimension, si::system > time
Definition time.hpp:22
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:187
ToDurationType convert_duration(FromDurationType from_duration)
Convert between duration representations (this function works for tautological conversions)
Definition convert.h:214
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:296
boost::units::quantity< MicroTimeUnit, std::int64_t > MicroTime
quantity of microseconds (using int64)
Definition types.h:39
ToTimeType convert(FromTimeType from_time)
Convert between time representations (this function works for tautological conversions)
Definition convert.h:49
decltype(boost::units::si::micro *boost::units::si::seconds) MicroTimeUnit
microsecond unit
Definition types.h:37
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:200
The global namespace for the Goby project.
static time_point now() noexcept
Returns the current system time unless SimulatorSettings::using_sim_time is set to true,...