Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add string to time function #152

Merged
merged 33 commits into from
Sep 4, 2020
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
ef60586
Added functions to convert between time_point and secNsec
ahcorde Aug 26, 2020
489a79e
Add function to convert a time_point in a string
ahcorde Aug 26, 2020
b7ccbcd
Simplify math in timepoint convertions
ahcorde Aug 26, 2020
770b512
make linters happy
ahcorde Aug 26, 2020
8f13ba3
make linters happy
ahcorde Aug 26, 2020
a9cd19f
make linters happy
ahcorde Aug 26, 2020
b2b1451
Fixed test
ahcorde Aug 27, 2020
0efc2c1
Added test for timePointToString
ahcorde Aug 27, 2020
1b450fa
Add string to time function
Aug 28, 2020
9f14978
Add string to time function
Aug 28, 2020
81c0d78
Merge branch 'jshep1/string_to_chrono_helper' of https://github.com/i…
Aug 28, 2020
b04ca81
Add tests
Aug 28, 2020
ec4845f
Merge branch 'ign-math6' into ahcorde/time/helper_functions
Aug 28, 2020
47debe1
refine a bit
Aug 28, 2020
e5061a4
Added documentation feedback
ahcorde Aug 28, 2020
fef7f9a
Merge branch 'ahcorde/time/helper_functions' of https://github.com/ig…
ahcorde Aug 28, 2020
be5708e
Update result addition
Aug 28, 2020
a866a24
change to auto
Aug 28, 2020
f11f678
Fix macOS build
scpeters Aug 28, 2020
36eb876
Fixed test and added a note with the precision on different OS
ahcorde Aug 31, 2020
ab0e075
Merge branch 'ahcorde/time/helper_functions' of https://github.com/ig…
ahcorde Aug 31, 2020
cacb37b
Revert chrono change
Aug 31, 2020
d512cb8
Merge branch 'ahcorde/time/helper_functions' into jshep1/string_to_ch…
Aug 31, 2020
39304dd
Update empty string and format fixes
Aug 31, 2020
8067150
Change std::chrono::system_clock for std::chrono::steady_clock
ahcorde Sep 1, 2020
76b3555
Removed comment
ahcorde Sep 1, 2020
37038a0
Merge branch 'ahcorde/time/helper_functions' into jshep1/string_to_ch…
Sep 1, 2020
d7c1d31
Update to steady clock
Sep 2, 2020
87d71f8
Added feedback
ahcorde Sep 2, 2020
f9ef912
alphabetize headers in helpers.hh
ahcorde Sep 2, 2020
c5cc779
sync branch
Sep 2, 2020
8fb84ee
sync with math6
Sep 3, 2020
65d145e
fix windows warning
Sep 3, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
212 changes: 208 additions & 4 deletions include/ignition/math/Helpers.hh
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,19 @@
#ifndef IGNITION_MATH_FUNCTIONS_HH_
#define IGNITION_MATH_FUNCTIONS_HH_

#include <algorithm>
#include <chrono>
#include <cmath>
#include <algorithm>
#include <cstdint>
#include <iomanip>
#include <iostream>
#include <limits>
#include <regex>
#include <sstream>
#include <string>
#include <iostream>
#include <vector>
#include <tuple>
#include <utility>
#include <cstdint>
#include <vector>

#include <ignition/math/config.hh>
#include "ignition/math/Export.hh"
Expand Down Expand Up @@ -727,6 +730,43 @@ namespace ignition
}
}

/// \brief Convert a std::chrono::steady_clock::time_point to a seconds and
/// nanoseconds pair.
/// \param[in] _time The time point to convert.
/// \return A pair where the first element is the number of seconds and
/// the second is the number of nanoseconds.
inline std::pair<int64_t, int64_t> timePointToSecNsec(
const std::chrono::system_clock::time_point &_time)
{
auto now_ns = std::chrono::duration_cast<std::chrono::nanoseconds>(
_time.time_since_epoch());
auto now_s = std::chrono::duration_cast<std::chrono::seconds>(
_time.time_since_epoch());
int64_t seconds = std::chrono::duration_cast<std::chrono::seconds>(
_time.time_since_epoch()).count();
int64_t nanoseconds = std::chrono::duration_cast
<std::chrono::nanoseconds>(now_ns - now_s).count();
return {seconds, nanoseconds};
}

/// \brief Convert to a seconds and nanoseconds to
/// std::chrono::steady_clock::time_point.
/// \param[in] _sec The seconds to convert.
/// \param[in] _nanosec The nanoseconds to convert.
/// \return A std::chrono::system_clock::time_poin based on the number of
/// seconds and
/// the number of nanoseconds.
inline std::chrono::system_clock::time_point secNsecToTimePoint(
const uint64_t &_sec, const uint64_t &_nanosec)
{
auto duration = std::chrono::seconds(_sec) + std::chrono::nanoseconds(
_nanosec);
auto result =
std::chrono::system_clock::from_time_t(0);
result += duration;
return result;
}

/// \brief Convert a std::chrono::steady_clock::duration to a seconds and
/// nanoseconds pair.
/// \param[in] _dur The duration to convert.
Expand All @@ -740,6 +780,170 @@ namespace ignition
return {s.count(), ns.count()};
}

// TODO(anyone): Replace this with std::chrono::days.
/// This will exist in C++-20
typedef std::chrono::duration<uint64_t, std::ratio<86400>> days;

