Fixed issue with wrong timestamp

Telemetry service used steady_clock for generating timestamps, but it
produced incorrect time. This change makes telemetry service use
steady_clock for intervals and system_clock for timestamps.

Changed readings timestamp to display current timestamp instead of a
time when reading was received.

Tested:
- correct timestamp is visible on dbus
- other telemetry service features are still working

Change-Id: Ic49f45640532cfffaeff5e0bd5591e6d99e5def5
Signed-off-by: Krzysztof Grobelny <krzysztof.grobelny@intel.com>
diff --git a/src/details/collection_function.cpp b/src/details/collection_function.cpp
index d92fdf3..360f082 100644
--- a/src/details/collection_function.cpp
+++ b/src/details/collection_function.cpp
@@ -8,101 +8,105 @@
 class FunctionSingle : public CollectionFunction
 {
   public:
-    ReadingItem calculate(const std::vector<ReadingItem>& readings,
-                          uint64_t) const override
+    double calculate(const std::vector<ReadingItem>& readings,
+                     Milliseconds) const override
     {
-        return readings.back();
+        return readings.back().second;
     }
 
-    ReadingItem calculateForStartupInterval(std::vector<ReadingItem>& readings,
-                                            uint64_t timestamp) const override
+    double calculateForStartupInterval(std::vector<ReadingItem>& readings,
+                                       Milliseconds) const override
     {
         readings.assign({readings.back()});
-        return readings.back();
+        return readings.back().second;
     }
 };
 
 class FunctionMinimum : public CollectionFunction
 {
   public:
-    ReadingItem calculate(const std::vector<ReadingItem>& readings,
-                          uint64_t) const override
+    double calculate(const std::vector<ReadingItem>& readings,
+                     Milliseconds) const override
     {
-        return *std::min_element(
-            readings.begin(), readings.end(),
-            [](const auto& left, const auto& right) {
-                return std::make_tuple(!std::isfinite(left.second),
-                                       left.second) <
-                       std::make_tuple(!std::isfinite(right.second),
-                                       right.second);
-            });
+        return std::min_element(
+                   readings.begin(), readings.end(),
+                   [](const auto& left, const auto& right) {
+                       return std::make_tuple(!std::isfinite(left.second),
+                                              left.second) <
+                              std::make_tuple(!std::isfinite(right.second),
+                                              right.second);
+                   })
+            ->second;
     }
 
-    ReadingItem calculateForStartupInterval(std::vector<ReadingItem>& readings,
-                                            uint64_t timestamp) const override
+    double calculateForStartupInterval(std::vector<ReadingItem>& readings,
+                                       Milliseconds timestamp) const override
     {
-        readings.assign({ReadingItem(calculate(readings, timestamp))});
-        return readings.back();
+        readings.assign(
+            {ReadingItem(timestamp, calculate(readings, timestamp))});
+        return readings.back().second;
     }
 };
 
 class FunctionMaximum : public CollectionFunction
 {
   public:
-    ReadingItem calculate(const std::vector<ReadingItem>& readings,
-                          uint64_t) const override
+    double calculate(const std::vector<ReadingItem>& readings,
+                     Milliseconds) const override
     {
-        return *std::max_element(
-            readings.begin(), readings.end(),
-            [](const auto& left, const auto& right) {
-                return std::make_tuple(std::isfinite(left.second),
-                                       left.second) <
-                       std::make_tuple(std::isfinite(right.second),
-                                       right.second);
-            });
+        return std::max_element(
+                   readings.begin(), readings.end(),
+                   [](const auto& left, const auto& right) {
+                       return std::make_tuple(std::isfinite(left.second),
+                                              left.second) <
+                              std::make_tuple(std::isfinite(right.second),
+                                              right.second);
+                   })
+            ->second;
     }
 
-    ReadingItem calculateForStartupInterval(std::vector<ReadingItem>& readings,
-                                            uint64_t timestamp) const override
+    double calculateForStartupInterval(std::vector<ReadingItem>& readings,
+                                       Milliseconds timestamp) const override
     {
-        readings.assign({ReadingItem(calculate(readings, timestamp))});
-        return readings.back();
+        readings.assign(
+            {ReadingItem(timestamp, calculate(readings, timestamp))});
+        return readings.back().second;
     }
 };
 
 class FunctionAverage : public CollectionFunction
 {
   public:
-    ReadingItem calculate(const std::vector<ReadingItem>& readings,
-                          uint64_t timestamp) const override
+    double calculate(const std::vector<ReadingItem>& readings,
+                     Milliseconds timestamp) const override
     {
         auto valueSum = 0.0;
-        auto timeSum = uint64_t{0};
+        auto timeSum = Milliseconds{0};
         for (auto it = readings.begin(); it != std::prev(readings.end()); ++it)
         {
             if (std::isfinite(it->second))
             {
                 const auto kt = std::next(it);
                 const auto duration = kt->first - it->first;
-                valueSum += it->second * duration;
+                valueSum += it->second * duration.count();
                 timeSum += duration;
             }
         }
 
         const auto duration = timestamp - readings.back().first;
-        valueSum += readings.back().second * duration;
+        valueSum += readings.back().second * duration.count();
         timeSum += duration;
 
-        return ReadingItem{timestamp, valueSum / timeSum};
+        return valueSum / std::max(timeSum.count(), uint64_t{1u});
     }
 
-    ReadingItem calculateForStartupInterval(std::vector<ReadingItem>& readings,
-                                            uint64_t timestamp) const override
+    double calculateForStartupInterval(std::vector<ReadingItem>& readings,
+                                       Milliseconds timestamp) const override
     {
         auto result = calculate(readings, timestamp);
-        if (std::isfinite(result.second))
+        if (std::isfinite(result))
         {
-            readings.assign({ReadingItem(readings.front().first, result.second),
+            readings.assign({ReadingItem(readings.front().first, result),
                              ReadingItem(timestamp, readings.back().second)});
         }
         return result;
@@ -111,9 +115,11 @@
 
 class FunctionSummation : public CollectionFunction
 {
+    using Multiplier = std::chrono::duration<double>;
+
   public:
-    ReadingItem calculate(const std::vector<ReadingItem>& readings,
-                          uint64_t timestamp) const override
+    double calculate(const std::vector<ReadingItem>& readings,
+                     const Milliseconds timestamp) const override
     {
         auto valueSum = 0.0;
         for (auto it = readings.begin(); it != std::prev(readings.end()); ++it)
@@ -121,28 +127,45 @@
             if (std::isfinite(it->second))
             {
                 const auto kt = std::next(it);
-                const auto duration = kt->first - it->first;
-                valueSum += it->second * duration;
+                const auto multiplier =
+                    calculateMultiplier(kt->first - it->first);
+                valueSum += it->second * multiplier.count();
             }
         }
 
-        const auto duration = timestamp - readings.back().first;
-        valueSum += readings.back().second * duration;
+        const auto multiplier =
+            calculateMultiplier(timestamp - readings.back().first);
+        valueSum += readings.back().second * multiplier.count();
 
-        return ReadingItem{timestamp, valueSum};
+        return valueSum;
     }
 
-    ReadingItem calculateForStartupInterval(std::vector<ReadingItem>& readings,
-                                            uint64_t timestamp) const override
+    double
+        calculateForStartupInterval(std::vector<ReadingItem>& readings,
+                                    const Milliseconds timestamp) const override
     {
-        auto result = calculate(readings, timestamp);
-        if (std::isfinite(result.second) && timestamp > 0u)
+        const auto result = calculate(readings, timestamp);
+        if (readings.size() > 2 && std::isfinite(result))
         {
-            readings.assign({ReadingItem(timestamp - 1u, result.second),
-                             ReadingItem(timestamp, readings.back().second)});
+            const auto multiplier =
+                calculateMultiplier(timestamp - readings.front().first).count();
+            if (multiplier > 0.)
+            {
+                const auto prevValue = result / multiplier;
+                readings.assign(
+                    {ReadingItem(readings.front().first, prevValue),
+                     ReadingItem(timestamp, readings.back().second)});
+            }
         }
         return result;
     }
+
+  private:
+    static constexpr Multiplier calculateMultiplier(Milliseconds duration)
+    {
+        constexpr auto m = Multiplier{Seconds{1}};
+        return Multiplier{duration / m};
+    }
 };
 
 std::shared_ptr<CollectionFunction>
diff --git a/src/details/collection_function.hpp b/src/details/collection_function.hpp
index a8708e7..ca653a1 100644
--- a/src/details/collection_function.hpp
+++ b/src/details/collection_function.hpp
@@ -1,5 +1,6 @@
 #pragma once
 
+#include "types/duration_types.hpp"
 #include "types/operation_type.hpp"
 
 #include <cstdint>
@@ -10,18 +11,18 @@
 namespace details
 {
 
-using ReadingItem = std::pair<uint64_t, double>;
+using ReadingItem = std::pair<Milliseconds, double>;
 
 class CollectionFunction
 {
   public:
     virtual ~CollectionFunction() = default;
 
-    virtual ReadingItem calculate(const std::vector<ReadingItem>& readings,
-                                  uint64_t timestamp) const = 0;
-    virtual ReadingItem
+    virtual double calculate(const std::vector<ReadingItem>& readings,
+                             Milliseconds timestamp) const = 0;
+    virtual double
         calculateForStartupInterval(std::vector<ReadingItem>& readings,
-                                    uint64_t timestamp) const = 0;
+                                    Milliseconds timestamp) const = 0;
 };
 
 std::shared_ptr<CollectionFunction> makeCollectionFunction(OperationType);
diff --git a/src/discrete_threshold.cpp b/src/discrete_threshold.cpp
index 89a1b7c..25cc46f 100644
--- a/src/discrete_threshold.cpp
+++ b/src/discrete_threshold.cpp
@@ -37,11 +37,11 @@
 }
 
 void DiscreteThreshold::sensorUpdated(interfaces::Sensor& sensor,
-                                      uint64_t timestamp)
+                                      Milliseconds timestamp)
 {}
 
 void DiscreteThreshold::sensorUpdated(interfaces::Sensor& sensor,
-                                      uint64_t timestamp, double value)
+                                      Milliseconds timestamp, double value)
 {
     auto& [sensorName, dwell, timer] = getDetails(sensor);
 
@@ -60,7 +60,7 @@
 }
 
 void DiscreteThreshold::startTimer(interfaces::Sensor& sensor,
-                                   uint64_t timestamp, double value)
+                                   Milliseconds timestamp, double value)
 {
     auto& [sensorName, dwell, timer] = getDetails(sensor);
     if (dwellTime == Milliseconds::zero())
@@ -87,7 +87,7 @@
 }
 
 void DiscreteThreshold::commit(const std::string& sensorName,
-                               uint64_t timestamp, double value)
+                               Milliseconds timestamp, double value)
 {
     for (const auto& action : actions)
     {
diff --git a/src/discrete_threshold.hpp b/src/discrete_threshold.hpp
index 8dc2eeb..636a4f5 100644
--- a/src/discrete_threshold.hpp
+++ b/src/discrete_threshold.hpp
@@ -4,7 +4,7 @@
 #include "interfaces/sensor_listener.hpp"
 #include "interfaces/threshold.hpp"
 #include "interfaces/trigger_action.hpp"
-#include "types/milliseconds.hpp"
+#include "types/duration_types.hpp"
 #include "types/trigger_types.hpp"
 
 #include <boost/asio/steady_timer.hpp>
@@ -30,8 +30,8 @@
     {}
 
     void initialize() override;
-    void sensorUpdated(interfaces::Sensor&, uint64_t) override;
-    void sensorUpdated(interfaces::Sensor&, uint64_t, double) override;
+    void sensorUpdated(interfaces::Sensor&, Milliseconds) override;
+    void sensorUpdated(interfaces::Sensor&, Milliseconds, double) override;
 
   private:
     boost::asio::io_context& ioc;
@@ -55,7 +55,7 @@
     };
     std::vector<ThresholdDetail> details;
 
-    void startTimer(interfaces::Sensor&, uint64_t, double);
-    void commit(const std::string&, uint64_t, double);
+    void startTimer(interfaces::Sensor&, Milliseconds, double);
+    void commit(const std::string&, Milliseconds, double);
     ThresholdDetail& getDetails(interfaces::Sensor& sensor);
 };
