blob: 0bd07089933647f519b0f3871789eaeb741f499f [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
4#include <stdint.h>
brians57dd5822013-02-27 21:44:15 +00005#include <sys/time.h>
James Kuszmaul651fc3f2019-05-15 21:14:25 -07006#include <time.h>
Brian4a424a22014-04-02 11:52:45 -07007
Austin Schuh793d6b92016-05-01 13:28:14 -07008#include <chrono>
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>
12#include <type_traits>
brians343bc112013-02-10 01:53:46 +000013
John Park33858a32018-09-28 23:05:48 -070014#include "aos/macros.h"
James Kuszmaul651fc3f2019-05-15 21:14:25 -070015#include "aos/type_traits/type_traits.h"
brians343bc112013-02-10 01:53:46 +000016
17namespace aos {
Austin Schuh793d6b92016-05-01 13:28:14 -070018
19class monotonic_clock {
20 public:
21 typedef ::std::chrono::nanoseconds::rep rep;
22 typedef ::std::chrono::nanoseconds::period period;
23 typedef ::std::chrono::nanoseconds duration;
24 typedef ::std::chrono::time_point<monotonic_clock> time_point;
25
26 static monotonic_clock::time_point now() noexcept;
Brian Silvermana3688802019-02-16 19:31:26 -080027 // This clock is still subject to rate adjustments based on adjtime, so it is
28 // not steady.
29 static constexpr bool is_steady = false;
30
Austin Schuh3ce0a922020-07-21 21:08:54 -070031 // Converts the time string to a time_point if it is well formatted. This is
32 // designed to reverse operator <<.
33 static std::optional<monotonic_clock::time_point> FromString(
34 const std::string_view now);
35
Brian Silvermana3688802019-02-16 19:31:26 -080036 // Returns the epoch (0).
37 static constexpr monotonic_clock::time_point epoch() {
38 return time_point(zero());
39 }
40
41 static constexpr monotonic_clock::duration zero() { return duration(0); }
42
43 static constexpr time_point min_time{
44 time_point(duration(::std::numeric_limits<duration::rep>::min()))};
Brian Silverman94357272019-02-23 21:00:54 -080045 static constexpr time_point max_time{
46 time_point(duration(::std::numeric_limits<duration::rep>::max()))};
Brian Silvermana3688802019-02-16 19:31:26 -080047};
48
49class realtime_clock {
50 public:
51 typedef ::std::chrono::nanoseconds::rep rep;
52 typedef ::std::chrono::nanoseconds::period period;
53 typedef ::std::chrono::nanoseconds duration;
Austin Schuh40102d22019-12-27 23:30:06 -080054 typedef ::std::chrono::time_point<realtime_clock> time_point;
Brian Silvermana3688802019-02-16 19:31:26 -080055
56#ifdef __linux__
Austin Schuh40102d22019-12-27 23:30:06 -080057 static realtime_clock::time_point now() noexcept;
Brian Silvermana3688802019-02-16 19:31:26 -080058#endif // __linux__
59 static constexpr bool is_steady = false;
Austin Schuh793d6b92016-05-01 13:28:14 -070060
Austin Schuh3ce0a922020-07-21 21:08:54 -070061 // Converts the time string to a time_point if it is well formatted. This is
62 // designed to reverse operator <<.
63 static std::optional<realtime_clock::time_point> FromString(
64 const std::string_view now);
65
Austin Schuh793d6b92016-05-01 13:28:14 -070066 // Returns the epoch (0).
Austin Schuh40102d22019-12-27 23:30:06 -080067 static constexpr realtime_clock::time_point epoch() {
Austin Schuh8aec1ed2016-05-01 13:29:20 -070068 return time_point(zero());
Austin Schuh793d6b92016-05-01 13:28:14 -070069 }
Austin Schuh8aec1ed2016-05-01 13:29:20 -070070
Austin Schuh40102d22019-12-27 23:30:06 -080071 static constexpr realtime_clock::duration zero() { return duration(0); }
Austin Schuh858c0212016-11-25 17:23:30 -080072
73 static constexpr time_point min_time{
74 time_point(duration(::std::numeric_limits<duration::rep>::min()))};
Brian Silverman94357272019-02-23 21:00:54 -080075 static constexpr time_point max_time{
76 time_point(duration(::std::numeric_limits<duration::rep>::max()))};
Austin Schuh793d6b92016-05-01 13:28:14 -070077};
78
James Kuszmaul38735e82019-12-07 16:42:06 -080079std::ostream &operator<<(std::ostream &stream,
80 const aos::monotonic_clock::time_point &now);
Austin Schuh40102d22019-12-27 23:30:06 -080081std::ostream &operator<<(std::ostream &stream,
82 const aos::realtime_clock::time_point &now);
Austin Schuhde8a8ff2019-11-30 15:25:36 -080083
brians343bc112013-02-10 01:53:46 +000084namespace time {
Brian Silvermanc03a30c2019-02-16 18:21:56 -080085#ifdef __linux__
86
Austin Schuhf2a50ba2016-12-24 16:16:26 -080087// Construct a time representing the period of hertz.
88constexpr ::std::chrono::nanoseconds FromRate(int hertz) {
89 return ::std::chrono::duration_cast<::std::chrono::nanoseconds>(
90 ::std::chrono::seconds(1)) /
91 hertz;
92}
93
James Kuszmaul651fc3f2019-05-15 21:14:25 -070094template <typename Scalar>
95constexpr Scalar TypedDurationInSeconds(monotonic_clock::duration dt) {
96 return ::std::chrono::duration_cast<::std::chrono::duration<Scalar>>(dt)
97 .count();
98}
99
100constexpr double DurationInSeconds(monotonic_clock::duration dt) {
101 return TypedDurationInSeconds<double>(dt);
102}
103
Brian Silvermanc03a30c2019-02-16 18:21:56 -0800104#endif // __linux__
105
Neil Balch229001a2018-01-07 18:22:52 -0800106// Converts a monotonic_clock::duration into a timespec object.
107struct timespec to_timespec(::aos::monotonic_clock::duration duration);
108
109// Converts a monotonic_clock::time_point into a timespec object as time since
110// epoch.
111struct timespec to_timespec(::aos::monotonic_clock::time_point time);
112
Brian Silverman967e5df2020-02-09 16:43:34 -0800113// Converts a timeval object to a monotonic_clock::time_point.
114::aos::monotonic_clock::time_point from_timeval(struct timeval t);
115
Brian Silvermanc03a30c2019-02-16 18:21:56 -0800116namespace time_internal {
117
118template <class T>
119struct is_duration : std::false_type {};
120template <class Rep, class Period>
121struct is_duration<std::chrono::duration<Rep, Period>> : std::true_type {};
122
123} // namespace time_internal
124
125// Returns the greatest duration t representable in ToDuration that is less or
126// equal to d.
127// Implementation copied from
128// https://en.cppreference.com/w/cpp/chrono/duration/floor.
129// TODO(Brian): Remove once we have C++17 support.
130template <class To, class Rep, class Period,
131 class = std::enable_if_t<time_internal::is_duration<To>{}>>
132constexpr To floor(const std::chrono::duration<Rep, Period> &d) {
133 To t = std::chrono::duration_cast<To>(d);
134 if (t > d) return t - To{1};
135 return t;
136}
137
138// Returns the value t representable in ToDuration that is the closest to d. If
139// there are two such values, returns the even value (that is, the value t such
140// that t % 2 == 0).
141// Implementation copied from
142// https://en.cppreference.com/w/cpp/chrono/duration/round.
143// TODO(Brian): Remove once we have C++17 support.
144template <class To, class Rep, class Period,
145 class = std::enable_if_t<
146 time_internal::is_duration<To>{} &&
147 !std::chrono::treat_as_floating_point<typename To::rep>{}>>
148constexpr To round(const std::chrono::duration<Rep, Period> &d) {
149 To t0 = aos::time::floor<To>(d);
150 To t1 = t0 + To{1};
151 auto diff0 = d - t0;
152 auto diff1 = t1 - d;
153 if (diff0 == diff1) {
154 if (t0.count() & 1) return t1;
155 return t0;
156 } else if (diff0 < diff1) {
157 return t0;
158 }
159 return t1;
160}
161
162// Returns the nearest time point to tp representable in ToDuration, rounding to
163// even in halfway cases, like std::chrono::round in C++17.
164// Implementation copied from
165// https://en.cppreference.com/w/cpp/chrono/time_point/round.
166// TODO(Brian): Remove once we have C++17 support.
167template <class To, class Clock, class FromDuration,
168 class = std::enable_if_t<
169 time_internal::is_duration<To>{} &&
170 !std::chrono::treat_as_floating_point<typename To::rep>{}>>
171constexpr std::chrono::time_point<Clock, To> round(
172 const std::chrono::time_point<Clock, FromDuration> &tp) {
173 return std::chrono::time_point<Clock, To>{
174 aos::time::round<To>(tp.time_since_epoch())};
175}
176
brians343bc112013-02-10 01:53:46 +0000177} // namespace time
178} // namespace aos
179
Brian Silvermanc03a30c2019-02-16 18:21:56 -0800180#ifdef __linux__
181
Austin Schuh793d6b92016-05-01 13:28:14 -0700182namespace std {
183namespace this_thread {
184// Template specialization for monotonic_clock, since we can use clock_nanosleep
185// with TIMER_ABSTIME and get very precise absolute time sleeps.
186template <>
187void sleep_until(const ::aos::monotonic_clock::time_point &end_time);
188
189} // namespace this_thread
190} // namespace std
191
Brian Silvermanc03a30c2019-02-16 18:21:56 -0800192#endif // __linux__
Austin Schuh793d6b92016-05-01 13:28:14 -0700193
John Park33858a32018-09-28 23:05:48 -0700194#endif // AOS_TIME_H_