diff --git a/include/rcutils/time.h b/include/rcutils/time.h
index 0fb765e7..8ae8e6d3 100644
--- a/include/rcutils/time.h
+++ b/include/rcutils/time.h
@@ -28,19 +28,24 @@ extern "C"
#include "rcutils/types.h"
#include "rcutils/visibility_control.h"
+/// Convenience defintitions to commonly used numbers.
+#define RCUTILS_NANOSECONDS_PER_SEC 1000000000l
+#define RCUTILS_NANOSECONDS_PER_MILLISEC 1000000l
+#define RCUTILS_NANOSECONDS_PER_MICROSEC 1000l
+
/// Convenience macro to convert seconds to nanoseconds.
-#define RCUTILS_S_TO_NS(seconds) ((seconds) * (1000LL * 1000LL * 1000LL))
+#define RCUTILS_S_TO_NS(seconds) ((seconds) * RCUTILS_NANOSECONDS_PER_SEC)
/// Convenience macro to convert milliseconds to nanoseconds.
-#define RCUTILS_MS_TO_NS(milliseconds) ((milliseconds) * (1000LL * 1000LL))
+#define RCUTILS_MS_TO_NS(milliseconds) ((milliseconds) * RCUTILS_NANOSECONDS_PER_MILLISEC)
/// Convenience macro to convert microseconds to nanoseconds.
-#define RCUTILS_US_TO_NS(microseconds) ((microseconds) * 1000LL)
+#define RCUTILS_US_TO_NS(microseconds) ((microseconds) * RCUTILS_NANOSECONDS_PER_MICROSEC)
/// Convenience macro to convert nanoseconds to seconds.
-#define RCUTILS_NS_TO_S(nanoseconds) ((nanoseconds) / (1000LL * 1000LL * 1000LL))
+#define RCUTILS_NS_TO_S(nanoseconds) ((nanoseconds) / RCUTILS_NANOSECONDS_PER_SEC)
/// Convenience macro to convert nanoseconds to milliseconds.
-#define RCUTILS_NS_TO_MS(nanoseconds) ((nanoseconds) / (1000LL * 1000LL))
+#define RCUTILS_NS_TO_MS(nanoseconds) ((nanoseconds) / RCUTILS_NANOSECONDS_PER_MILLISEC)
/// Convenience macro to convert nanoseconds to microseconds.
-#define RCUTILS_NS_TO_US(nanoseconds) ((nanoseconds) / 1000LL)
+#define RCUTILS_NS_TO_US(nanoseconds) ((nanoseconds) / RCUTILS_NANOSECONDS_PER_MICROSEC)
/// Convenience macro for rcutils_steady_time_now(rcutils_time_point_value_t *).
#define RCUTILS_STEADY_TIME rcutils_steady_time_now
@@ -49,6 +54,69 @@ typedef int64_t rcutils_time_point_value_t;
/// A duration of time, measured in nanoseconds.
typedef int64_t rcutils_duration_value_t;
+/**
+ * This function returns an accurate conversion from nanoseconds to seconds.
+ *
+ * The nanoseconds argument has to be an int64_t to ensure exact division
+ *
+ *
+ * Attribute | Adherence
+ * ------------------ | -------------
+ * Allocates Memory | No
+ * Thread-Safe | Yes
+ * Uses Atomics | No
+ * Lock-Free | Yes
+ *
+ * \param[in] nanoseconds The int64_t needed for conversion
+ * \return double That nanoseconds number as seconds.
+ */
+RCUTILS_PUBLIC
+RCUTILS_WARN_UNUSED
+double
+rcutils_nanoseconds_to_seconds(const int64_t nanoseconds);
+
+/**
+ * This function returns an accurate conversion from nanoseconds to milliseconds.
+ *
+ * The nanoseconds argument has to be an int64_t to ensure exact division
+ *
+ *
+ * Attribute | Adherence
+ * ------------------ | -------------
+ * Allocates Memory | No
+ * Thread-Safe | Yes
+ * Uses Atomics | No
+ * Lock-Free | Yes
+ *
+ * \param[in] nanoseconds The int64_t needed for conversion
+ * \return double That nanoseconds number as milliseconds.
+ */
+RCUTILS_PUBLIC
+RCUTILS_WARN_UNUSED
+double
+rcutils_nanoseconds_to_milliseconds(const int64_t nanoseconds);
+
+/**
+ * This function returns an accurate conversion from nanoseconds to microseconds.
+ *
+ * The nanoseconds argument has to be an int64_t to ensure exact division
+ *
+ *
+ * Attribute | Adherence
+ * ------------------ | -------------
+ * Allocates Memory | No
+ * Thread-Safe | Yes
+ * Uses Atomics | No
+ * Lock-Free | Yes
+ *
+ * \param[in] nanoseconds The int64_t needed for conversion
+ * \return double That nanoseconds number as microseconds.
+ */
+RCUTILS_PUBLIC
+RCUTILS_WARN_UNUSED
+double
+rcutils_nanoseconds_to_microseconds(const int64_t nanoseconds);
+
/**
* This function returns the time from a system clock.
* The closest equivalent would be to std::chrono::system_clock::now();
diff --git a/src/time.c b/src/time.c
index 882c9d98..a2a88b3d 100644
--- a/src/time.c
+++ b/src/time.c
@@ -28,6 +28,48 @@ extern "C"
#include "rcutils/error_handling.h"
#include "rcutils/snprintf.h"
+double
+rcutils_nanoseconds_to_seconds(const int64_t nanoseconds)
+{
+ // scale the nanoseconds separately for improved accuracy
+ int64_t sec, nsec;
+ nsec = (nanoseconds % RCUTILS_NANOSECONDS_PER_SEC);
+ sec = ((nanoseconds - nsec) / RCUTILS_NANOSECONDS_PER_SEC);
+
+ double sec_double, nsec_double;
+ nsec_double = 1e-9 * (double)(nsec);
+ sec_double = (double)(sec);
+ return sec_double + nsec_double;
+}
+
+double
+rcutils_nanoseconds_to_milliseconds(const int64_t nanoseconds)
+{
+ // scale the nanoseconds separately for improved accuracy
+ int64_t sec, nsec;
+ nsec = (nanoseconds % RCUTILS_NANOSECONDS_PER_MILLISEC);
+ sec = ((nanoseconds - nsec) / RCUTILS_NANOSECONDS_PER_MILLISEC);
+
+ double sec_double, nsec_double;
+ nsec_double = 1e-6 * (double)(nsec);
+ sec_double = (double)(sec);
+ return sec_double + nsec_double;
+}
+
+double
+rcutils_nanoseconds_to_microseconds(const int64_t nanoseconds)
+{
+ // scale the nanoseconds separately for improved accuracy
+ int64_t sec, nsec;
+ nsec = (nanoseconds % RCUTILS_NANOSECONDS_PER_MICROSEC);
+ sec = ((nanoseconds - nsec) / RCUTILS_NANOSECONDS_PER_MICROSEC);
+
+ double sec_double, nsec_double;
+ nsec_double = 1e-3 * (double)(nsec);
+ sec_double = (double)(sec);
+ return sec_double + nsec_double;
+}
+
rcutils_ret_t
rcutils_time_point_value_as_nanoseconds_string(
const rcutils_time_point_value_t * time_point,
diff --git a/test/test_time.cpp b/test/test_time.cpp
index 5976cabf..a76be533 100644
--- a/test/test_time.cpp
+++ b/test/test_time.cpp
@@ -121,6 +121,36 @@ TEST_F(TestTimeFixture, test_rcutils_time_conversion_macros) {
9007199254740.992); // maximum precision double (53 bits)
}
+// Tests the rcutils time unit conversion functions.
+TEST_F(TestTimeFixture, test_rcutils_time_conversion_functions) {
+ // nanoseconds to seconds
+ EXPECT_EQ(rcutils_nanoseconds_to_seconds(1000000000ll), 1.0); // int64_t
+ EXPECT_EQ(rcutils_nanoseconds_to_seconds(1000000042ll), 1.000000042); // int64_t
+ EXPECT_EQ(rcutils_nanoseconds_to_seconds(-2999999999ll), -2.999999999); // int64_t
+ EXPECT_EQ(rcutils_nanoseconds_to_seconds(1 + 1), 0.000000002); // sum of two int64_ts
+ EXPECT_EQ(
+ rcutils_nanoseconds_to_seconds(9007199254740992),
+ 9007199.254740992); // maximum precision double as an int64_t
+
+ // nanoseconds to milliseconds
+ EXPECT_EQ(rcutils_nanoseconds_to_milliseconds(1000000ll), 1.0); // int64_t
+ EXPECT_EQ(rcutils_nanoseconds_to_milliseconds(1000042ll), 1.000042); // int64_t
+ EXPECT_EQ(rcutils_nanoseconds_to_milliseconds(-2999999ll), -2.999999); // int64_t
+ EXPECT_EQ(rcutils_nanoseconds_to_milliseconds(1 + 1), 0.000002); // sum of int64_ts
+ EXPECT_EQ(
+ rcutils_nanoseconds_to_milliseconds(9007199254740992),
+ 9007199254.740992); // maximum precision double as an int64_t
+
+ // nanoseconds to microseconds
+ EXPECT_EQ(rcutils_nanoseconds_to_microseconds(1000ll), 1.0); // int64_t
+ EXPECT_EQ(rcutils_nanoseconds_to_microseconds(1042ll), 1.042); // int64_t
+ EXPECT_EQ(rcutils_nanoseconds_to_microseconds(-2999ll), -2.999); // int64_t
+ EXPECT_EQ(rcutils_nanoseconds_to_microseconds(1 + 1), 0.002); // sum of int64_ts
+ EXPECT_EQ(
+ rcutils_nanoseconds_to_microseconds(9007199254740992),
+ 9007199254740.992); // maximum precision double as an int64_t
+}
+
// Tests the rcutils_system_time_now() function.
TEST_F(TestTimeFixture, test_rcutils_system_time_now) {
rcutils_ret_t ret;