diff --git a/src/interfaces/clock.hpp b/src/interfaces/clock.hpp
index 0c355b7..b37ff3a 100644
--- a/src/interfaces/clock.hpp
+++ b/src/interfaces/clock.hpp
@@ -1,5 +1,7 @@
 #pragma once
 
+#include "types/duration_types.hpp"
+
 #include <chrono>
 
 namespace interfaces
@@ -8,15 +10,10 @@
 class Clock
 {
   public:
-    using duration = std::chrono::steady_clock::time_point::duration;
-    using rep = std::chrono::steady_clock::time_point::rep;
-    using period = std::chrono::steady_clock::time_point::period;
-    using time_point = std::chrono::steady_clock::time_point;
-
     virtual ~Clock() = default;
 
-    virtual time_point now() const noexcept = 0;
-    virtual uint64_t timestamp() const noexcept = 0;
+    virtual Milliseconds steadyTimestamp() const noexcept = 0;
+    virtual Milliseconds systemTimestamp() const noexcept = 0;
 };
 
 } // namespace interfaces
diff --git a/src/interfaces/sensor_listener.hpp b/src/interfaces/sensor_listener.hpp
index 9406da6..a47c8d4 100644
--- a/src/interfaces/sensor_listener.hpp
+++ b/src/interfaces/sensor_listener.hpp
@@ -1,5 +1,7 @@
 #pragma once
 
+#include "types/duration_types.hpp"
+
 #include <cstdint>
 #include <optional>
 
@@ -13,8 +15,8 @@
   public:
     virtual ~SensorListener() = default;
 
-    virtual void sensorUpdated(interfaces::Sensor&, uint64_t) = 0;
-    virtual void sensorUpdated(interfaces::Sensor&, uint64_t, double) = 0;
+    virtual void sensorUpdated(interfaces::Sensor&, Milliseconds) = 0;
+    virtual void sensorUpdated(interfaces::Sensor&, Milliseconds, double) = 0;
 };
 
 } // namespace interfaces
diff --git a/src/interfaces/trigger_action.hpp b/src/interfaces/trigger_action.hpp
index d21f238..437a79f 100644
--- a/src/interfaces/trigger_action.hpp
+++ b/src/interfaces/trigger_action.hpp
@@ -1,5 +1,7 @@
 #pragma once
 
+#include "types/duration_types.hpp"
+
 #include <cstdint>
 #include <string>
 
@@ -11,7 +13,7 @@
   public:
     virtual ~TriggerAction() = default;
 
-    virtual void commit(const std::string& id, uint64_t timestamp,
+    virtual void commit(const std::string& id, Milliseconds timestamp,
                         double value) = 0;
 };
 } // namespace interfaces
diff --git a/src/metric.cpp b/src/metric.cpp
index ee12c74..d8241b9 100644
--- a/src/metric.cpp
+++ b/src/metric.cpp
@@ -16,28 +16,26 @@
 
     virtual ~CollectionData() = default;
 
-    virtual ReadingItem update(uint64_t timestamp) = 0;
-    virtual ReadingItem update(uint64_t timestamp, double value) = 0;
+    virtual std::optional<double> update(Milliseconds timestamp) = 0;
+    virtual double update(Milliseconds timestamp, double value) = 0;
 };
 
 class Metric::DataPoint : public Metric::CollectionData
 {
   public:
-    ReadingItem update(uint64_t timestamp) override
+    std::optional<double> update(Milliseconds) override
     {
-        return ReadingItem{lastTimestamp, lastReading};
+        return lastReading;
     }
 
-    ReadingItem update(uint64_t timestamp, double reading) override
+    double update(Milliseconds, double reading) override
     {
-        lastTimestamp = timestamp;
         lastReading = reading;
-        return update(timestamp);
+        return reading;
     }
 
   private:
-    uint64_t lastTimestamp = 0u;
-    double lastReading = 0.0;
+    std::optional<double> lastReading;
 };
 
 class Metric::DataInterval : public Metric::CollectionData
@@ -56,43 +54,51 @@
         }
     }
 
-    ReadingItem update(uint64_t timestamp) override
+    std::optional<double> update(Milliseconds timestamp) override
     {
-        if (readings.size() > 0)
+        if (readings.empty())
         {
-            auto it = readings.begin();
-            for (auto kt = std::next(readings.rbegin()); kt != readings.rend();
-                 ++kt)
-            {
-                const auto& [nextItemTimestamp, nextItemReading] =
-                    *std::prev(kt);
-                if (timestamp >= nextItemTimestamp &&
-                    static_cast<uint64_t>(timestamp - nextItemTimestamp) >
-                        duration.t.count())
-                {
-                    it = kt.base();
-                    break;
-                }
-            }
-            readings.erase(readings.begin(), it);
-
-            if (timestamp > duration.t.count())
-            {
-                readings.front().first = std::max(
-                    readings.front().first, timestamp - duration.t.count());
-            }
+            return std::nullopt;
         }
 
+        cleanup(timestamp);
+
         return function->calculate(readings, timestamp);
     }
 
-    ReadingItem update(uint64_t timestamp, double reading) override
+    double update(Milliseconds timestamp, double reading) override
     {
         readings.emplace_back(timestamp, reading);
-        return update(timestamp);
+
+        cleanup(timestamp);
+
+        return function->calculate(readings, timestamp);
     }
 
   private:
+    void cleanup(Milliseconds timestamp)
+    {
+        auto it = readings.begin();
+        for (auto kt = std::next(readings.rbegin()); kt != readings.rend();
+             ++kt)
+        {
+            const auto& [nextItemTimestamp, nextItemReading] = *std::prev(kt);
+            if (timestamp >= nextItemTimestamp &&
+                timestamp - nextItemTimestamp > duration.t)
+            {
+                it = kt.base();
+                break;
+            }
+        }
+        readings.erase(readings.begin(), it);
+
+        if (timestamp > duration.t)
+        {
+            readings.front().first =
+                std::max(readings.front().first, timestamp - duration.t);
+        }
+    }
+
     std::shared_ptr<details::CollectionFunction> function;
     std::vector<ReadingItem> readings;
     CollectionDuration duration;
@@ -105,12 +111,17 @@
         function(std::move(function))
     {}
 
-    ReadingItem update(uint64_t timestamp) override
+    std::optional<double> update(Milliseconds timestamp) override
     {
+        if (readings.empty())
+        {
+            return std::nullopt;
+        }
+
         return function->calculateForStartupInterval(readings, timestamp);
     }
 
-    ReadingItem update(uint64_t timestamp, double reading) override
+    double update(Milliseconds timestamp, double reading) override
     {
         readings.emplace_back(timestamp, reading);
         return function->calculateForStartupInterval(readings, timestamp);
@@ -158,24 +169,31 @@
 
 std::vector<MetricValue> Metric::getReadings() const
 {
-    const auto timestamp = clock->timestamp();
+    const auto steadyTimestamp = clock->steadyTimestamp();
+    const auto systemTimestamp = clock->systemTimestamp();
+
     auto resultReadings = readings;
 
     for (size_t i = 0; i < resultReadings.size(); ++i)
     {
-        std::tie(resultReadings[i].timestamp, resultReadings[i].value) =
-            collectionAlgorithms[i]->update(timestamp);
+        if (const auto value = collectionAlgorithms[i]->update(steadyTimestamp))
+        {
+            resultReadings[i].timestamp =
+                std::chrono::duration_cast<Milliseconds>(systemTimestamp)
+                    .count();
+            resultReadings[i].value = *value;
+        }
     }
 
     return resultReadings;
 }
 
-void Metric::sensorUpdated(interfaces::Sensor& notifier, uint64_t timestamp)
+void Metric::sensorUpdated(interfaces::Sensor& notifier, Milliseconds timestamp)
 {
     findAssociatedData(notifier).update(timestamp);
 }
 
-void Metric::sensorUpdated(interfaces::Sensor& notifier, uint64_t timestamp,
+void Metric::sensorUpdated(interfaces::Sensor& notifier, Milliseconds timestamp,
                            double value)
 {
     findAssociatedData(notifier).update(timestamp, value);
diff --git a/src/metric.hpp b/src/metric.hpp
index 1ff5bc2..859315e 100644
--- a/src/metric.hpp
+++ b/src/metric.hpp
@@ -19,8 +19,9 @@
     void initialize() override;
     void deinitialize() override;
     std::vector<MetricValue> getReadings() const override;
-    void sensorUpdated(interfaces::Sensor&, uint64_t) override;
-    void sensorUpdated(interfaces::Sensor&, uint64_t, double value) override;
+    void sensorUpdated(interfaces::Sensor&, Milliseconds) override;
+    void sensorUpdated(interfaces::Sensor&, Milliseconds,
+                       double value) override;
     LabeledMetricParameters dumpConfiguration() const override;
     uint64_t sensorCount() const override;
 
diff --git a/src/numeric_threshold.cpp b/src/numeric_threshold.cpp
index ebb7826..3bec427 100644
--- a/src/numeric_threshold.cpp
+++ b/src/numeric_threshold.cpp
@@ -42,11 +42,11 @@
 }
 
 void NumericThreshold::sensorUpdated(interfaces::Sensor& sensor,
-                                     uint64_t timestamp)
+                                     Milliseconds timestamp)
 {}
 
 void NumericThreshold::sensorUpdated(interfaces::Sensor& sensor,
-                                     uint64_t timestamp, double value)
+                                     Milliseconds timestamp, double value)
 {
     auto& [sensorName, prevValue, dwell, timer] = getDetails(sensor);
     bool decreasing = thresholdValue < prevValue && thresholdValue > value;
@@ -68,8 +68,8 @@
 }
 
 void NumericThreshold::startTimer(const std::string& sensorName,
-                                  uint64_t timestamp, double value, bool& dwell,
-                                  boost::asio::steady_timer& timer)
+                                  Milliseconds timestamp, double value,
+                                  bool& dwell, boost::asio::steady_timer& timer)
 {
     if (dwellTime == Milliseconds::zero())
     {
@@ -93,8 +93,8 @@
     }
 }
 
