blob: 37ff3a8a55c1d517194bc7e55d0750adeee5e1a8 [file] [log] [blame]
John Park33858a32018-09-28 23:05:48 -07001#ifndef AOS_TIME_H_
2#define AOS_TIME_H_
brians343bc112013-02-10 01:53:46 +00003
brians57dd5822013-02-27 21:44:15 +00004#include <sys/time.h>
Brian4a424a22014-04-02 11:52:45 -07005
Austin Schuh793d6b92016-05-01 13:28:14 -07006#include <chrono>
Tyler Chatowbf0609c2021-07-31 16:13:27 -07007#include <cstdint>
8#include <ctime>
Austin Schuh3ce0a922020-07-21 21:08:54 -07009#include <optional>
brians343bc112013-02-10 01:53:46 +000010#include <ostream>
James Kuszmaul651fc3f2019-05-15 21:14:25 -070011#include <thread>
brians343bc112013-02-10 01:53:46 +000012
13namespace aos {
Austin Schuh793d6b92016-05-01 13:28:14 -070014
15class monotonic_clock {
16 public:
17 typedef ::std::chrono::nanoseconds::rep rep;
18 typedef ::std::chrono::nanoseconds::period period;
19 typedef ::std::chrono::nanoseconds duration;
20 typedef ::std::chrono::time_point<monotonic_clock> time_point;
21
22 static monotonic_clock::time_point now() noexcept;
Brian Silvermana3688802019-02-16 19:31:26 -080023 // This clock is still subject to rate adjustments based on adjtime, so it is
24 // not steady.
25 static constexpr bool is_steady = false;
26
Austin Schuh3ce0a922020-07-21 21:08:54 -070027 // Converts the time string to a time_point if it is well formatted. This is
28 // designed to reverse operator <<.
29 static std::optional<monotonic_clock::time_point> FromString(
30 const std::string_view now);
31
Brian Silvermana3688802019-02-16 19:31:26 -080032 // Returns the epoch (0).
33 static constexpr monotonic_clock::time_point epoch() {
34 return time_point(zero());
35 }
36
37 static constexpr monotonic_clock::duration zero() { return duration(0); }
38
39 static constexpr time_point min_time{
40 time_point(duration(::std::numeric_limits<duration::rep>::min()))};
Brian Silverman94357272019-02-23 21:00:54 -080041 static constexpr time_point max_time{
42 time_point(duration(::std::numeric_limits<duration::rep>::max()))};
Brian Silvermana3688802019-02-16 19:31:26 -080043};
44
45class realtime_clock {
46 public:
47 typedef ::std::chrono::nanoseconds::rep rep;
48 typedef ::std::chrono::nanoseconds::period period;
49 typedef ::std::chrono::nanoseconds duration;
Austin Schuh40102d22019-12-27 23:30:06 -080050 typedef ::std::chrono::time_point<realtime_clock> time_point;
Brian Silvermana3688802019-02-16 19:31:26 -080051
52#ifdef __linux__
Austin Schuh40102d22019-12-27 23:30:06 -080053 static realtime_clock::time_point now() noexcept;
Brian Silvermana3688802019-02-16 19:31:26 -080054#endif // __linux__
55 static constexpr bool is_steady = false;
Austin Schuh793d6b92016-05-01 13:28:14 -070056
Austin Schuh3ce0a922020-07-21 21:08:54 -070057 // Converts the time string to a time_point if it is well formatted. This is
58 // designed to reverse operator <<.
59 static std::optional<realtime_clock::time_point> FromString(
60 const std::string_view now);
61
Austin Schuh793d6b92016-05-01 13:28:14 -070062 // Returns the epoch (0).
Austin Schuh40102d22019-12-27 23:30:06 -080063 static constexpr realtime_clock::time_point epoch() {
Austin Schuh8aec1ed2016-05-01 13:29:20 -070064 return time_point(zero());
Austin Schuh793d6b92016-05-01 13:28:14 -070065 }
Austin Schuh8aec1ed2016-05-01 13:29:20 -070066
Austin Schuh40102d22019-12-27 23:30:06 -080067 static constexpr realtime_clock::duration zero() { return duration(0); }
Austin Schuh858c0212016-11-25 17:23:30 -080068
69 static constexpr time_point min_time{
70 time_point(duration(::std::numeric_limits<duration::rep>::min()))};
Brian Silverman94357272019-02-23 21:00:54 -080071 static constexpr time_point max_time{
72 time_point(duration(::std::numeric_limits<duration::rep>::max()))};
Austin Schuh793d6b92016-05-01 13:28:14 -070073};
74
James Kuszmaul38735e82019-12-07 16:42:06 -080075std::ostream &operator<<(std::ostream &stream,
76 const aos::monotonic_clock::time_point &now);
Austin Schuh40102d22019-12-27 23:30:06 -080077std::ostream &operator<<(std::ostream &stream,
78 const aos::realtime_clock::time_point &now);
Austin Schuhde8a8ff2019-11-30 15:25:36 -080079
brians343bc112013-02-10 01:53:46 +000080namespace time {
Brian Silvermanc03a30c2019-02-16 18:21:56 -080081#ifdef __linux__
82
Austin Schuhf2a50ba2016-12-24 16:16:26 -080083// Construct a time representing the period of hertz.
84constexpr ::std::chrono::nanoseconds FromRate(int hertz) {
85 return ::std::chrono::duration_cast<::std::chrono::nanoseconds>(
86 ::std::chrono::seconds(1)) /
87 hertz;
88}
89
James Kuszmaul651fc3f2019-05-15 21:14:25 -070090template <typename Scalar>
91constexpr Scalar TypedDurationInSeconds(monotonic_clock::duration dt) {
92 return ::std::chrono::duration_cast<::std::chrono::duration<Scalar>>(dt)
93 .count();
94}
95
96constexpr double DurationInSeconds(monotonic_clock::duration dt) {
97 return TypedDurationInSeconds<double>(dt);
98}
99
Brian Silvermanc03a30c2019-02-16 18:21:56 -0800100#endif // __linux__
101
Neil Balch229001a2018-01-07 18:22:52 -0800102// Converts a monotonic_clock::duration into a timespec object.
103struct timespec to_timespec(::aos::monotonic_clock::duration duration);
104
105// Converts a monotonic_clock::time_point into a timespec object as time since
106// epoch.
107struct timespec to_timespec(::aos::monotonic_clock::time_point time);
108
Brian Silverman967e5df2020-02-09 16:43:34 -0800109// Converts a timeval object to a monotonic_clock::time_point.
110::aos::monotonic_clock::time_point from_timeval(struct timeval t);
111
Brian Silvermanc03a30c2019-02-16 18:21:56 -0800112namespace time_internal {
113
114template <class T>
115struct is_duration : std::false_type {};
116template <class Rep, class Period>
117struct is_duration<std::chrono::duration<Rep, Period>> : std::true_type {};
118
119} // namespace time_internal
120
121// Returns the greatest duration t representable in ToDuration that is less or
122// equal to d.
123// Implementation copied from
124// https://en.cppreference.com/w/cpp/chrono/duration/floor.
125// TODO(Brian): Remove once we have C++17 support.
126template <class To, class Rep, class Period,
127 class = std::enable_if_t<time_internal::is_duration<To>{}>>
128constexpr To floor(const std::chrono::duration<Rep, Period> &d) {
129 To t = std::chrono::duration_cast<To>(d);
130 if (t > d) return t - To{1};
131 return t;
132}
133
134// Returns the value t representable in ToDuration that is the closest to d. If
135// there are two such values, returns the even value (that is, the value t such
136// that t % 2 == 0).
137// Implementation copied from
138// https://en.cppreference.com/w/cpp/chrono/duration/round.
139// TODO(Brian): Remove once we have C++17 support.
140template <class To, class Rep, class Period,
141 class = std::enable_if_t<
142 time_internal::is_duration<To>{} &&
143 !std::chrono::treat_as_floating_point<typename To::rep>{}>>
144constexpr To round(const std::chrono::duration<Rep, Period> &d) {
145 To t0 = aos::time::floor<To>(d);
146 To t1 = t0 + To{1};
147 auto diff0 = d - t0;
148 auto diff1 = t1 - d;
149 if (diff0 == diff1) {
150 if (t0.count() & 1) return t1;
151 return t0;
152 } else if (diff0 < diff1) {
153 return t0;
154 }
155 return t1;
156}
157
158// Returns the nearest time point to tp representable in ToDuration, rounding to
159// even in halfway cases, like std::chrono::round in C++17.
160// Implementation copied from
161// https://en.cppreference.com/w/cpp/chrono/time_point/round.
162// TODO(Brian): Remove once we have C++17 support.
163template <class To, class Clock, class FromDuration,
164 class = std::enable_if_t<
165 time_internal::is_duration<To>{} &&
166 !std::chrono::treat_as_floating_point<typename To::rep>{}>>
167constexpr std::chrono::time_point<Clock, To> round(
168 const std::chrono::time_point<Clock, FromDuration> &tp) {
169 return std::chrono::time_point<Clock, To>{
170 aos::time::round<To>(tp.time_since_epoch())};
171}
172
brians343bc112013-02-10 01:53:46 +0000173} // namespace time
174} // namespace aos
175
Brian Silvermanc03a30c2019-02-16 18:21:56 -0800176#ifdef __linux__
177
Austin Schuh793d6b92016-05-01 13:28:14 -0700178namespace std {
179namespace this_thread {
180// Template specialization for monotonic_clock, since we can use clock_nanosleep
181// with TIMER_ABSTIME and get very precise absolute time sleeps.
182template <>
183void sleep_until(const ::aos::monotonic_clock::time_point &end_time);
184
185} // namespace this_thread
186} // namespace std
187
Brian Silvermanc03a30c2019-02-16 18:21:56 -0800188#endif // __linux__
Austin Schuh793d6b92016-05-01 13:28:14 -0700189
John Park33858a32018-09-28 23:05:48 -0700190#endif // AOS_TIME_H_