clock: Add class for future use
diff --git a/.gitignore b/.gitignore
index c62c609..884d17b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,6 +42,7 @@
 
 # Output binaries
 /example/follow
+/test/clock
 /test/event
 /test/exception
 /test/internal_sdref
diff --git a/src/Makefile.am b/src/Makefile.am
index 2943a2c..a027d5f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -4,6 +4,9 @@
 libsdeventplus_la_SOURCES =
 libsdeventplus_la_LIBADD = $(COMMON_LIBS)
 
+nobase_include_HEADERS += sdeventplus/clock.hpp
+libsdeventplus_la_SOURCES += sdeventplus/clock.cpp
+
 nobase_include_HEADERS += sdeventplus/event.hpp
 libsdeventplus_la_SOURCES += sdeventplus/event.cpp
 
@@ -16,6 +19,8 @@
 nobase_include_HEADERS += sdeventplus/internal/sdref.hpp
 libsdeventplus_la_SOURCES += sdeventplus/internal/sdref.cpp
 
+nobase_include_HEADERS += sdeventplus/internal/utils.hpp
+
 nobase_include_HEADERS += sdeventplus/source/base.hpp
 libsdeventplus_la_SOURCES += sdeventplus/source/base.cpp
 
diff --git a/src/sdeventplus/clock.cpp b/src/sdeventplus/clock.cpp
new file mode 100644
index 0000000..37395c4
--- /dev/null
+++ b/src/sdeventplus/clock.cpp
@@ -0,0 +1,38 @@
+#include <sdeventplus/clock.hpp>
+#include <sdeventplus/exception.hpp>
+#include <sdeventplus/internal/utils.hpp>
+#include <utility>
+
+namespace sdeventplus
+{
+
+template <ClockId Id>
+Clock<Id>::Clock(const Event& event) : event(event)
+{
+}
+
+template <ClockId Id>
+Clock<Id>::Clock(Event&& event) : event(std::move(event))
+{
+}
+
+template <ClockId Id>
+typename Clock<Id>::time_point Clock<Id>::now() const
+{
+    uint64_t now;
+    int r = event.getSdEvent()->sd_event_now(event.get(),
+                                             static_cast<clockid_t>(Id), &now);
+    if (r < 0)
+    {
+        throw SdEventError(-r, "sd_event_now");
+    }
+    return time_point(SdEventDuration(now));
+}
+
+template class Clock<ClockId::RealTime>;
+template class Clock<ClockId::Monotonic>;
+template class Clock<ClockId::BootTime>;
+template class Clock<ClockId::RealTimeAlarm>;
+template class Clock<ClockId::BootTimeAlarm>;
+
+} // namespace sdeventplus
diff --git a/src/sdeventplus/clock.hpp b/src/sdeventplus/clock.hpp
new file mode 100644
index 0000000..c59d721
--- /dev/null
+++ b/src/sdeventplus/clock.hpp
@@ -0,0 +1,41 @@
+#pragma once
+
+#include <chrono>
+#include <cstdint>
+#include <ctime>
+#include <sdeventplus/event.hpp>
+#include <sdeventplus/internal/utils.hpp>
+#include <type_traits>
+
+namespace sdeventplus
+{
+
+enum class ClockId : clockid_t
+{
+    RealTime = CLOCK_REALTIME,
+    Monotonic = CLOCK_MONOTONIC,
+    BootTime = CLOCK_BOOTTIME,
+    RealTimeAlarm = CLOCK_REALTIME_ALARM,
+    BootTimeAlarm = CLOCK_BOOTTIME_ALARM,
+};
+
+template <ClockId Id>
+class Clock
+{
+  public:
+    using rep = SdEventDuration::rep;
+    using period = SdEventDuration::period;
+    using duration = SdEventDuration;
+    using time_point = std::chrono::time_point<Clock>;
+    static constexpr bool is_steady = Id == ClockId::Monotonic;
+
+    Clock(const Event& event);
+    Clock(Event&& event);
+
+    time_point now() const;
+
+  private:
+    const Event event;
+};
+
+} // namespace sdeventplus
diff --git a/src/sdeventplus/internal/sdevent.hpp b/src/sdeventplus/internal/sdevent.hpp
index a3672d1..4baff05 100644
--- a/src/sdeventplus/internal/sdevent.hpp
+++ b/src/sdeventplus/internal/sdevent.hpp
@@ -18,6 +18,10 @@
     virtual sd_event* sd_event_unref(sd_event* event) const = 0;
 
     virtual int sd_event_loop(sd_event* event) const = 0;
+
+    virtual int sd_event_now(sd_event* event, clockid_t clock,
+                             uint64_t* usec) const = 0;
+
     virtual int sd_event_get_watchdog(sd_event* event) const = 0;
     virtual int sd_event_set_watchdog(sd_event* event, int b) const = 0;
 