-void NumericThreshold::commit(const std::string& sensorName, uint64_t timestamp,
-                              double value)
+void NumericThreshold::commit(const std::string& sensorName,
+                              Milliseconds timestamp, double value)
 {
     for (const auto& action : actions)
     {
diff --git a/src/numeric_threshold.hpp b/src/numeric_threshold.hpp
index 338d00b..2aff15c 100644
--- a/src/numeric_threshold.hpp
+++ b/src/numeric_threshold.hpp
@@ -4,7 +4,7 @@
 #include "interfaces/sensor_listener.hpp"
 #include "interfaces/threshold.hpp"
 #include "interfaces/trigger_action.hpp"
-#include "types/milliseconds.hpp"
+#include "types/duration_types.hpp"
 #include "types/trigger_types.hpp"
 
 #include <boost/asio/steady_timer.hpp>
@@ -28,8 +28,8 @@
     ~NumericThreshold();
 
     void initialize() override;
-    void sensorUpdated(interfaces::Sensor&, uint64_t) override;
-    void sensorUpdated(interfaces::Sensor&, uint64_t, double) override;
+    void sensorUpdated(interfaces::Sensor&, Milliseconds) override;
+    void sensorUpdated(interfaces::Sensor&, Milliseconds, double) override;
 
   private:
     boost::asio::io_context& ioc;
@@ -54,8 +54,8 @@
     };
     std::vector<ThresholdDetail> details;
 
-    void startTimer(const std::string&, uint64_t, double, bool&,
+    void startTimer(const std::string&, Milliseconds, double, bool&,
                     boost::asio::steady_timer&);
-    void commit(const std::string&, uint64_t, double);
+    void commit(const std::string&, Milliseconds, double);
     ThresholdDetail& getDetails(interfaces::Sensor& sensor);
 };
diff --git a/src/on_change_threshold.cpp b/src/on_change_threshold.cpp
index 5285ee3..e278c7f 100644
--- a/src/on_change_threshold.cpp
+++ b/src/on_change_threshold.cpp
@@ -18,11 +18,11 @@
 }
 
 void OnChangeThreshold::sensorUpdated(interfaces::Sensor& sensor,
-                                      uint64_t timestamp)
+                                      Milliseconds timestamp)
 {}
 
 void OnChangeThreshold::sensorUpdated(interfaces::Sensor& sensor,
-                                      uint64_t timestamp, double value)
+                                      Milliseconds timestamp, double value)
 {
     auto it =
         std::find_if(sensors.begin(), sensors.end(),
@@ -32,7 +32,7 @@
 }
 
 void OnChangeThreshold::commit(const std::string& sensorName,
-                               uint64_t timestamp, double value)
+                               Milliseconds timestamp, double value)
 {
     for (const auto& action : actions)
     {
diff --git a/src/on_change_threshold.hpp b/src/on_change_threshold.hpp
index 7eb1f6d..61c75d5 100644
--- a/src/on_change_threshold.hpp
+++ b/src/on_change_threshold.hpp
@@ -25,13 +25,13 @@
     {}
 
     void initialize() override;
-    void sensorUpdated(interfaces::Sensor&, uint64_t) override;
-    void sensorUpdated(interfaces::Sensor&, uint64_t, double) override;
+    void sensorUpdated(interfaces::Sensor&, Milliseconds) override;
+    void sensorUpdated(interfaces::Sensor&, Milliseconds, double) override;
 
   private:
     const Sensors sensors;
     const std::vector<std::string> sensorNames;
     const std::vector<std::unique_ptr<interfaces::TriggerAction>> actions;
 
-    void commit(const std::string&, uint64_t, double);
+    void commit(const std::string&, Milliseconds, double);
 };
diff --git a/src/report.cpp b/src/report.cpp
index 54189e3..170f50d 100644
--- a/src/report.cpp
+++ b/src/report.cpp
@@ -21,7 +21,7 @@
                interfaces::ReportManager& reportManager,
                interfaces::JsonStorage& reportStorageIn,
                std::vector<std::shared_ptr<interfaces::Metric>> metricsIn,
-               const bool enabledIn) :
+               const bool enabledIn, std::unique_ptr<interfaces::Clock> clock) :
     id(reportId),
     name(reportName), reportingType(reportingTypeIn), interval(intervalIn),
     reportActions(std::move(reportActionsIn)),
@@ -30,7 +30,7 @@
     reportUpdates(reportUpdatesIn),
     readingsBuffer(deduceBufferSize(reportUpdates, reportingType)),
     objServer(objServer), metrics(std::move(metricsIn)), timer(ioc),
-    reportStorage(reportStorageIn), enabled(enabledIn)
+    reportStorage(reportStorageIn), enabled(enabledIn), clock(std::move(clock))
 {
     readingParameters =
         toReadingParameters(utils::transform(metrics, [](const auto& metric) {
@@ -318,7 +318,8 @@
     }
 
     readings = {
-        Clock().timestamp(),
+        std::chrono::duration_cast<Milliseconds>(clock->systemTimestamp())
+            .count(),
         std::vector<ReadingData>(readingsBuffer.begin(), readingsBuffer.end())};
 
     reportIface->signal_property("Readings");
diff --git a/src/report.hpp b/src/report.hpp
index 72563f5..e2f422d 100644
--- a/src/report.hpp
+++ b/src/report.hpp
@@ -1,5 +1,6 @@
 #pragma once
 
+#include "interfaces/clock.hpp"
 #include "interfaces/json_storage.hpp"
 #include "interfaces/metric.hpp"
 #include "interfaces/report.hpp"
@@ -29,7 +30,7 @@
            interfaces::ReportManager& reportManager,
            interfaces::JsonStorage& reportStorage,
            std::vector<std::shared_ptr<interfaces::Metric>> metrics,
-           const bool enabled);
+           const bool enabled, std::unique_ptr<interfaces::Clock> clock);
     ~Report() = default;
 
     Report(const Report&) = delete;
@@ -83,6 +84,7 @@
 
     interfaces::JsonStorage& reportStorage;
     bool enabled;
+    std::unique_ptr<interfaces::Clock> clock;
 
   public:
     static constexpr const char* reportIfaceName =
diff --git a/src/report_factory.cpp b/src/report_factory.cpp
index f72a3f7..278b9f1 100644
--- a/src/report_factory.cpp
+++ b/src/report_factory.cpp
@@ -40,10 +40,10 @@
                 std::make_unique<Clock>());
         });
 