/// \brief break down durations
/// \param[in] d Duration to breaw down
/// \return A tuple based on the durations specified
template<class...Durations, class DurationIn>
std::tuple<Durations...> break_down_durations(DurationIn d) {
std::tuple<Durations...> retval;
using discard = int[];
(void)discard{0, (void((
(std::get<Durations>(retval) =
std::chrono::duration_cast<Durations>(d)),
(d -= std::chrono::duration_cast<DurationIn>(
std::get<Durations>(retval))))), 0)...};
return retval;
}

/// \brief Convert a std::chrono::steady_clock::duration to a string
/// \param[in] _point The std::chrono::system_clock::time_point to convert.
/// \return A string formatted with the time_point
inline std::string timePointToString(
const std::chrono::system_clock::time_point &_point)
{
auto duration = _point - std::chrono::system_clock::from_time_t(0);
auto clean_duration = break_down_durations<days,
std::chrono::hours,
std::chrono::minutes,
std::chrono::seconds,
std::chrono::milliseconds>(
duration);
std::ostringstream output_string;
output_string << std::get<0>(clean_duration).count() << " "
<< std::setw(2) << std::setfill('0')
<< std::get<1>(clean_duration).count() << ":"
<< std::setw(2) << std::setfill('0')
<< std::get<2>(clean_duration).count() << ":"
<< std::setw(2) << std::setfill('0')
<< std::setprecision(5)
<< std::get<3>(clean_duration).count() +
std::get<4>(clean_duration).count()/1000.0;
return output_string.str();
}

/// \brief Convert a string to a std::chrono::system_clock::time_point
/// \param[in] _timeString The string to convert in general format
/// "dd hh:mm:ss.nnn" where n is millisecond value
/// \return A std::chrono::system_clock::time_point containing the
/// string's time value
inline std::chrono::system_clock::time_point stringToTimePoint(
const std::string &_timeString)
{
std::chrono::system_clock::time_point timePoint =
std::chrono::system_clock::from_time_t(-1);

// The following regex takes a time string in the general format of
// "dd hh:mm:ss.nnn" where n is milliseconds, if just one number is
// provided, it is assumed to be seconds
std::regex time_regex(
"^([0-9]+ ){0,1}" // day:
// Any positive integer

"(?:([1-9]:|[0-1][0-9]:|2[0-3]:){0,1}" // hour:
// 1-9:
// 01-19:
// 20-23:

"([0-9]:|[0-5][0-9]:)){0,1}" // minute:
// 0-9:
// 00-59:

"(?:([0-9]|[0-5][0-9]){0,1}" // second:
// 0-9
// 00-59

"(\\.[0-9]{1,3}){0,1})$"); // millisecond:
// .0 - .9
// .00 - .99
// .000 - 0.999
std::smatch matches;

// `matches` should always be a size of 6 as there are 6 matching
// groups in the regex.
// 1. The whole regex
// 2. The days
// 3. The hours
// 4. The minutes
// 5. The seconds
// 6. The milliseconds
// We can also index them as such below.
// Note that the space will remain in the day match, the colon
// will remain in the hour and minute matches, and the period will
// remain in the millisecond match
if (!std::regex_search(_timeString, matches, time_regex) ||
matches.size() != 6)
return timePoint;

uint64_t numberDays = 0;
uint64_t numberHours = 0;
uint64_t numberMinutes = 0;
uint64_t numberSeconds = 0;
uint64_t numberMilliseconds = 0;
std::string dayString = matches[1];
std::string hourString = matches[2];
std::string minuteString = matches[3];
std::string secondString = matches[4];
std::string millisecondString = matches[5];

// Days are the only unbounded number, so check first to see if stoi
// runs successfully
if (!dayString.empty())
{
// Erase the space
dayString.erase(dayString.length() - 1);
try
ahcorde marked this conversation as resolved.
Show resolved Hide resolved
{
numberDays = std::stoi(dayString);
}
catch (const std::out_of_range &oor)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

another windows warning found by sdformat:

'oor': unreferenced local variable

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this would be easy enough to fix by just deleting oor:

catch (const std::out_of_range &)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for pointing this out, I'm creating a PR now

{
return timePoint;
}
}

if (!hourString.empty())
{
// Erase the colon
hourString.erase(hourString.length() - 1);
numberHours = std::stoi(hourString);
}

if (!minuteString.empty())
{
// Erase the colon
minuteString.erase(minuteString.length() - 1);
numberMinutes = std::stoi(minuteString);
}

if (!secondString.empty())
{
numberSeconds = std::stoi(secondString);
}

if (!millisecondString.empty())
{
// Erase the period
millisecondString.erase(0, 1);
// Multiplier because "4" = 400 ms, "04" = 40 ms, and "004" = 4 ms
numberMilliseconds = std::stoi(millisecondString) *
JShep1 marked this conversation as resolved.
Show resolved Hide resolved
(1000 / pow(10, millisecondString.length()));
}

timePoint = std::chrono::system_clock::from_time_t(0);
auto duration = std::chrono::milliseconds(numberMilliseconds) +
std::chrono::seconds(numberSeconds) +
std::chrono::minutes(numberMinutes) +
std::chrono::hours(numberHours) +
std::chrono::hours(24 * numberDays);
timePoint += duration;

return timePoint;
}

// Degrade precision on Windows, which cannot handle 'long double'
// values properly. See the implementation of Unpair.
// 32 bit ARM processors also define 'long double' to be the same
Expand Down
Loading