@@ -74,6 +78,12 @@
         return ::sd_event_loop(event);
     }
 
+    int sd_event_now(sd_event* event, clockid_t clock,
+                     uint64_t* usec) const override
+    {
+        return ::sd_event_now(event, clock, usec);
+    }
+
     int sd_event_get_watchdog(sd_event* event) const override
     {
         return ::sd_event_get_watchdog(event);
diff --git a/src/sdeventplus/internal/utils.hpp b/src/sdeventplus/internal/utils.hpp
new file mode 100644
index 0000000..253e10d
--- /dev/null
+++ b/src/sdeventplus/internal/utils.hpp
@@ -0,0 +1,12 @@
+#pragma once
+
+#include <chrono>
+
+namespace sdeventplus
+{
+
+// Defined by systemd taking uint64_t usec params
+using SdEventDuration =
+    std::chrono::duration<uint64_t, std::chrono::microseconds::period>;
+
+} // namespace sdeventplus
diff --git a/src/sdeventplus/test/sdevent.hpp b/src/sdeventplus/test/sdevent.hpp
index 1cb723f..5f0e400 100644
--- a/src/sdeventplus/test/sdevent.hpp
+++ b/src/sdeventplus/test/sdevent.hpp
@@ -18,6 +18,9 @@
     MOCK_CONST_METHOD1(sd_event_unref, sd_event*(sd_event*));
 
     MOCK_CONST_METHOD1(sd_event_loop, int(sd_event*));
+
+    MOCK_CONST_METHOD3(sd_event_now, int(sd_event*, clockid_t, uint64_t*));
+
     MOCK_CONST_METHOD1(sd_event_get_watchdog, int(sd_event*));
     MOCK_CONST_METHOD2(sd_event_set_watchdog, int(sd_event*, int b));
 
diff --git a/test/Makefile.am b/test/Makefile.am
index 1b4ee1e..d1923fa 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -7,6 +7,11 @@
 check_PROGRAMS =
 TESTS = $(check_PROGRAMS)
 
+check_PROGRAMS += clock
+clock_SOURCES = clock.cpp
+clock_CPPFLAGS = $(gtest_cppflags)
+clock_LDADD = $(gtest_ldadd)
+
 check_PROGRAMS += event
 event_SOURCES = event.cpp
 event_CPPFLAGS = $(gtest_cppflags)
diff --git a/test/clock.cpp b/test/clock.cpp
new file mode 100644
index 0000000..e004341
--- /dev/null
+++ b/test/clock.cpp
@@ -0,0 +1,58 @@
+#include <cerrno>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <sdeventplus/clock.hpp>
+#include <sdeventplus/event.hpp>
+#include <sdeventplus/exception.hpp>
+#include <sdeventplus/test/sdevent.hpp>
+#include <systemd/sd-event.h>
+#include <type_traits>
+#include <utility>
+
+namespace sdeventplus
+{
+namespace
+{
+
+using testing::DoAll;
+using testing::Return;
+using testing::SetArgPointee;
+
+class ClockTest : public testing::Test
+{
+  protected:
+    testing::StrictMock<test::SdEventMock> mock;
+    sd_event* const expected_event = reinterpret_cast<sd_event*>(1234);
+};
+
+TEST_F(ClockTest, CopyEvent)
+{
+    Event event(expected_event, std::false_type(), &mock);
+
+    EXPECT_CALL(mock, sd_event_ref(expected_event))
+        .WillOnce(Return(expected_event));
+    Clock<ClockId::RealTime> clock(event);
+    EXPECT_CALL(mock, sd_event_now(expected_event, CLOCK_REALTIME, testing::_))
+        .WillOnce(DoAll(SetArgPointee<2>(2000000), Return(0)));
+    EXPECT_EQ(Clock<ClockId::RealTime>::time_point(std::chrono::seconds{2}),
+              clock.now());
+
+    EXPECT_CALL(mock, sd_event_unref(expected_event))
+        .Times(2)
+        .WillRepeatedly(Return(nullptr));
+}
+
+TEST_F(ClockTest, MoveEvent)
+{
+    Event event(expected_event, std::false_type(), &mock);
+
+    Clock<ClockId::Monotonic> clock(std::move(event));
+    EXPECT_CALL(mock, sd_event_now(expected_event, CLOCK_MONOTONIC, testing::_))
+        .WillOnce(Return(-EINVAL));
+    EXPECT_THROW(clock.now(), SdEventError);
+
+    EXPECT_CALL(mock, sd_event_unref(expected_event)).WillOnce(Return(nullptr));
+}
+
+} // namespace
+} // namespace sdeventplus