Add support for parsing time strings
This lets us take time strings as command line arguments pretty easily
and manipulate them
Change-Id: I7971cce24a71933c9c1fa9fd13555848efc5964e
diff --git a/aos/time/time.cc b/aos/time/time.cc
index 03fe45b..89f1c4d 100644
--- a/aos/time/time.cc
+++ b/aos/time/time.cc
@@ -3,6 +3,7 @@
#include <inttypes.h>
#include <string.h>
+#include <algorithm>
#include <chrono>
#include <ctime>
#include <iomanip>
@@ -80,6 +81,67 @@
return stream;
}
+std::optional<monotonic_clock::time_point> monotonic_clock::FromString(
+ const std::string_view now) {
+ // This should undo the operator << above.
+ if (now.size() < 14) {
+ return std::nullopt;
+ }
+
+ if (now.substr(now.size() - 3, now.size()) != "sec") {
+ return std::nullopt;
+ }
+
+ if (now.substr(now.size() - 13, 1) != ".") {
+ return std::nullopt;
+ }
+
+ bool negative = now.substr(0, 1) == "-";
+
+ std::string sec(
+ now.substr(negative ? 1 : 0, now.size() - (negative ? 14 : 13)));
+ std::string nsec(now.substr(now.size() - 12, 9));
+
+ if (!std::all_of(sec.begin(), sec.end(), ::isdigit) ||
+ !std::all_of(nsec.begin(), nsec.end(), ::isdigit)) {
+ return std::nullopt;
+ }
+
+ return monotonic_clock::time_point(
+ std::chrono::seconds((negative ? -1 : 1) * atoll(sec.c_str())) +
+ std::chrono::nanoseconds((negative ? -1 : 1) * atoll(nsec.c_str())));
+}
+
+std::optional<realtime_clock::time_point> realtime_clock::FromString(
+ const std::string_view now) {
+ // This should undo the operator << above.
+
+ if (now.size() < 25) {
+ return std::nullopt;
+ }
+
+ if (now.substr(now.size() - 10, 1) != ".") {
+ return std::nullopt;
+ }
+
+ std::string nsec(now.substr(now.size() - 9, 9));
+
+ if (!std::all_of(nsec.begin(), nsec.end(), ::isdigit)) {
+ return std::nullopt;
+ }
+
+ struct tm tm;
+ std::istringstream ss(std::string(now.substr(0, now.size() - 10)));
+ ss >> std::get_time(&tm, "%Y-%m-%d_%H-%M-%S");
+ tm.tm_isdst = -1;
+
+ time_t seconds = mktime(&tm);
+
+ return realtime_clock::time_point(
+ std::chrono::seconds(seconds) +
+ std::chrono::nanoseconds(atoll(nsec.c_str())));
+}
+
std::ostream &operator<<(std::ostream &stream,
const aos::realtime_clock::time_point &now) {
std::tm tm;
diff --git a/aos/time/time.h b/aos/time/time.h
index e31de5c..0bd0708 100644
--- a/aos/time/time.h
+++ b/aos/time/time.h
@@ -6,6 +6,7 @@
#include <time.h>
#include <chrono>
+#include <optional>
#include <ostream>
#include <thread>
#include <type_traits>
@@ -27,6 +28,11 @@
// not steady.
static constexpr bool is_steady = false;
+ // Converts the time string to a time_point if it is well formatted. This is
+ // designed to reverse operator <<.
+ static std::optional<monotonic_clock::time_point> FromString(
+ const std::string_view now);
+
// Returns the epoch (0).
static constexpr monotonic_clock::time_point epoch() {
return time_point(zero());
@@ -52,6 +58,11 @@
#endif // __linux__
static constexpr bool is_steady = false;
+ // Converts the time string to a time_point if it is well formatted. This is
+ // designed to reverse operator <<.
+ static std::optional<realtime_clock::time_point> FromString(
+ const std::string_view now);
+
// Returns the epoch (0).
static constexpr realtime_clock::time_point epoch() {
return time_point(zero());
diff --git a/aos/time/time_test.cc b/aos/time/time_test.cc
index c5eb634..6ff1085 100644
--- a/aos/time/time_test.cc
+++ b/aos/time/time_test.cc
@@ -89,6 +89,7 @@
s << t;
EXPECT_EQ(s.str(), "-13.085000000sec");
+ EXPECT_EQ(monotonic_clock::FromString(s.str()).value(), t);
}
{
const monotonic_clock::time_point t =
@@ -98,6 +99,7 @@
s << t;
EXPECT_EQ(s.str(), "-0.000000001sec");
+ EXPECT_EQ(monotonic_clock::FromString(s.str()).value(), t);
}
{
const monotonic_clock::time_point t =
@@ -107,6 +109,7 @@
s << t;
EXPECT_EQ(s.str(), "-1.000000001sec");
+ EXPECT_EQ(monotonic_clock::FromString(s.str()).value(), t);
}
{
const monotonic_clock::time_point t =
@@ -116,6 +119,7 @@
s << t;
EXPECT_EQ(s.str(), "-2.000000001sec");
+ EXPECT_EQ(monotonic_clock::FromString(s.str()).value(), t);
}
}
@@ -127,6 +131,7 @@
s << t;
EXPECT_EQ(s.str(), "-9223372036.854775808sec");
+ EXPECT_EQ(monotonic_clock::FromString(s.str()).value(), t);
}
// Test that << works with the epoch on the realtime clock.
@@ -137,6 +142,7 @@
s << t;
EXPECT_EQ(s.str(), "1970-01-01_00-00-00.000000000");
+ EXPECT_EQ(realtime_clock::FromString(s.str()).value(), t);
}
// Test that << works with positive time on the realtime clock.
@@ -149,6 +155,7 @@
s << t;
EXPECT_EQ(s.str(), "1970-01-06_00-00-11.005000000");
+ EXPECT_EQ(realtime_clock::FromString(s.str()).value(), t);
}
// Test that << works with negative time on the realtime clock.
@@ -161,6 +168,7 @@
s << t;
EXPECT_EQ(s.str(), "1969-12-31_23-59-59.999999999");
+ EXPECT_EQ(realtime_clock::FromString(s.str()).value(), t);
}
{
const realtime_clock::time_point t =
@@ -170,6 +178,7 @@
s << t;
EXPECT_EQ(s.str(), "1969-12-31_23-59-59.000000001");
+ EXPECT_EQ(realtime_clock::FromString(s.str()).value(), t);
}
{
const realtime_clock::time_point t = realtime_clock::epoch() -
@@ -180,6 +189,7 @@
s << t;
EXPECT_EQ(s.str(), "1969-12-31_23-59-58.000000001");
+ EXPECT_EQ(realtime_clock::FromString(s.str()).value(), t);
}
{
const realtime_clock::time_point t =
@@ -190,6 +200,7 @@
s << t;
EXPECT_EQ(s.str(), "1969-12-27_00-00-10.995000000");
+ EXPECT_EQ(realtime_clock::FromString(s.str()).value(), t);
}
}