-    return std::make_unique<Report>(bus->get_io_context(), objServer, id, name,
-                                    reportingType, reportActions, period,
-                                    appendLimit, reportUpdates, reportManager,
-                                    reportStorage, std::move(metrics), enabled);
+    return std::make_unique<Report>(
+        bus->get_io_context(), objServer, id, name, reportingType,
+        reportActions, period, appendLimit, reportUpdates, reportManager,
+        reportStorage, std::move(metrics), enabled, std::make_unique<Clock>());
 }
 
 Sensors ReportFactory::getSensors(
diff --git a/src/sensor.cpp b/src/sensor.cpp
index 5c71910..d81e1a1 100644
--- a/src/sensor.cpp
+++ b/src/sensor.cpp
@@ -100,7 +100,7 @@
 
 void Sensor::updateValue(double newValue)
 {
-    timestamp = Clock().timestamp();
+    timestamp = Clock().steadyTimestamp();
 
     if (value == newValue)
     {
diff --git a/src/sensor.hpp b/src/sensor.hpp
index 3c9c746..d2c3ec2 100644
--- a/src/sensor.hpp
+++ b/src/sensor.hpp
@@ -2,7 +2,7 @@
 
 #include "interfaces/sensor.hpp"
 #include "interfaces/sensor_listener.hpp"
-#include "types/milliseconds.hpp"
+#include "types/duration_types.hpp"
 #include "utils/unique_call.hpp"
 
 #include <boost/asio/high_resolution_timer.hpp>
@@ -53,7 +53,7 @@
 
     utils::UniqueCall uniqueCall;
     std::vector<std::weak_ptr<interfaces::SensorListener>> listeners;
-    uint64_t timestamp = 0;
+    Milliseconds timestamp = Milliseconds{0u};
     std::optional<double> value;
     std::unique_ptr<sdbusplus::bus::match_t> signalMonitor;
 };
diff --git a/src/trigger_actions.cpp b/src/trigger_actions.cpp
index e159cb1..22c81a3 100644
--- a/src/trigger_actions.cpp
+++ b/src/trigger_actions.cpp
@@ -9,9 +9,9 @@
 
 namespace
 {
-std::string timestampToString(uint64_t timestamp)
+std::string timestampToString(Milliseconds timestamp)
 {
-    std::time_t t = static_cast<time_t>(timestamp);
+    std::time_t t = static_cast<time_t>(timestamp.count());
     std::array<char, sizeof("YYYY-MM-DDThh:mm:ssZ")> buf = {};
     size_t size =
         std::strftime(buf.data(), buf.size(), "%FT%TZ", std::gmtime(&t));
@@ -55,7 +55,7 @@
     throw std::runtime_error("Invalid type");
 }
 
-void LogToJournal::commit(const std::string& sensorName, uint64_t timestamp,
+void LogToJournal::commit(const std::string& sensorName, Milliseconds timestamp,
                           double value)
 {
     std::string msg = std::string(getType()) +
@@ -84,14 +84,14 @@
     throw std::runtime_error("Invalid type");
 }
 
-void LogToRedfish::commit(const std::string& sensorName, uint64_t timestamp,
+void LogToRedfish::commit(const std::string& sensorName, Milliseconds timestamp,
                           double value)
 {
     phosphor::logging::log<phosphor::logging::level::INFO>(
         "Threshold value is exceeded",
         phosphor::logging::entry("REDFISH_MESSAGE_ID=%s", getMessageId()),
         phosphor::logging::entry("REDFISH_MESSAGE_ARGS=%s,%f,%llu,%s",
-                                 sensorName.c_str(), value, timestamp,
+                                 sensorName.c_str(), value, timestamp.count(),
                                  getDirection(value, threshold)));
 }
 
@@ -146,7 +146,7 @@
     throw std::runtime_error("Invalid severity");
 }
 
-void LogToJournal::commit(const std::string& sensorName, uint64_t timestamp,
+void LogToJournal::commit(const std::string& sensorName, Milliseconds timestamp,
                           double value)
 {
     std::string msg = std::string(getSeverity()) +
@@ -171,14 +171,14 @@
     throw std::runtime_error("Invalid severity");
 }
 
-void LogToRedfish::commit(const std::string& sensorName, uint64_t timestamp,
+void LogToRedfish::commit(const std::string& sensorName, Milliseconds timestamp,
                           double value)
 {
     phosphor::logging::log<phosphor::logging::level::INFO>(
         "Discrete treshold condition is met",
         phosphor::logging::entry("REDFISH_MESSAGE_ID=%s", getMessageId()),
         phosphor::logging::entry("REDFISH_MESSAGE_ARGS=%s,%f,%llu",
-                                 sensorName.c_str(), value, timestamp));
+                                 sensorName.c_str(), value, timestamp.count()));
 }
 
 void fillActions(
@@ -216,7 +216,7 @@
 
 namespace onChange
 {
-void LogToJournal::commit(const std::string& sensorName, uint64_t timestamp,
+void LogToJournal::commit(const std::string& sensorName, Milliseconds timestamp,
                           double value)
 {
     std::string msg = "Value changed on sensor " + sensorName +
@@ -226,7 +226,7 @@
     phosphor::logging::log<phosphor::logging::level::INFO>(msg.c_str());
 }
 
-void LogToRedfish::commit(const std::string& sensorName, uint64_t timestamp,
+void LogToRedfish::commit(const std::string& sensorName, Milliseconds timestamp,
                           double value)
 {
     const char* messageId = "OpenBMC.0.1.0.DiscreteThresholdOnChange";
@@ -234,7 +234,7 @@
         "Uncondtional discrete threshold triggered",
         phosphor::logging::entry("REDFISH_MESSAGE_ID=%s", messageId),
         phosphor::logging::entry("REDFISH_MESSAGE_ARGS=%s,%f,%llu",
-                                 sensorName.c_str(), value, timestamp));
+                                 sensorName.c_str(), value, timestamp.count()));
 }
 
 void fillActions(
@@ -270,7 +270,7 @@
 } // namespace onChange
 } // namespace discrete
 
-void UpdateReport::commit(const std::string&, uint64_t, double)
+void UpdateReport::commit(const std::string&, Milliseconds, double)
 {
     for (const auto& name : reportIds)
     {
diff --git a/src/trigger_actions.hpp b/src/trigger_actions.hpp
index d86acb8..2871256 100644
--- a/src/trigger_actions.hpp
+++ b/src/trigger_actions.hpp
@@ -15,7 +15,7 @@
     LogToJournal(::numeric::Type type, double val) : type(type), threshold(val)
     {}
 
-    void commit(const std::string& id, uint64_t timestamp,
+    void commit(const std::string& id, Milliseconds timestamp,
                 double value) override;
 
   private:
@@ -31,7 +31,7 @@
     LogToRedfish(::numeric::Type type, double val) : type(type), threshold(val)
     {}
 
-    void commit(const std::string& id, uint64_t timestamp,
+    void commit(const std::string& id, Milliseconds timestamp,
                 double value) override;
 
   private:
@@ -56,7 +56,7 @@
     LogToJournal(::discrete::Severity severity) : severity(severity)
     {}
 
-    void commit(const std::string& id, uint64_t timestamp,
+    void commit(const std::string& id, Milliseconds timestamp,
                 double value) override;
 
   private:
@@ -71,7 +71,7 @@
     LogToRedfish(::discrete::Severity severity) : severity(severity)
     {}
 
-    void commit(const std::string& id, uint64_t timestamp,
+    void commit(const std::string& id, Milliseconds timestamp,
                 double value) override;
 
   private:
@@ -94,7 +94,7 @@
     LogToJournal()
     {}
 
-    void commit(const std::string& id, uint64_t timestamp,
+    void commit(const std::string& id, Milliseconds timestamp,
                 double value) override;
 };
 
@@ -104,7 +104,7 @@
     LogToRedfish()
     {}
 
-    void commit(const std::string& id, uint64_t timestamp,
+    void commit(const std::string& id, Milliseconds timestamp,
                 double value) override;
 };
 
@@ -126,7 +126,7 @@
         reportIds(std::move(ids))
     {}
 
-    void commit(const std::string& id, uint64_t timestamp,
+    void commit(const std::string& id, Milliseconds timestamp,
                 double value) override;
 
   private:
diff --git a/src/types/collection_duration.hpp b/src/types/collection_duration.hpp
index 2db8278..cdb9ff9 100644
--- a/src/types/collection_duration.hpp
+++ b/src/types/collection_duration.hpp
@@ -1,6 +1,6 @@
 #pragma once
 
-#include "types/milliseconds.hpp"
+#include "types/duration_types.hpp"
 
 #include <boost/serialization/strong_typedef.hpp>
 #include <nlohmann/json.hpp>
diff --git a/src/types/duration_type.hpp b/src/types/duration_type.hpp
deleted file mode 100644
index 69d3862..0000000
--- a/src/types/duration_type.hpp
+++ /dev/null
@@ -1,6 +0,0 @@
-#pragma once
-
-#include <chrono>
-#include <cstdint>
-
-using Milliseconds = std::chrono::duration<uint64_t, std::milli>;
diff --git a/src/types/milliseconds.hpp b/src/types/duration_types.hpp
similarity index 66%
rename from src/types/milliseconds.hpp
rename to src/types/duration_types.hpp
index 6de2c2b..b65f779 100644
--- a/src/types/milliseconds.hpp
+++ b/src/types/duration_types.hpp
@@ -2,4 +2,5 @@
 
 #include <chrono>
 
+using Seconds = std::chrono::duration<uint64_t>;
 using Milliseconds = std::chrono::duration<uint64_t, std::milli>;
diff --git a/src/utils/clock.hpp b/src/utils/clock.hpp
index 00fd8d0..4e17952 100644
--- a/src/utils/clock.hpp
+++ b/src/utils/clock.hpp
@@ -1,22 +1,24 @@
 #pragma once
 
 #include "interfaces/clock.hpp"
-#include "types/duration_type.hpp"
+#include "types/duration_types.hpp"
 
 #include <chrono>
 
 class Clock : public interfaces::Clock
 {
   public:
-    time_point now() const noexcept override
+    Milliseconds steadyTimestamp() const noexcept override
     {
-        return std::chrono::steady_clock::now();
+        return std::chrono::time_point_cast<Milliseconds>(
+                   std::chrono::steady_clock::now())
+            .time_since_epoch();
     }
 
-    uint64_t timestamp() const noexcept override
+    Milliseconds systemTimestamp() const noexcept override
     {
-        return std::chrono::time_point_cast<Milliseconds>(now())
-            .time_since_epoch()
-            .count();
+        return std::chrono::time_point_cast<Milliseconds>(
+                   std::chrono::system_clock::now())
+            .time_since_epoch();
     }
 };
diff --git a/src/utils/detached_timer.hpp b/src/utils/detached_timer.hpp
index 636949c..ae97fab 100644
--- a/src/utils/detached_timer.hpp
+++ b/src/utils/detached_timer.hpp
@@ -1,6 +1,6 @@
 #pragma once
 
-#include "types/milliseconds.hpp"
+#include "types/duration_types.hpp"
 
 #include <boost/asio/io_context.hpp>
 #include <boost/asio/steady_timer.hpp>
diff --git a/tests/src/dbus_environment.hpp b/tests/src/dbus_environment.hpp
index 087daef..86d7007 100644
--- a/tests/src/dbus_environment.hpp
+++ b/tests/src/dbus_environment.hpp
@@ -1,6 +1,6 @@
 #pragma once
 
-#include "types/duration_type.hpp"
+#include "types/duration_types.hpp"
 #include "utils/set_exception.hpp"
 
 #include <sdbusplus/asio/object_server.hpp>
diff --git a/tests/src/fakes/clock_fake.hpp b/tests/src/fakes/clock_fake.hpp
index 3871a3b..b65b82f 100644
--- a/tests/src/fakes/clock_fake.hpp
+++ b/tests/src/fakes/clock_fake.hpp
@@ -1,49 +1,64 @@
 #pragma once
 
 #include "interfaces/clock.hpp"
-#include "types/duration_type.hpp"
+#include "types/duration_types.hpp"
 
 class ClockFake : public interfaces::Clock
 {
   public:
-    time_point now() const noexcept override
+    template <class ClockType>
+    struct InternalClock
     {
-        return timePoint;
-    }
+        using clock = ClockType;
+        using time_point = typename clock::time_point;
 
-    uint64_t timestamp() const noexcept override
-    {
-        return toTimestamp(now());
-    }
+        Milliseconds timestamp() const noexcept
+        {
+            return ClockFake::toTimestamp(now);
+        }
 
-    uint64_t advance(Milliseconds delta) noexcept
-    {
-        timePoint += delta;
-        return timestamp();
-    }
+        void advance(Milliseconds delta) noexcept
+        {
+            now += delta;
+        }
 
-    void set(Milliseconds timeSinceEpoch) noexcept
-    {
-        timePoint = time_point{timeSinceEpoch};
-    }
+        void set(Milliseconds timeSinceEpoch) noexcept
+        {
+            now = time_point{timeSinceEpoch};
+        }
 
-    void reset(void) noexcept
-    {
-        set(Milliseconds(0));
-    }
+        void reset() noexcept
+        {
+            now = time_point{Milliseconds{0u}};
+        }
 
-    static uint64_t toTimestamp(Milliseconds time)
-    {
-        return time.count();
-    }
+      private:
+        time_point now = clock::now();
+    };
 
-    static uint64_t toTimestamp(time_point tp)
+    template <class TimePoint>
+    static Milliseconds toTimestamp(TimePoint tp)
     {
         return std::chrono::time_point_cast<Milliseconds>(tp)
-            .time_since_epoch()
-            .count();
+            .time_since_epoch();
     }
 
-  private:
-    time_point timePoint = std::chrono::steady_clock::now();
+    Milliseconds steadyTimestamp() const noexcept override
+    {
+        return steady.timestamp();
+    }
+
+    Milliseconds systemTimestamp() const noexcept override
+    {
+        return system.timestamp();
+    }
+
+    void advance(Milliseconds delta) noexcept
+    {
+        steady.advance(delta);
+        system.advance(delta);
+    }
+
+    InternalClock<std::chrono::steady_clock> steady;
+    InternalClock<std::chrono::system_clock> system;
 };
diff --git a/tests/src/helpers.hpp b/tests/src/helpers.hpp
index c12c610..8ae0b7f 100644
--- a/tests/src/helpers.hpp
+++ b/tests/src/helpers.hpp
@@ -4,3 +4,4 @@
 #include "helpers/interfaces/sensor_id_helpers.hpp"
 #include "helpers/labeled_tuple_helpers.hpp"
 #include "helpers/metric_value_helpers.hpp"
+#include "helpers/types/duration_types_helpers.hpp"
diff --git a/tests/src/helpers/types/duration_types_helpers.hpp b/tests/src/helpers/types/duration_types_helpers.hpp
new file mode 100644
index 0000000..be4886c
--- /dev/null
+++ b/tests/src/helpers/types/duration_types_helpers.hpp
@@ -0,0 +1,12 @@
+#pragma once
+
+#include "types/duration_types.hpp"
+
+#include <gmock/gmock.h>
+
+template <class Ratio>
+inline void PrintTo(const std::chrono::duration<uint64_t, Ratio>& o,
+                    std::ostream* os)
+{
+    (*os) << std::chrono::duration_cast<Milliseconds>(o).count() << "us";
+}
diff --git a/tests/src/mocks/sensor_listener_mock.hpp b/tests/src/mocks/sensor_listener_mock.hpp
index 3a61519..a5c0331 100644
--- a/tests/src/mocks/sensor_listener_mock.hpp
+++ b/tests/src/mocks/sensor_listener_mock.hpp
@@ -18,10 +18,10 @@
             .WillByDefault(InvokeWithoutArgs([this] { sensorUpdated(); }));
     }
 
-    MOCK_METHOD(void, sensorUpdated, (interfaces::Sensor&, uint64_t),
+    MOCK_METHOD(void, sensorUpdated, (interfaces::Sensor&, Milliseconds),
                 (override));
-    MOCK_METHOD(void, sensorUpdated, (interfaces::Sensor&, uint64_t, double),
-                (override));
+    MOCK_METHOD(void, sensorUpdated,
+                (interfaces::Sensor&, Milliseconds, double), (override));
 
     MOCK_METHOD(void, sensorUpdated, (), ());
 };
diff --git a/tests/src/mocks/trigger_action_mock.hpp b/tests/src/mocks/trigger_action_mock.hpp
index 586ac21..65585d8 100644
--- a/tests/src/mocks/trigger_action_mock.hpp
+++ b/tests/src/mocks/trigger_action_mock.hpp
@@ -7,6 +7,6 @@
 class TriggerActionMock : public interfaces::TriggerAction
 {
   public:
-    MOCK_METHOD(void, commit, (const std::string&, uint64_t, double),
+    MOCK_METHOD(void, commit, (const std::string&, Milliseconds, double),
                 (override));
 };
diff --git a/tests/src/params/trigger_params.hpp b/tests/src/params/trigger_params.hpp
index ea309e6..886cf78 100644
--- a/tests/src/params/trigger_params.hpp
+++ b/tests/src/params/trigger_params.hpp
@@ -1,6 +1,6 @@
 #pragma once
 
-#include "types/milliseconds.hpp"
+#include "types/duration_types.hpp"
 #include "types/trigger_types.hpp"
 
 #include <sdbusplus/message.hpp>
diff --git a/tests/src/test_discrete_threshold.cpp b/tests/src/test_discrete_threshold.cpp
index 47b6179..3dd2baa 100644
--- a/tests/src/test_discrete_threshold.cpp
+++ b/tests/src/test_discrete_threshold.cpp
@@ -3,7 +3,7 @@
 #include "helpers.hpp"
 #include "mocks/sensor_mock.hpp"
 #include "mocks/trigger_action_mock.hpp"
-#include "types/milliseconds.hpp"
+#include "types/duration_types.hpp"
 #include "utils/conv_container.hpp"
 
 #include <gmock/gmock.h>
@@ -66,11 +66,11 @@
     struct UpdateParams
     {
         size_t sensor;
-        uint64_t timestamp;
+        Milliseconds timestamp;
         double value;
         Milliseconds sleepAfter;
 
-        UpdateParams(size_t sensor, uint64_t timestamp, double value,
+        UpdateParams(size_t sensor, Milliseconds timestamp, double value,
                      Milliseconds sleepAfter = 0ms) :
             sensor(sensor),
             timestamp(timestamp), value(value), sleepAfter(sleepAfter)
@@ -80,11 +80,11 @@
     struct ExpectedParams
     {
         size_t sensor;
-        uint64_t timestamp;
+        Milliseconds timestamp;
         double value;
         Milliseconds waitMin;
 
-        ExpectedParams(size_t sensor, uint64_t timestamp, double value,
+        ExpectedParams(size_t sensor, Milliseconds timestamp, double value,
                        Milliseconds waitMin = 0ms) :
             sensor(sensor),
             timestamp(timestamp), value(value), waitMin(waitMin)
@@ -122,16 +122,16 @@
         *os << ", Updates: ";
         for (const auto& [index, timestamp, value, sleepAfter] : o.updates)
         {
-            *os << "{ SensorIndex: " << index << ", Timestamp: " << timestamp
-                << ", Value: " << value
+            *os << "{ SensorIndex: " << index
+                << ", Timestamp: " << timestamp.count() << ", Value: " << value
                 << ", SleepAfter: " << sleepAfter.count() << "ms }, ";
         }
         *os << "Expected: ";
         for (const auto& [index, timestamp, value, waitMin] : o.expected)
         {
-            *os << "{ SensorIndex: " << index << ", Timestamp: " << timestamp
-                << ", Value: " << value << ", waitMin: " << waitMin.count()
-                << "ms }, ";
+            *os << "{ SensorIndex: " << index
+                << ", Timestamp: " << timestamp.count() << ", Value: " << value
+                << ", waitMin: " << waitMin.count() << "ms }, ";
         }
         *os << " }";
     }
@@ -204,21 +204,26 @@
     }
 };
 
-INSTANTIATE_TEST_SUITE_P(
-    _, TestDiscreteThresholdNoDwellTime,
-    Values(
-        DiscreteParams()
-            .ThresholdValue(90.0)
-            .Updates({{0, 1, 80.0}, {0, 2, 89.0}})
-            .Expected({}),
-        DiscreteParams()
-            .ThresholdValue(90.0)
-            .Updates({{0, 1, 80.0}, {0, 2, 90.0}, {0, 3, 80.0}, {0, 4, 90.0}})
-            .Expected({{0, 2, 90.0}, {0, 4, 90.0}}),
-        DiscreteParams()
-            .ThresholdValue(90.0)
-            .Updates({{0, 1, 90.0}, {0, 2, 99.0}, {1, 3, 100.0}, {1, 4, 90.0}})
-            .Expected({{0, 1, 90.0}, {1, 4, 90.0}})));
+INSTANTIATE_TEST_SUITE_P(_, TestDiscreteThresholdNoDwellTime,
+                         Values(DiscreteParams()
+                                    .ThresholdValue(90.0)
+                                    .Updates({{0, 1ms, 80.0}, {0, 2ms, 89.0}})
+                                    .Expected({}),
+                                DiscreteParams()
+                                    .ThresholdValue(90.0)
+                                    .Updates({{0, 1ms, 80.0},
+                                              {0, 2ms, 90.0},
+                                              {0, 3ms, 80.0},
+                                              {0, 4ms, 90.0}})
+                                    .Expected({{0, 2ms, 90.0}, {0, 4ms, 90.0}}),
+                                DiscreteParams()
+                                    .ThresholdValue(90.0)
+                                    .Updates({{0, 1ms, 90.0},
+                                              {0, 2ms, 99.0},
+                                              {1, 3ms, 100.0},
+                                              {1, 4ms, 90.0}})
+                                    .Expected({{0, 1ms, 90.0},
+                                               {1, 4ms, 90.0}})));
 
 TEST_P(TestDiscreteThresholdNoDwellTime, senorsIsUpdatedMultipleTimes)
 {
@@ -239,31 +244,31 @@
     Values(DiscreteParams()
                .DwellTime(200ms)
                .ThresholdValue(90.0)
-               .Updates({{0, 1, 90.0, 100ms}, {0, 2, 91.0}, {0, 3, 90.0}})
-               .Expected({{0, 3, 90.0, 300ms}}),
+               .Updates({{0, 1ms, 90.0, 100ms}, {0, 2ms, 91.0}, {0, 3ms, 90.0}})
+               .Expected({{0, 3ms, 90.0, 300ms}}),
            DiscreteParams()
                .DwellTime(100ms)
                .ThresholdValue(90.0)
-               .Updates({{0, 1, 90.0, 100ms}})
-               .Expected({{0, 1, 90.0, 100ms}}),
+               .Updates({{0, 1ms, 90.0, 100ms}})
+               .Expected({{0, 1ms, 90.0, 100ms}}),
            DiscreteParams()
                .DwellTime(1000ms)
                .ThresholdValue(90.0)
-               .Updates({{0, 1, 90.0, 700ms},
-                         {0, 1, 91.0, 100ms},
-                         {0, 1, 90.0, 300ms},
-                         {0, 1, 91.0, 100ms}})
+               .Updates({{0, 1ms, 90.0, 700ms},
+                         {0, 1ms, 91.0, 100ms},
+                         {0, 1ms, 90.0, 300ms},
+                         {0, 1ms, 91.0, 100ms}})
                .Expected({}),
            DiscreteParams()
                .DwellTime(200ms)
                .ThresholdValue(90.0)
-               .Updates({{0, 1, 90.0},
-                         {1, 2, 89.0, 100ms},
-                         {1, 3, 90.0, 100ms},
-                         {1, 4, 89.0, 100ms},
-                         {1, 5, 90.0, 300ms},
-                         {1, 6, 89.0, 100ms}})
-               .Expected({{0, 1, 90, 200ms}, {1, 5, 90, 500ms}})));
+               .Updates({{0, 1ms, 90.0},
+                         {1, 2ms, 89.0, 100ms},
+                         {1, 3ms, 90.0, 100ms},
+                         {1, 4ms, 89.0, 100ms},
+                         {1, 5ms, 90.0, 300ms},
+                         {1, 6ms, 89.0, 100ms}})
+               .Expected({{0, 1ms, 90, 200ms}, {1, 5ms, 90, 500ms}})));
 
 TEST_P(TestDiscreteThresholdWithDwellTime, senorsIsUpdatedMultipleTimes)
 {
diff --git a/tests/src/test_metric.cpp b/tests/src/test_metric.cpp
index e19446c..bd1d8c4 100644
--- a/tests/src/test_metric.cpp
+++ b/tests/src/test_metric.cpp
@@ -14,11 +14,17 @@
 
 namespace tstring = utils::tstring;
 
-using Timestamp = uint64_t;
+constexpr Milliseconds systemTimestamp = 42ms;
 
 class TestMetric : public Test
 {
   public:
+    TestMetric()
+    {
+        clockFake.steady.reset();
+        clockFake.system.set(systemTimestamp);
+    }
+
     static std::vector<std::shared_ptr<SensorMock>>
         makeSensorMocks(size_t amount)
     {
@@ -102,18 +108,23 @@
 
 TEST_F(TestMetricAfterInitialization, updatesMetricValuesOnSensorUpdate)
 {
-    sut->sensorUpdated(*sensorMocks.front(), Timestamp{18}, 31.2);
+    sut->sensorUpdated(*sensorMocks.front(), Milliseconds{18}, 31.2);
 
-    ASSERT_THAT(sut->getReadings(),
-                ElementsAre(MetricValue{"id", "metadata", 31.2, 18u}));
+    ASSERT_THAT(
+        sut->getReadings(),
+        ElementsAre(MetricValue{"id", "metadata", 31.2,
+                                std::chrono::duration_cast<Milliseconds>(
+                                    clockFake.system.timestamp())
+                                    .count()}));
 }
 
 TEST_F(TestMetricAfterInitialization,
        throwsWhenUpdateIsPerformedOnUnknownSensor)
 {
     auto sensor = std::make_shared<StrictMock<SensorMock>>();
-    EXPECT_THROW(sut->sensorUpdated(*sensor, Timestamp{10}), std::out_of_range);
-    EXPECT_THROW(sut->sensorUpdated(*sensor, Timestamp{10}, 20.0),
+    EXPECT_THROW(sut->sensorUpdated(*sensor, Milliseconds{10}),
+                 std::out_of_range);
+    EXPECT_THROW(sut->sensorUpdated(*sensor, Milliseconds{10}, 20.0),
                  std::out_of_range);
 }
 
@@ -146,7 +157,6 @@
   public:
     void SetUp() override
     {
-        clockFake.reset();
         sut = makeSut(params.operationType(GetParam().operationType())
                           .collectionTimeScope(GetParam().collectionTimeScope())
                           .collectionDuration(GetParam().collectionDuration()));
@@ -168,7 +178,7 @@
     return MetricParams()
         .operationType(OperationType::single)
         .readings(TestMetricCalculationFunctions::defaultReadings())
-        .expectedReading(11ms, 7.0);
+        .expectedReading(systemTimestamp + 16ms, 7.0);
 }
 
 INSTANTIATE_TEST_SUITE_P(
@@ -205,14 +215,14 @@
     Values(defaultMinParams()
                .collectionTimeScope(CollectionTimeScope::interval)
                .collectionDuration(CollectionDuration(100ms))
-               .expectedReading(10ms, 3.0),
+               .expectedReading(systemTimestamp + 16ms, 3.0),
            defaultMinParams()
                .collectionTimeScope(CollectionTimeScope::interval)
                .collectionDuration(CollectionDuration(3ms))
-               .expectedReading(13ms, 7.0),
+               .expectedReading(systemTimestamp + 16ms, 7.0),
            defaultMinParams()
                .collectionTimeScope(CollectionTimeScope::startup)
-               .expectedReading(10ms, 3.0)));
+               .expectedReading(systemTimestamp + 16ms, 3.0)));
 
 MetricParams defaultMaxParams()
 {
@@ -224,18 +234,18 @@
     Values(defaultMaxParams()
                .collectionTimeScope(CollectionTimeScope::interval)
                .collectionDuration(CollectionDuration(100ms))
-               .expectedReading(0ms, 14.0),
+               .expectedReading(systemTimestamp + 16ms, 14.0),
            defaultMaxParams()
                .collectionTimeScope(CollectionTimeScope::interval)
                .collectionDuration(CollectionDuration(6ms))
-               .expectedReading(10ms, 14.0),
+               .expectedReading(systemTimestamp + 16ms, 14.0),
            defaultMaxParams()
                .collectionTimeScope(CollectionTimeScope::interval)
                .collectionDuration(CollectionDuration(5ms))
-               .expectedReading(11ms, 7.0),
+               .expectedReading(systemTimestamp + 16ms, 7.0),
            defaultMaxParams()
                .collectionTimeScope(CollectionTimeScope::startup)
-               .expectedReading(0ms, 14.0)));
+               .expectedReading(systemTimestamp + 16ms, 14.0)));
 
 MetricParams defaultSumParams()
 {
@@ -247,18 +257,21 @@
     Values(defaultSumParams()
                .collectionTimeScope(CollectionTimeScope::interval)
                .collectionDuration(CollectionDuration(100ms))
-               .expectedReading(16ms, 14. * 10 + 3. * 1 + 7 * 5),
+               .expectedReading(systemTimestamp + 16ms,
+                                14. * 0.01 + 3. * 0.001 + 7. * 0.005),
            defaultSumParams()
                .collectionTimeScope(CollectionTimeScope::interval)
                .collectionDuration(CollectionDuration(8ms))
-               .expectedReading(16ms, 14. * 2 + 3. * 1 + 7 * 5),
+               .expectedReading(systemTimestamp + 16ms,
+                                14. * 0.002 + 3. * 0.001 + 7 * 0.005),
            defaultSumParams()
                .collectionTimeScope(CollectionTimeScope::interval)
                .collectionDuration(CollectionDuration(6ms))
-               .expectedReading(16ms, 3. * 1 + 7 * 5),
+               .expectedReading(systemTimestamp + 16ms, 3. * 0.001 + 7 * 0.005),
            defaultSumParams()
                .collectionTimeScope(CollectionTimeScope::startup)
-               .expectedReading(16ms, 14. * 10 + 3. * 1 + 7 * 5)));
+               .expectedReading(systemTimestamp + 16ms,
+                                14. * 0.01 + 3. * 0.001 + 7 * 0.005)));
 
 MetricParams defaultAvgParams()
 {
@@ -270,24 +283,27 @@
     Values(defaultAvgParams()
                .collectionTimeScope(CollectionTimeScope::interval)
                .collectionDuration(CollectionDuration(100ms))
-               .expectedReading(16ms, (14. * 10 + 3. * 1 + 7 * 5) / 16.),
+               .expectedReading(systemTimestamp + 16ms,
+                                (14. * 10 + 3. * 1 + 7 * 5) / 16.),
            defaultAvgParams()
                .collectionTimeScope(CollectionTimeScope::interval)
                .collectionDuration(CollectionDuration(8ms))
-               .expectedReading(16ms, (14. * 2 + 3. * 1 + 7 * 5) / 8.),
+               .expectedReading(systemTimestamp + 16ms,
+                                (14. * 2 + 3. * 1 + 7 * 5) / 8.),
            defaultAvgParams()
                .collectionTimeScope(CollectionTimeScope::interval)
                .collectionDuration(CollectionDuration(6ms))
-               .expectedReading(16ms, (3. * 1 + 7 * 5) / 6.),
+               .expectedReading(systemTimestamp + 16ms, (3. * 1 + 7 * 5) / 6.),
            defaultAvgParams()
                .collectionTimeScope(CollectionTimeScope::startup)
-               .expectedReading(16ms, (14. * 10 + 3. * 1 + 7 * 5) / 16.)));
+               .expectedReading(systemTimestamp + 16ms,
+                                (14. * 10 + 3. * 1 + 7 * 5) / 16.)));
 
 TEST_P(TestMetricCalculationFunctions, calculatesReadingValue)
 {
     for (auto [timestamp, reading] : GetParam().readings())
     {
-        sut->sensorUpdated(*sensorMocks.front(), clockFake.timestamp(),
+        sut->sensorUpdated(*sensorMocks.front(), clockFake.steadyTimestamp(),
                            reading);
         clockFake.advance(timestamp);
     }
@@ -296,9 +312,9 @@
         GetParam().expectedReading();
     const auto readings = sut->getReadings();
 
-    EXPECT_THAT(readings, ElementsAre(MetricValue{
-                              "id", "metadata", expectedReading,
-                              ClockFake::toTimestamp(expectedTimestamp)}));
+    EXPECT_THAT(readings,
+                ElementsAre(MetricValue{"id", "metadata", expectedReading,
+                                        expectedTimestamp.count()}));
 }
 
 TEST_P(TestMetricCalculationFunctions,
@@ -306,7 +322,7 @@
 {
     for (auto [timestamp, reading] : GetParam().readings())
     {
-        sut->sensorUpdated(*sensorMocks.front(), clockFake.timestamp(),
+        sut->sensorUpdated(*sensorMocks.front(), clockFake.steadyTimestamp(),
                            reading);
         clockFake.advance(timestamp);
         sut->getReadings();
@@ -316,7 +332,7 @@
         GetParam().expectedReading();
     const auto readings = sut->getReadings();
 
-    EXPECT_THAT(readings, ElementsAre(MetricValue{
-                              "id", "metadata", expectedReading,
-                              ClockFake::toTimestamp(expectedTimestamp)}));
+    EXPECT_THAT(readings,
+                ElementsAre(MetricValue{"id", "metadata", expectedReading,
+                                        expectedTimestamp.count()}));
 }
diff --git a/tests/src/test_numeric_threshold.cpp b/tests/src/test_numeric_threshold.cpp
index bda31a0..851d4a9 100644
--- a/tests/src/test_numeric_threshold.cpp
+++ b/tests/src/test_numeric_threshold.cpp
@@ -69,14 +69,14 @@
     }
 
     NumericParams&
-        Updates(std::vector<std::tuple<size_t, uint64_t, double>> val)
+        Updates(std::vector<std::tuple<size_t, Milliseconds, double>> val)
     {
         updates = std::move(val);
         return *this;
     }
 
     NumericParams&
-        Expected(std::vector<std::tuple<size_t, uint64_t, double>> val)
+        Expected(std::vector<std::tuple<size_t, Milliseconds, double>> val)
     {
         expected = std::move(val);
         return *this;
@@ -88,21 +88,23 @@
             << ", Updates: ";
         for (const auto& [index, timestamp, value] : o.updates)
         {
-            *os << "{ SensorIndex: " << index << ", Timestamp: " << timestamp
-                << ", Value: " << value << " }, ";
+            *os << "{ SensorIndex: " << index
+                << ", Timestamp: " << timestamp.count() << ", Value: " << value
+                << " }, ";
         }
         *os << "Expected: ";
         for (const auto& [index, timestamp, value] : o.expected)
         {
-            *os << "{ SensorIndex: " << index << ", Timestamp: " << timestamp
-                << ", Value: " << value << " }, ";
+            *os << "{ SensorIndex: " << index
+                << ", Timestamp: " << timestamp.count() << ", Value: " << value
+                << " }, ";
         }
         *os << " }";
     }
 
     numeric::Direction direction;
-    std::vector<std::tuple<size_t, uint64_t, double>> updates;
-    std::vector<std::tuple<size_t, uint64_t, double>> expected;
+    std::vector<std::tuple<size_t, Milliseconds, double>> updates;
+    std::vector<std::tuple<size_t, Milliseconds, double>> expected;
 };
 
 class TestNumericThresholdNoDwellTime :
@@ -116,53 +118,70 @@
     }
 };
 
-INSTANTIATE_TEST_SUITE_P(
-    _, TestNumericThresholdNoDwellTime,
-    Values(
-        NumericParams()
-            .Direction(numeric::Direction::increasing)
-            .Updates({{0, 1, 80.0}, {0, 2, 89.0}})
-            .Expected({}),
-        NumericParams()
-            .Direction(numeric::Direction::increasing)
-            .Updates({{0, 1, 80.0}, {0, 2, 91.0}})
-            .Expected({{0, 2, 91.0}}),
-        NumericParams()
-            .Direction(numeric::Direction::increasing)
-            .Updates({{0, 1, 80.0}, {0, 2, 99.0}, {0, 3, 80.0}, {0, 4, 98.0}})
-            .Expected({{0, 2, 99.0}, {0, 4, 98.0}}),
-        NumericParams()
-            .Direction(numeric::Direction::increasing)
-            .Updates({{0, 1, 80.0}, {0, 2, 99.0}, {1, 3, 100.0}, {1, 4, 98.0}})
-            .Expected({{0, 2, 99.0}}),
-        NumericParams()
-            .Direction(numeric::Direction::decreasing)
-            .Updates({{0, 1, 100.0}, {0, 2, 91.0}})
-            .Expected({}),
-        NumericParams()
-            .Direction(numeric::Direction::decreasing)
-            .Updates({{0, 1, 100.0}, {0, 2, 80.0}})
-            .Expected({{0, 2, 80.0}}),
-        NumericParams()
-            .Direction(numeric::Direction::decreasing)
-            .Updates({{0, 1, 100.0}, {0, 2, 80.0}, {0, 3, 99.0}, {0, 4, 85.0}})
-            .Expected({{0, 2, 80.0}, {0, 4, 85.0}}),
-        NumericParams()
-            .Direction(numeric::Direction::decreasing)
-            .Updates({{0, 1, 100.0}, {0, 2, 80.0}, {1, 3, 99.0}, {1, 4, 88.0}})
-            .Expected({{0, 2, 80.0}, {1, 4, 88.0}}),
-        NumericParams()
-            .Direction(numeric::Direction::either)
-            .Updates({{0, 1, 98.0}, {0, 2, 91.0}})
-            .Expected({}),
-        NumericParams()
-            .Direction(numeric::Direction::either)
-            .Updates({{0, 1, 100.0}, {0, 2, 80.0}, {0, 3, 85.0}, {0, 4, 91.0}})
-            .Expected({{0, 2, 80.0}, {0, 4, 91.0}}),
-        NumericParams()
-            .Direction(numeric::Direction::either)
-            .Updates({{0, 1, 100.0}, {1, 2, 80.0}, {0, 3, 85.0}, {1, 4, 91.0}})
-            .Expected({{0, 3, 85.0}, {1, 4, 91.0}})));
+INSTANTIATE_TEST_SUITE_P(_, TestNumericThresholdNoDwellTime,
+                         Values(NumericParams()
+                                    .Direction(numeric::Direction::increasing)
+                                    .Updates({{0, 1ms, 80.0}, {0, 2ms, 89.0}})
+                                    .Expected({}),
+                                NumericParams()
+                                    .Direction(numeric::Direction::increasing)
+                                    .Updates({{0, 1ms, 80.0}, {0, 2ms, 91.0}})
+                                    .Expected({{0, 2ms, 91.0}}),
+                                NumericParams()
+                                    .Direction(numeric::Direction::increasing)
+                                    .Updates({{0, 1ms, 80.0},
+                                              {0, 2ms, 99.0},
+                                              {0, 3ms, 80.0},
+                                              {0, 4ms, 98.0}})
+                                    .Expected({{0, 2ms, 99.0}, {0, 4ms, 98.0}}),
+                                NumericParams()
+                                    .Direction(numeric::Direction::increasing)
+                                    .Updates({{0, 1ms, 80.0},
+                                              {0, 2ms, 99.0},
+                                              {1, 3ms, 100.0},
+                                              {1, 4ms, 98.0}})
+                                    .Expected({{0, 2ms, 99.0}}),
+                                NumericParams()
+                                    .Direction(numeric::Direction::decreasing)
+                                    .Updates({{0, 1ms, 100.0}, {0, 2ms, 91.0}})
+                                    .Expected({}),
+                                NumericParams()
+                                    .Direction(numeric::Direction::decreasing)
+                                    .Updates({{0, 1ms, 100.0}, {0, 2ms, 80.0}})
+                                    .Expected({{0, 2ms, 80.0}}),
+                                NumericParams()
+                                    .Direction(numeric::Direction::decreasing)
+                                    .Updates({{0, 1ms, 100.0},
+                                              {0, 2ms, 80.0},
+                                              {0, 3ms, 99.0},
+                                              {0, 4ms, 85.0}})
+                                    .Expected({{0, 2ms, 80.0}, {0, 4ms, 85.0}}),
+                                NumericParams()
+                                    .Direction(numeric::Direction::decreasing)
+                                    .Updates({{0, 1ms, 100.0},
+                                              {0, 2ms, 80.0},
+                                              {1, 3ms, 99.0},
+                                              {1, 4ms, 88.0}})
+                                    .Expected({{0, 2ms, 80.0}, {1, 4ms, 88.0}}),
+                                NumericParams()
+                                    .Direction(numeric::Direction::either)
+                                    .Updates({{0, 1ms, 98.0}, {0, 2ms, 91.0}})
+                                    .Expected({}),
+                                NumericParams()
+                                    .Direction(numeric::Direction::either)
+                                    .Updates({{0, 1ms, 100.0},
+                                              {0, 2ms, 80.0},
+                                              {0, 3ms, 85.0},
+                                              {0, 4ms, 91.0}})
+                                    .Expected({{0, 2ms, 80.0}, {0, 4ms, 91.0}}),
+                                NumericParams()
+                                    .Direction(numeric::Direction::either)
+                                    .Updates({{0, 1ms, 100.0},
+                                              {1, 2ms, 80.0},
+                                              {0, 3ms, 85.0},
+                                              {1, 4ms, 91.0}})
+                                    .Expected({{0, 3ms, 85.0},
+                                               {1, 4ms, 91.0}})));
 
 TEST_P(TestNumericThresholdNoDwellTime, senorsIsUpdatedMultipleTimes)
 {
@@ -195,53 +214,70 @@
     }
 };
 
-INSTANTIATE_TEST_SUITE_P(
-    _, TestNumericThresholdWithDwellTime,
-    Values(
-        NumericParams()
-            .Direction(numeric::Direction::increasing)
-            .Updates({{0, 1, 80.0}, {0, 2, 89.0}})
-            .Expected({}),
-        NumericParams()
-            .Direction(numeric::Direction::increasing)
-            .Updates({{0, 1, 80.0}, {0, 2, 91.0}})
-            .Expected({{0, 2, 91.0}}),
-        NumericParams()
-            .Direction(numeric::Direction::increasing)
-            .Updates({{0, 1, 80.0}, {0, 2, 99.0}, {0, 3, 80.0}, {0, 4, 98.0}})
-            .Expected({{0, 2, 99.0}, {0, 4, 98.0}}),
-        NumericParams()
-            .Direction(numeric::Direction::increasing)
-            .Updates({{0, 1, 80.0}, {1, 2, 99.0}, {0, 3, 100.0}, {1, 4, 86.0}})
-            .Expected({{0, 3, 100.0}}),
-        NumericParams()
-            .Direction(numeric::Direction::decreasing)
-            .Updates({{0, 1, 100.0}, {0, 2, 91.0}})
-            .Expected({}),
-        NumericParams()
-            .Direction(numeric::Direction::decreasing)
-            .Updates({{0, 1, 100.0}, {0, 2, 80.0}})
-            .Expected({{0, 2, 80.0}}),
-        NumericParams()
-            .Direction(numeric::Direction::decreasing)
-            .Updates({{0, 1, 100.0}, {0, 2, 80.0}, {0, 3, 99.0}, {0, 4, 85.0}})
-            .Expected({{0, 2, 80.0}, {0, 4, 85.0}}),
-        NumericParams()
-            .Direction(numeric::Direction::decreasing)
-            .Updates({{0, 1, 100.0}, {0, 2, 80.0}, {1, 3, 99.0}, {1, 4, 88.0}})
-            .Expected({{0, 2, 80.0}, {1, 4, 88.0}}),
-        NumericParams()
-            .Direction(numeric::Direction::either)
-            .Updates({{0, 1, 98.0}, {0, 2, 91.0}})
-            .Expected({}),
-        NumericParams()
-            .Direction(numeric::Direction::either)
-            .Updates({{0, 1, 100.0}, {0, 2, 80.0}, {0, 3, 85.0}, {0, 4, 91.0}})
-            .Expected({{0, 2, 80.0}, {0, 4, 91.0}}),
-        NumericParams()
-            .Direction(numeric::Direction::either)
-            .Updates({{0, 1, 100.0}, {1, 2, 80.0}, {0, 3, 85.0}, {1, 4, 91.0}})
-            .Expected({{0, 3, 85.0}, {1, 4, 91.0}})));
+INSTANTIATE_TEST_SUITE_P(_, TestNumericThresholdWithDwellTime,
+                         Values(NumericParams()
+                                    .Direction(numeric::Direction::increasing)
+                                    .Updates({{0, 1ms, 80.0}, {0, 2ms, 89.0}})
+                                    .Expected({}),
+                                NumericParams()
+                                    .Direction(numeric::Direction::increasing)
+                                    .Updates({{0, 1ms, 80.0}, {0, 2ms, 91.0}})
+                                    .Expected({{0, 2ms, 91.0}}),
+                                NumericParams()
+                                    .Direction(numeric::Direction::increasing)
+                                    .Updates({{0, 1ms, 80.0},
+                                              {0, 2ms, 99.0},
+                                              {0, 3ms, 80.0},
+                                              {0, 4ms, 98.0}})
+                                    .Expected({{0, 2ms, 99.0}, {0, 4ms, 98.0}}),
+                                NumericParams()
+                                    .Direction(numeric::Direction::increasing)
+                                    .Updates({{0, 1ms, 80.0},
+                                              {1, 2ms, 99.0},
+                                              {0, 3ms, 100.0},
+                                              {1, 4ms, 86.0}})
+                                    .Expected({{0, 3ms, 100.0}}),
+                                NumericParams()
+                                    .Direction(numeric::Direction::decreasing)
+                                    .Updates({{0, 1ms, 100.0}, {0, 2ms, 91.0}})
+                                    .Expected({}),
+                                NumericParams()
+                                    .Direction(numeric::Direction::decreasing)
+                                    .Updates({{0, 1ms, 100.0}, {0, 2ms, 80.0}})
+                                    .Expected({{0, 2ms, 80.0}}),
+                                NumericParams()
+                                    .Direction(numeric::Direction::decreasing)
+                                    .Updates({{0, 1ms, 100.0},
+                                              {0, 2ms, 80.0},
+                                              {0, 3ms, 99.0},
+                                              {0, 4ms, 85.0}})
+                                    .Expected({{0, 2ms, 80.0}, {0, 4ms, 85.0}}),
+                                NumericParams()
+                                    .Direction(numeric::Direction::decreasing)
+                                    .Updates({{0, 1ms, 100.0},
+                                              {0, 2ms, 80.0},
+                                              {1, 3ms, 99.0},
+                                              {1, 4ms, 88.0}})
+                                    .Expected({{0, 2ms, 80.0}, {1, 4ms, 88.0}}),
+                                NumericParams()
+                                    .Direction(numeric::Direction::either)
+                                    .Updates({{0, 1ms, 98.0}, {0, 2ms, 91.0}})
+                                    .Expected({}),
+                                NumericParams()
+                                    .Direction(numeric::Direction::either)
+                                    .Updates({{0, 1ms, 100.0},
+                                              {0, 2ms, 80.0},
+                                              {0, 3ms, 85.0},
+                                              {0, 4ms, 91.0}})
+                                    .Expected({{0, 2ms, 80.0}, {0, 4ms, 91.0}}),
+                                NumericParams()
+                                    .Direction(numeric::Direction::either)
+                                    .Updates({{0, 1ms, 100.0},
+                                              {1, 2ms, 80.0},
+                                              {0, 3ms, 85.0},
+                                              {1, 4ms, 91.0}})
+                                    .Expected({{0, 3ms, 85.0},
+                                               {1, 4ms, 91.0}})));
 
 TEST_P(TestNumericThresholdWithDwellTime,
        senorsIsUpdatedMultipleTimesSleepAfterEveryUpdate)
@@ -276,53 +312,70 @@
     }
 };
 
-INSTANTIATE_TEST_SUITE_P(
-    _, TestNumericThresholdWithDwellTime2,
-    Values(
-        NumericParams()
-            .Direction(numeric::Direction::increasing)
-            .Updates({{0, 1, 80.0}, {0, 2, 89.0}})
-            .Expected({}),
-        NumericParams()
-            .Direction(numeric::Direction::increasing)
-            .Updates({{0, 1, 80.0}, {0, 2, 91.0}})
-            .Expected({{0, 2, 91.0}}),
-        NumericParams()
-            .Direction(numeric::Direction::increasing)
-            .Updates({{0, 1, 80.0}, {0, 2, 99.0}, {0, 3, 80.0}, {0, 4, 98.0}})
-            .Expected({{0, 4, 98.0}}),
-        NumericParams()
-            .Direction(numeric::Direction::increasing)
-            .Updates({{0, 1, 80.0}, {1, 2, 99.0}, {0, 3, 100.0}, {1, 4, 98.0}})
-            .Expected({{0, 3, 100.0}}),
-        NumericParams()
-            .Direction(numeric::Direction::decreasing)
-            .Updates({{0, 1, 100.0}, {0, 2, 91.0}})
-            .Expected({}),
-        NumericParams()
-            .Direction(numeric::Direction::decreasing)
-            .Updates({{0, 1, 100.0}, {0, 2, 80.0}})
-            .Expected({{0, 2, 80.0}}),
-        NumericParams()
-            .Direction(numeric::Direction::decreasing)
-            .Updates({{0, 1, 100.0}, {0, 2, 80.0}, {0, 3, 99.0}, {0, 4, 85.0}})
-            .Expected({{0, 4, 85.0}}),
-        NumericParams()
-            .Direction(numeric::Direction::decreasing)
-            .Updates({{0, 1, 100.0}, {0, 2, 80.0}, {1, 3, 99.0}, {1, 4, 88.0}})
-            .Expected({{0, 2, 80.0}, {1, 4, 88.0}}),
-        NumericParams()
-            .Direction(numeric::Direction::either)
-            .Updates({{0, 1, 98.0}, {0, 2, 91.0}})
-            .Expected({}),
-        NumericParams()
-            .Direction(numeric::Direction::either)
-            .Updates({{0, 1, 100.0}, {0, 2, 80.0}, {0, 3, 85.0}, {0, 4, 91.0}})
-            .Expected({{0, 4, 91.0}}),
-        NumericParams()
-            .Direction(numeric::Direction::either)
-            .Updates({{0, 1, 100.0}, {1, 2, 80.0}, {0, 3, 85.0}, {1, 4, 91.0}})
-            .Expected({{0, 3, 85.0}, {1, 4, 91.0}})));
+INSTANTIATE_TEST_SUITE_P(_, TestNumericThresholdWithDwellTime2,
+                         Values(NumericParams()
+                                    .Direction(numeric::Direction::increasing)
+                                    .Updates({{0, 1ms, 80.0}, {0, 2ms, 89.0}})
+                                    .Expected({}),
+                                NumericParams()
+                                    .Direction(numeric::Direction::increasing)
+                                    .Updates({{0, 1ms, 80.0}, {0, 2ms, 91.0}})
+                                    .Expected({{0, 2ms, 91.0}}),
+                                NumericParams()
+                                    .Direction(numeric::Direction::increasing)
+                                    .Updates({{0, 1ms, 80.0},
+                                              {0, 2ms, 99.0},
+                                              {0, 3ms, 80.0},
+                                              {0, 4ms, 98.0}})
+                                    .Expected({{0, 4ms, 98.0}}),
+                                NumericParams()
+                                    .Direction(numeric::Direction::increasing)
+                                    .Updates({{0, 1ms, 80.0},
+                                              {1, 2ms, 99.0},
+                                              {0, 3ms, 100.0},
+                                              {1, 4ms, 98.0}})
+                                    .Expected({{0, 3ms, 100.0}}),
+                                NumericParams()
+                                    .Direction(numeric::Direction::decreasing)
+                                    .Updates({{0, 1ms, 100.0}, {0, 2ms, 91.0}})
+                                    .Expected({}),
+                                NumericParams()
+                                    .Direction(numeric::Direction::decreasing)
+                                    .Updates({{0, 1ms, 100.0}, {0, 2ms, 80.0}})
+                                    .Expected({{0, 2ms, 80.0}}),
+                                NumericParams()
+                                    .Direction(numeric::Direction::decreasing)
+                                    .Updates({{0, 1ms, 100.0},
+                                              {0, 2ms, 80.0},
+                                              {0, 3ms, 99.0},
+                                              {0, 4ms, 85.0}})
+                                    .Expected({{0, 4ms, 85.0}}),
+                                NumericParams()
+                                    .Direction(numeric::Direction::decreasing)
+                                    .Updates({{0, 1ms, 100.0},
+                                              {0, 2ms, 80.0},
+                                              {1, 3ms, 99.0},
+                                              {1, 4ms, 88.0}})
+                                    .Expected({{0, 2ms, 80.0}, {1, 4ms, 88.0}}),
+                                NumericParams()
+                                    .Direction(numeric::Direction::either)
+                                    .Updates({{0, 1ms, 98.0}, {0, 2ms, 91.0}})
+                                    .Expected({}),
+                                NumericParams()
+                                    .Direction(numeric::Direction::either)
+                                    .Updates({{0, 1ms, 100.0},
+                                              {0, 2ms, 80.0},
+                                              {0, 3ms, 85.0},
+                                              {0, 4ms, 91.0}})
+                                    .Expected({{0, 4ms, 91.0}}),
+                                NumericParams()
+                                    .Direction(numeric::Direction::either)
+                                    .Updates({{0, 1ms, 100.0},
+                                              {1, 2ms, 80.0},
+                                              {0, 3ms, 85.0},
+                                              {1, 4ms, 91.0}})
+                                    .Expected({{0, 3ms, 85.0},
+                                               {1, 4ms, 91.0}})));
 
 TEST_P(TestNumericThresholdWithDwellTime2,
        senorsIsUpdatedMultipleTimesSleepAfterLastUpdate)
diff --git a/tests/src/test_on_change_threshold.cpp b/tests/src/test_on_change_threshold.cpp
index 20819c5..75a63c5 100644
--- a/tests/src/test_on_change_threshold.cpp
+++ b/tests/src/test_on_change_threshold.cpp
@@ -54,8 +54,8 @@
 
 struct OnChangeParams
 {
-    using UpdateParams = std::tuple<size_t, uint64_t, double>;
-    using ExpectedParams = std::tuple<size_t, uint64_t, double>;
+    using UpdateParams = std::tuple<size_t, Milliseconds, double>;
+    using ExpectedParams = std::tuple<size_t, Milliseconds, double>;
 
     OnChangeParams& Updates(std::vector<UpdateParams> val)
     {
@@ -74,14 +74,16 @@
         *os << "{ Updates: ";
         for (const auto& [index, timestamp, value] : o.updates)
         {
-            *os << "{ SensorIndex: " << index << ", Timestamp: " << timestamp
-                << ", Value: " << value << " }, ";
+            *os << "{ SensorIndex: " << index
+                << ", Timestamp: " << timestamp.count() << ", Value: " << value
+                << " }, ";
         }
         *os << "Expected: ";
         for (const auto& [index, timestamp, value] : o.expected)
         {
-            *os << "{ SensorIndex: " << index << ", Timestamp: " << timestamp
-                << ", Value: " << value << " }, ";
+            *os << "{ SensorIndex: " << index
+                << ", Timestamp: " << timestamp.count() << ", Value: " << value
+                << " }, ";
         }
         *os << " }";
     }
@@ -98,20 +100,25 @@
 INSTANTIATE_TEST_SUITE_P(
     _, TestOnChangeThresholdUpdates,
     Values(
-        OnChangeParams().Updates({{0, 1, 80.0}}).Expected({{0, 1, 80.0}}),
+        OnChangeParams().Updates({{0, 1ms, 80.0}}).Expected({{0, 1ms, 80.0}}),
         OnChangeParams()
-            .Updates({{0, 1, 80.0}, {1, 2, 81.0}})
-            .Expected({{0, 1, 80.0}, {1, 2, 81.0}}),
+            .Updates({{0, 1ms, 80.0}, {1, 2ms, 81.0}})
+            .Expected({{0, 1ms, 80.0}, {1, 2ms, 81.0}}),
         OnChangeParams()
-            .Updates({{0, 1, 80.0}, {0, 2, 90.0}})
-            .Expected({{0, 1, 80.0}, {0, 2, 90.0}}),
+            .Updates({{0, 1ms, 80.0}, {0, 2ms, 90.0}})
+            .Expected({{0, 1ms, 80.0}, {0, 2ms, 90.0}}),
         OnChangeParams()
-            .Updates({{0, 1, 80.0}, {1, 2, 90.0}, {0, 3, 90.0}})
-            .Expected({{0, 1, 80.0}, {1, 2, 90.0}, {0, 3, 90.0}}),
+            .Updates({{0, 1ms, 80.0}, {1, 2ms, 90.0}, {0, 3ms, 90.0}})
+            .Expected({{0, 1ms, 80.0}, {1, 2ms, 90.0}, {0, 3ms, 90.0}}),
         OnChangeParams()
-            .Updates({{0, 1, 80.0}, {1, 2, 80.0}, {1, 3, 90.0}, {0, 4, 90.0}})
-            .Expected(
-                {{0, 1, 80.0}, {1, 2, 80.0}, {1, 3, 90.0}, {0, 4, 90.0}})));
+            .Updates({{0, 1ms, 80.0},
+                      {1, 2ms, 80.0},
+                      {1, 3ms, 90.0},
+                      {0, 4ms, 90.0}})
+            .Expected({{0, 1ms, 80.0},
+                       {1, 2ms, 80.0},
+                       {1, 3ms, 90.0},
+                       {0, 4ms, 90.0}})));
 
 TEST_P(TestOnChangeThresholdUpdates, senorsIsUpdatedMultipleTimes)
 {
diff --git a/tests/src/test_report.cpp b/tests/src/test_report.cpp
index dc08630..675171a 100644
--- a/tests/src/test_report.cpp
+++ b/tests/src/test_report.cpp
@@ -1,4 +1,5 @@
 #include "dbus_environment.hpp"
+#include "fakes/clock_fake.hpp"
 #include "helpers.hpp"
 #include "mocks/json_storage_mock.hpp"
 #include "mocks/metric_mock.hpp"
@@ -19,6 +20,8 @@
 using namespace std::chrono_literals;
 namespace tstring = utils::tstring;
 
+constexpr Milliseconds systemTimestamp = 55ms;
+
 class TestReport : public Test
 {
   public:
@@ -28,10 +31,17 @@
         std::make_unique<NiceMock<ReportManagerMock>>();
     testing::NiceMock<StorageMock> storageMock;
     std::vector<std::shared_ptr<MetricMock>> metricMocks;
+    std::unique_ptr<ClockFake> clockFakePtr = std::make_unique<ClockFake>();
+    ClockFake& clockFake = *clockFakePtr;
     std::unique_ptr<Report> sut;
 
     MockFunction<void()> checkPoint;
 
+    TestReport()
+    {
+        clockFake.system.set(systemTimestamp);
+    }
+
     void initMetricMocks(
         const std::vector<LabeledMetricParameters>& metricParameters)
     {
@@ -76,7 +86,7 @@
             params.reportUpdates(), *reportManagerMock, storageMock,
             utils::convContainer<std::shared_ptr<interfaces::Metric>>(
                 metricMocks),
-            params.enabled());
+            params.enabled(), std::move(clockFakePtr));
     }
 
     template <class T>
@@ -396,7 +406,7 @@
 
 TEST_P(TestReportAllReportTypes, updateReadingsCallEnabledPropertyOff)
 {
-    const uint64_t expectedTime = Clock().timestamp();
+    clockFake.system.advance(10ms);
 
     setProperty(sut->getPath(), "Enabled", false);
     sut->updateReadings();
@@ -404,19 +414,19 @@
         getProperty<Readings>(sut->getPath(), "Readings");
 
     EXPECT_THAT(getProperty<bool>(sut->getPath(), "Enabled"), Eq(false));
-    EXPECT_THAT(timestamp, Lt(expectedTime));
+    EXPECT_THAT(Milliseconds{timestamp}, Eq(0ms));
 }
 
 TEST_P(TestReportAllReportTypes, updateReadingsCallEnabledPropertyOn)
 {
-    const uint64_t expectedTime = Clock().timestamp();
+    clockFake.system.advance(10ms);
 
     sut->updateReadings();
     const auto [timestamp, readings] =
         getProperty<Readings>(sut->getPath(), "Readings");
 
     EXPECT_THAT(getProperty<bool>(sut->getPath(), "Enabled"), Eq(true));
-    EXPECT_THAT(timestamp, Ge(expectedTime));
+    EXPECT_THAT(Milliseconds{timestamp}, Eq(systemTimestamp + 10ms));
 }
 
 class TestReportOnRequestType : public TestReport
@@ -430,14 +440,14 @@
 
 TEST_F(TestReportOnRequestType, updatesReadingTimestamp)
 {
-    const uint64_t expectedTime = Clock().timestamp();
+    clockFake.system.advance(10ms);
 
     ASSERT_THAT(update(sut->getPath()), Eq(boost::system::errc::success));
 
     const auto [timestamp, readings] =
         getProperty<Readings>(sut->getPath(), "Readings");
 
-    EXPECT_THAT(timestamp, Ge(expectedTime));
+    EXPECT_THAT(Milliseconds{timestamp}, Eq(systemTimestamp + 10ms));
 }
 
 TEST_F(TestReportOnRequestType, updatesReadingWhenUpdateIsCalled)
@@ -509,13 +519,13 @@
 
 TEST_F(TestReportPeriodicReport, readingTimestampIsUpdatedAfterIntervalExpires)
 {
-    const uint64_t expectedTime = Clock().timestamp();
+    clockFake.system.advance(10ms);
     DbusEnvironment::sleepFor(ReportManager::minInterval + 1ms);
 
     const auto [timestamp, readings] =
         getProperty<Readings>(sut->getPath(), "Readings");
 
-    EXPECT_THAT(timestamp, Ge(expectedTime));
+    EXPECT_THAT(Milliseconds{timestamp}, Eq(systemTimestamp + 10ms));
 }
 
 TEST_F(TestReportPeriodicReport, readingsAreUpdatedAfterIntervalExpires)
diff --git a/tests/src/test_sensor.cpp b/tests/src/test_sensor.cpp
index ffa73b1..0eae668 100644
--- a/tests/src/test_sensor.cpp
+++ b/tests/src/test_sensor.cpp
@@ -52,7 +52,7 @@
     std::unique_ptr<stubs::DbusSensorObject> sensorObject = makeSensorObject();
 
     SensorCache sensorCache;
-    uint64_t timestamp = Clock().timestamp();
+    Milliseconds timestamp = Clock().steadyTimestamp();
     std::shared_ptr<Sensor> sut = sensorCache.makeSensor<Sensor>(
         DbusEnvironment::serviceName(), sensorObject->path(), "metadata",
         DbusEnvironment::getIoc(), DbusEnvironment::getBus());
diff --git a/tests/src/test_trigger_actions.cpp b/tests/src/test_trigger_actions.cpp
index 7a65fa2..1c36326 100644
--- a/tests/src/test_trigger_actions.cpp
+++ b/tests/src/test_trigger_actions.cpp
@@ -46,7 +46,7 @@
 
 TEST_P(TestLogToJournalNumeric, commitAnActionDoesNotThrow)
 {
-    EXPECT_NO_THROW(sut->commit("Test", 100'000, commmitValue));
+    EXPECT_NO_THROW(sut->commit("Test", Milliseconds{100'000}, commmitValue));
 }
 
 class TestLogToJournalNumericThrow : public TestLogToJournalNumeric
@@ -56,7 +56,7 @@
 
 TEST_P(TestLogToJournalNumericThrow, commitAnActionExpectThrow)
 {
-    EXPECT_THROW(sut->commit("Test", 100'000, commmitValue),
+    EXPECT_THROW(sut->commit("Test", Milliseconds{100'000}, commmitValue),
                  std::runtime_error);
 }
 
@@ -79,7 +79,7 @@
 
 TEST_P(TestLogToRedfishNumeric, commitExpectNoThrow)
 {
-    EXPECT_NO_THROW(sut->commit("Test", 100'000, commmitValue));
+    EXPECT_NO_THROW(sut->commit("Test", Milliseconds{100'000}, commmitValue));
 }
 
 class TestLogToRedfishNumericThrow : public TestLogToRedfishNumeric
@@ -89,7 +89,7 @@
 
 TEST_P(TestLogToRedfishNumericThrow, commitExpectToThrow)
 {
-    EXPECT_THROW(sut->commit("Test", 100'000, commmitValue),
+    EXPECT_THROW(sut->commit("Test", Milliseconds{100'000}, commmitValue),
                  std::runtime_error);
 }
 
@@ -130,7 +130,7 @@
 
 TEST_P(TestLogToJournalDiscrete, commitAnActionDoesNotThrow)
 {
-    EXPECT_NO_THROW(sut->commit("Test", 100'000, 90.0));
+    EXPECT_NO_THROW(sut->commit("Test", Milliseconds{100'000}, 90.0));
 }
 
 class TestLogToJournalDiscreteThrow : public TestLogToJournalDiscrete
@@ -141,7 +141,8 @@
 
 TEST_P(TestLogToJournalDiscreteThrow, commitAnActionExpectThrow)
 {
-    EXPECT_THROW(sut->commit("Test", 100'000, 90.0), std::runtime_error);
+    EXPECT_THROW(sut->commit("Test", Milliseconds{100'000}, 90.0),
+                 std::runtime_error);
 }
 
 class TestLogToRedfishDiscrete :
@@ -163,7 +164,7 @@
 
 TEST_P(TestLogToRedfishDiscrete, commitExpectNoThrow)
 {
-    EXPECT_NO_THROW(sut->commit("Test", 100'000, 90.0));
+    EXPECT_NO_THROW(sut->commit("Test", Milliseconds{100'000}, 90.0));
 }
 
 class TestLogToRedfishDiscreteThrow : public TestLogToRedfishDiscrete
@@ -174,7 +175,8 @@
 
 TEST_P(TestLogToRedfishDiscreteThrow, commitExpectToThrow)
 {
-    EXPECT_THROW(sut->commit("Test", 100'000, 90.0), std::runtime_error);
+    EXPECT_THROW(sut->commit("Test", Milliseconds{100'000}, 90.0),
+                 std::runtime_error);
 }
 
 namespace onChange
@@ -192,7 +194,7 @@
 
 TEST_F(TestLogToJournalDiscreteOnChange, commitExpectNoThrow)
 {
-    EXPECT_NO_THROW(sut->commit("Test", 100'000, 90.0));
+    EXPECT_NO_THROW(sut->commit("Test", Milliseconds{100'000}, 90.0));
 }
 
 class TestLogToRedfishDiscreteOnChange : public Test
@@ -208,7 +210,7 @@
 
 TEST_F(TestLogToRedfishDiscreteOnChange, commitExpectNoThrow)
 {
-    EXPECT_NO_THROW(sut->commit("Test", 100'000, 90.0));
+    EXPECT_NO_THROW(sut->commit("Test", Milliseconds{100'000}, 90.0));
 }
 } // namespace onChange
 } // namespace discrete
@@ -230,7 +232,7 @@
     EXPECT_CALL(reportManager, updateReport(_)).Times(0);
 
     make({});
-    sut->commit("Test", 100'000, 90.0);
+    sut->commit("Test", Milliseconds{100'000}, 90.0);
 }
 
 TEST_F(TestUpdateReport, commitExpectReportUpdate)
@@ -242,7 +244,7 @@
     }
 
     make(names);
-    sut->commit("Test", 100'000, 90.0);
+    sut->commit("Test", Milliseconds{100'000}, 90.0);
 }
 
 } // namespace action