Goby3 3.1.5a
2024.05.23
Loading...
Searching...
No Matches
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
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 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
157template <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>
161ToTimeType 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
190template <typename TimeType = SystemClock::time_point>
191inline 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
203template <typename TimeType = SystemClock::time_point>
204inline 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
216template <typename ToDurationType, typename FromDurationType,
217 typename std::enable_if<std::is_same<ToDurationType, FromDurationType>{}, int>::type = 0>
218ToDurationType convert_duration(FromDurationType from_duration)
219{
220 return from_duration;
221};
222
229template <
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>
240ToDurationType convert_duration(FromDurationType from_duration)
241{
242 return ToDurationType(from_duration);
243};
244
251template <
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>
262ToDurationType 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
274template <
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>
285ToDurationType 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
298template <typename ToTimeType>
299ToTimeType
300convert_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
348template <typename ToTimeType>
349ToTimeType 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
382template <typename TimeType> TimeType goby::time::SystemClock::now()
383{
384 return goby::time::convert<TimeType, goby::time::SystemClock::time_point>(now());
385}
386
387#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:191
ToDurationType convert_duration(FromDurationType from_duration)
Convert between duration representations (this function works for tautological conversions)
Definition convert.h:218
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
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:204
The global namespace for the Goby project.
std::chrono::system_clock::time_point date
Definition jwt.h:79
static time_point now() noexcept
Returns the current system time unless SimulatorSettings::using_sim_time is set to true,...