Move time utils to be in one place

We've accumulated several time utility functions in the http classes.
Time isn't a core HTTP primitive, so http is not where those functions
below.

This commit moves all the time functions from the crow::utility
namespace into the redfish::time_utils namespace, as well as moves the
unit tests.

No code changes where made to the individual functions, with the
exception of changing the namespace on the unit tests.

Tested: Unit tests pass.

Signed-off-by: Ed Tanous <edtanous@google.com>
Change-Id: I8493375f60aea31899c84ae703e0f71a17dbdb73
diff --git a/http/ut/utility_test.cpp b/http/ut/utility_test.cpp
index 8bc122f..4d9bd91 100644
--- a/http/ut/utility_test.cpp
+++ b/http/ut/utility_test.cpp
@@ -81,63 +81,6 @@
     EXPECT_EQ(data, decoded);
 }
 
-TEST(Utility, GetDateTimeStdtime)
-{
-    // some time before the epoch
-    EXPECT_EQ(getDateTimeStdtime(std::time_t{-1234567}),
-              "1970-01-01T00:00:00+00:00");
-
-    // epoch
-    EXPECT_EQ(getDateTimeStdtime(std::time_t{0}), "1970-01-01T00:00:00+00:00");
-
-    // Limits
-    EXPECT_EQ(getDateTimeStdtime(std::numeric_limits<std::time_t>::max()),
-              "9999-12-31T23:59:59+00:00");
-    EXPECT_EQ(getDateTimeStdtime(std::numeric_limits<std::time_t>::min()),
-              "1970-01-01T00:00:00+00:00");
-}
-
-TEST(Utility, GetDateTimeUint)
-{
-    EXPECT_EQ(getDateTimeUint(uint64_t{1638312095}),
-              "2021-11-30T22:41:35+00:00");
-    // some time in the future, beyond 2038
-    EXPECT_EQ(getDateTimeUint(uint64_t{41638312095}),
-              "3289-06-18T21:48:15+00:00");
-    // the maximum time we support
-    EXPECT_EQ(getDateTimeUint(uint64_t{253402300799}),
-              "9999-12-31T23:59:59+00:00");
-
-    // returns the maximum Redfish date
-    EXPECT_EQ(getDateTimeUint(std::numeric_limits<uint64_t>::max()),
-              "9999-12-31T23:59:59+00:00");
-
-    EXPECT_EQ(getDateTimeUint(std::numeric_limits<uint64_t>::min()),
-              "1970-01-01T00:00:00+00:00");
-}
-
-TEST(Utility, GetDateTimeUintMs)
-{
-    EXPECT_EQ(getDateTimeUintMs(uint64_t{1638312095123}),
-              "2021-11-30T22:41:35.123+00:00");
-    // returns the maximum Redfish date
-    EXPECT_EQ(getDateTimeUintMs(std::numeric_limits<uint64_t>::max()),
-              "9999-12-31T23:59:59.999+00:00");
-    EXPECT_EQ(getDateTimeUintMs(std::numeric_limits<uint64_t>::min()),
-              "1970-01-01T00:00:00.000+00:00");
-}
-
-TEST(Utility, GetDateTimeUintUs)
-{
-    EXPECT_EQ(getDateTimeUintUs(uint64_t{1638312095123456}),
-              "2021-11-30T22:41:35.123456+00:00");
-    // returns the maximum Redfish date
-    EXPECT_EQ(getDateTimeUintUs(std::numeric_limits<uint64_t>::max()),
-              "9999-12-31T23:59:59.999999+00:00");
-    EXPECT_EQ(getDateTimeUintUs(std::numeric_limits<uint64_t>::min()),
-              "1970-01-01T00:00:00.000000+00:00");
-}
-
 TEST(Utility, UrlFromPieces)
 {
     boost::urls::url url = urlFromPieces("redfish", "v1", "foo");
diff --git a/http/utility.hpp b/http/utility.hpp
index c9728f5..e08e565 100644
--- a/http/utility.hpp
+++ b/http/utility.hpp
@@ -539,190 +539,6 @@
     return true;
 }
 
-namespace details
-{
-// Returns year/month/day triple in civil calendar
-// Preconditions:  z is number of days since 1970-01-01 and is in the range:
-//                   [numeric_limits<Int>::min(),
-//                   numeric_limits<Int>::max()-719468].
-// Algorithm sourced from
-// https://howardhinnant.github.io/date_algorithms.html#civil_from_days
-// All constants are explained in the above
-template <class IntType>
-constexpr std::tuple<IntType, unsigned, unsigned>
-    civilFromDays(IntType z) noexcept
-{
-    z += 719468;
-    IntType era = (z >= 0 ? z : z - 146096) / 146097;
-    unsigned doe = static_cast<unsigned>(z - era * 146097); // [0, 146096]
-    unsigned yoe =
-        (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365; // [0, 399]
-    IntType y = static_cast<IntType>(yoe) + era * 400;
-    unsigned doy = doe - (365 * yoe + yoe / 4 - yoe / 100); // [0, 365]
-    unsigned mp = (5 * doy + 2) / 153;                      // [0, 11]
-    unsigned d = doy - (153 * mp + 2) / 5 + 1;              // [1, 31]
-    unsigned m = mp < 10 ? mp + 3 : mp - 9;                 // [1, 12]
-
-    return std::tuple<IntType, unsigned, unsigned>(y + (m <= 2), m, d);
-}
-
-// Creates a string from an integer in the most efficient way possible without
-// using std::locale.  Adds an exact zero pad based on the pad input parameter.
-// Does not handle negative numbers.
-inline std::string padZeros(int value, size_t pad)
-{
-    std::string result(pad, '0');
-    for (int val = value; pad > 0; pad--)
-    {
-        result[pad - 1] = static_cast<char>('0' + val % 10);
-        val /= 10;
-    }
-    return result;
-}
-
-template <typename IntType, typename Period>
-std::string toISO8061ExtendedStr(std::chrono::duration<IntType, Period> t)
-{
-    using seconds = std::chrono::duration<int>;
-    using minutes = std::chrono::duration<int, std::ratio<60>>;
-    using hours = std::chrono::duration<int, std::ratio<3600>>;
-    using days = std::chrono::duration<
-        IntType, std::ratio_multiply<hours::period, std::ratio<24>>>;
-
-    // d is days since 1970-01-01
-    days d = std::chrono::duration_cast<days>(t);
-
-    // t is now time duration since midnight of day d
-    t -= d;
-
-    // break d down into year/month/day
-    int year = 0;
-    int month = 0;
-    int day = 0;
-    std::tie(year, month, day) = details::civilFromDays(d.count());
-    // Check against limits.  Can't go above year 9999, and can't go below epoch
-    // (1970)
-    if (year >= 10000)
-    {
-        year = 9999;
-        month = 12;
-        day = 31;
-        t = days(1) - std::chrono::duration<IntType, Period>(1);
-    }
-    else if (year < 1970)
-    {
-        year = 1970;
-        month = 1;
-        day = 1;
-        t = std::chrono::duration<IntType, Period>::zero();
-    }
-    std::string out;
-    out += details::padZeros(year, 4);
-    out += '-';
-    out += details::padZeros(month, 2);
-    out += '-';
-    out += details::padZeros(day, 2);
-
-    out += 'T';
-    hours hr = duration_cast<hours>(t);
-    out += details::padZeros(hr.count(), 2);
-    t -= hr;
-    out += ':';
-
-    minutes mt = duration_cast<minutes>(t);
-    out += details::padZeros(mt.count(), 2);
-    t -= mt;
-    out += ':';
-
-    seconds se = duration_cast<seconds>(t);
-    out += details::padZeros(se.count(), 2);
-    t -= se;
-
-    if constexpr (std::is_same_v<typename decltype(t)::period, std::milli>)
-    {
-        out += '.';
-        using MilliDuration = std::chrono::duration<int, std::milli>;
-        MilliDuration subsec = duration_cast<MilliDuration>(t);
-        out += details::padZeros(subsec.count(), 3);
-    }
-    else if constexpr (std::is_same_v<typename decltype(t)::period, std::micro>)
-    {
-        out += '.';
-        using MicroDuration = std::chrono::duration<int, std::micro>;
-        MicroDuration subsec = duration_cast<MicroDuration>(t);
-        out += details::padZeros(subsec.count(), 6);
-    }
-
-    out += "+00:00";
-    return out;
-}
-} // namespace details
-
-// Returns the formatted date time string.
-// Note that the maximum supported date is 9999-12-31T23:59:59+00:00, if
-// the given |secondsSinceEpoch| is too large, we return the maximum supported
-// date.
-inline std::string getDateTimeUint(uint64_t secondsSinceEpoch)
-{
-    using DurationType = std::chrono::duration<uint64_t>;
-    DurationType sinceEpoch(secondsSinceEpoch);
-    return details::toISO8061ExtendedStr(sinceEpoch);
-}
-
-// Returns the formatted date time string with millisecond precision
-// Note that the maximum supported date is 9999-12-31T23:59:59+00:00, if
-// the given |secondsSinceEpoch| is too large, we return the maximum supported
-// date.
-inline std::string getDateTimeUintMs(uint64_t milliSecondsSinceEpoch)
-{
-    using DurationType = std::chrono::duration<uint64_t, std::milli>;
-    DurationType sinceEpoch(milliSecondsSinceEpoch);
-    return details::toISO8061ExtendedStr(sinceEpoch);
-}
-
-// Returns the formatted date time string with microsecond precision
-inline std::string getDateTimeUintUs(uint64_t microSecondsSinceEpoch)
-{
-    using DurationType = std::chrono::duration<uint64_t, std::micro>;
-    DurationType sinceEpoch(microSecondsSinceEpoch);
-    return details::toISO8061ExtendedStr(sinceEpoch);
-}
-
-inline std::string getDateTimeStdtime(std::time_t secondsSinceEpoch)
-{
-    using DurationType = std::chrono::duration<std::time_t>;
-    DurationType sinceEpoch(secondsSinceEpoch);
-    return details::toISO8061ExtendedStr(sinceEpoch);
-}
-
-/**
- * Returns the current Date, Time & the local Time Offset
- * infromation in a pair
- *
- * @param[in] None
- *
- * @return std::pair<std::string, std::string>, which consist
- * of current DateTime & the TimeOffset strings respectively.
- */
-inline std::pair<std::string, std::string> getDateTimeOffsetNow()
-{
-    std::time_t time = std::time(nullptr);
-    std::string dateTime = getDateTimeStdtime(time);
-
-    /* extract the local Time Offset value from the
-     * recevied dateTime string.
-     */
-    std::string timeOffset("Z00:00");
-    std::size_t lastPos = dateTime.size();
-    std::size_t len = timeOffset.size();
-    if (lastPos > len)
-    {
-        timeOffset = dateTime.substr(lastPos - len);
-    }
-
-    return std::make_pair(dateTime, timeOffset);
-}
-
 inline bool constantTimeStringCompare(const std::string_view a,
                                       const std::string_view b)
 {
diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp
index d581aeb..2087e54 100644
--- a/redfish-core/include/event_service_manager.hpp
+++ b/redfish-core/include/event_service_manager.hpp
@@ -416,15 +416,15 @@
         logEntryArray.push_back({});
         nlohmann::json& logEntryJson = logEntryArray.back();
 
-        logEntryJson = {
-            {"EventId", "TestID"},
-            {"EventType", "Event"},
-            {"Severity", "OK"},
-            {"Message", "Generated test event"},
-            {"MessageId", "OpenBMC.0.2.TestEventLog"},
-            {"MessageArgs", nlohmann::json::array()},
-            {"EventTimestamp", crow::utility::getDateTimeOffsetNow().first},
-            {"Context", customText}};
+        logEntryJson = {{"EventId", "TestID"},
+                        {"EventType", "Event"},
+                        {"Severity", "OK"},
+                        {"Message", "Generated test event"},
+                        {"MessageId", "OpenBMC.0.2.TestEventLog"},
+                        {"MessageArgs", nlohmann::json::array()},
+                        {"EventTimestamp",
+                         redfish::time_utils::getDateTimeOffsetNow().first},
+                        {"Context", customText}};
 
         nlohmann::json msg;
         msg["@odata.type"] = "#Event.v1_4_0.Event";
@@ -1027,7 +1027,8 @@
         nlohmann::json event = {
             {"EventId", eventId},
             {"MemberId", memberId},
-            {"EventTimestamp", crow::utility::getDateTimeOffsetNow().first},
+            {"EventTimestamp",
+             redfish::time_utils::getDateTimeOffsetNow().first},
             {"OriginOfCondition", origin}};
         for (nlohmann::json::iterator it = event.begin(); it != event.end();
              ++it)
@@ -1085,7 +1086,8 @@
         {
             std::shared_ptr<Subscription> entry = it.second;
             nlohmann::json msgJson = {
-                {"Timestamp", crow::utility::getDateTimeOffsetNow().first},
+                {"Timestamp",
+                 redfish::time_utils::getDateTimeOffsetNow().first},
                 {"OriginOfCondition", "/ibm/v1/HMC/BroadcastService"},
                 {"Name", "Broadcast Message"},
                 {"Message", broadcastMsg}};
diff --git a/redfish-core/include/utils/time_utils.hpp b/redfish-core/include/utils/time_utils.hpp
index e814c51..2733ba2 100644
--- a/redfish-core/include/utils/time_utils.hpp
+++ b/redfish-core/include/utils/time_utils.hpp
@@ -238,5 +238,190 @@
     return std::make_optional(duration);
 }
 
+namespace details
+{
+// Returns year/month/day triple in civil calendar
+// Preconditions:  z is number of days since 1970-01-01 and is in the range:
+//                   [numeric_limits<Int>::min(),
+//                   numeric_limits<Int>::max()-719468].
+// Algorithm sourced from
+// https://howardhinnant.github.io/date_algorithms.html#civil_from_days
+// All constants are explained in the above
+template <class IntType>
+constexpr std::tuple<IntType, unsigned, unsigned>
+    civilFromDays(IntType z) noexcept
+{
+    z += 719468;
+    IntType era = (z >= 0 ? z : z - 146096) / 146097;
+    unsigned doe = static_cast<unsigned>(z - era * 146097); // [0, 146096]
+    unsigned yoe =
+        (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365; // [0, 399]
+    IntType y = static_cast<IntType>(yoe) + era * 400;
+    unsigned doy = doe - (365 * yoe + yoe / 4 - yoe / 100); // [0, 365]
+    unsigned mp = (5 * doy + 2) / 153;                      // [0, 11]
+    unsigned d = doy - (153 * mp + 2) / 5 + 1;              // [1, 31]
+    unsigned m = mp < 10 ? mp + 3 : mp - 9;                 // [1, 12]
+
+    return std::tuple<IntType, unsigned, unsigned>(y + (m <= 2), m, d);
+}
+
+// Creates a string from an integer in the most efficient way possible without
+// using std::locale.  Adds an exact zero pad based on the pad input parameter.
+// Does nt handle negative numbers.
+inline std::string padZeros(int value, size_t pad)
+{
+    std::string result(pad, '0');
+    for (int val = value; pad > 0; pad--)
+    {
+        result[pad - 1] = static_cast<char>('0' + val % 10);
+        val /= 10;
+    }
+    return result;
+}
+
+template <typename IntType, typename Period>
+std::string toISO8061ExtendedStr(std::chrono::duration<IntType, Period> t)
+{
+    using seconds = std::chrono::duration<int>;
+    using minutes = std::chrono::duration<int, std::ratio<60>>;
+    using hours = std::chrono::duration<int, std::ratio<3600>>;
+    using days = std::chrono::duration<
+        IntType, std::ratio_multiply<hours::period, std::ratio<24>>>;
+
+    // d is days since 1970-01-01
+    days d = std::chrono::duration_cast<days>(t);
+
+    // t is now time duration since midnight of day d
+    t -= d;
+
+    // break d down into year/month/day
+    int year = 0;
+    int month = 0;
+    int day = 0;
+    std::tie(year, month, day) = details::civilFromDays(d.count());
+    // Check against limits.  Can't go above year 9999, and can't go below epoch
+    // (1970)
+    if (year >= 10000)
+    {
+        year = 9999;
+        month = 12;
+        day = 31;
+        t = days(1) - std::chrono::duration<IntType, Period>(1);
+    }
+    else if (year < 1970)
+    {
+        year = 1970;
+        month = 1;
+        day = 1;
+        t = std::chrono::duration<IntType, Period>::zero();
+    }
+
+    std::string out;
+    out += details::padZeros(year, 4);
+    out += '-';
+    out += details::padZeros(month, 2);
+    out += '-';
+    out += details::padZeros(day, 2);
+    out += 'T';
+    hours hr = duration_cast<hours>(t);
+    out += details::padZeros(hr.count(), 2);
+    t -= hr;
+    out += ':';
+
+    minutes mt = duration_cast<minutes>(t);
+    out += details::padZeros(mt.count(), 2);
+    t -= mt;
+    out += ':';
+
+    seconds se = duration_cast<seconds>(t);
+    out += details::padZeros(se.count(), 2);
+    t -= se;
+
+    if constexpr (std::is_same_v<typename decltype(t)::period, std::milli>)
+    {
+        out += '.';
+        using MilliDuration = std::chrono::duration<int, std::milli>;
+        MilliDuration subsec = duration_cast<MilliDuration>(t);
+        out += details::padZeros(subsec.count(), 3);
+    }
+    else if constexpr (std::is_same_v<typename decltype(t)::period, std::micro>)
+    {
+        out += '.';
+
+        using MicroDuration = std::chrono::duration<int, std::micro>;
+        MicroDuration subsec = duration_cast<MicroDuration>(t);
+        out += details::padZeros(subsec.count(), 6);
+    }
+
+    out += "+00:00";
+    return out;
+}
+} // namespace details
+
+// Returns the formatted date time string.
+// Note that the maximum supported date is 9999-12-31T23:59:59+00:00, if
+// the given |secondsSinceEpoch| is too large, we return the maximum supported
+// date.
+inline std::string getDateTimeUint(uint64_t secondsSinceEpoch)
+{
+    using DurationType = std::chrono::duration<uint64_t>;
+    DurationType sinceEpoch(secondsSinceEpoch);
+    return details::toISO8061ExtendedStr(sinceEpoch);
+}
+
+// Returns the formatted date time string with millisecond precision
+// Note that the maximum supported date is 9999-12-31T23:59:59+00:00, if
+// the given |secondsSinceEpoch| is too large, we return the maximum supported
+// date.
+inline std::string getDateTimeUintMs(uint64_t milliSecondsSinceEpoch)
+{
+    using DurationType = std::chrono::duration<uint64_t, std::milli>;
+    DurationType sinceEpoch(milliSecondsSinceEpoch);
+    return details::toISO8061ExtendedStr(sinceEpoch);
+}
+
+// Returns the formatted date time string with microsecond precision
+inline std::string getDateTimeUintUs(uint64_t microSecondsSinceEpoch)
+{
+    using DurationType = std::chrono::duration<uint64_t, std::micro>;
+    DurationType sinceEpoch(microSecondsSinceEpoch);
+    return details::toISO8061ExtendedStr(sinceEpoch);
+}
+
+inline std::string getDateTimeStdtime(std::time_t secondsSinceEpoch)
+{
+    using DurationType = std::chrono::duration<std::time_t>;
+    DurationType sinceEpoch(secondsSinceEpoch);
+    return details::toISO8061ExtendedStr(sinceEpoch);
+}
+
+/**
+ * Returns the current Date, Time & the local Time Offset
+ * infromation in a pair
+ *
+ * @param[in] None
+ *
+ * @return std::pair<std::string, std::string>, which consist
+ * of current DateTime & the TimeOffset strings respectively.
+ */
+inline std::pair<std::string, std::string> getDateTimeOffsetNow()
+{
+    std::time_t time = std::time(nullptr);
+    std::string dateTime = getDateTimeStdtime(time);
+
+    /* extract the local Time Offset value from the
+     * recevied dateTime string.
+     */
+    std::string timeOffset("Z00:00");
+    std::size_t lastPos = dateTime.size();
+    std::size_t len = timeOffset.size();
+    if (lastPos > len)
+    {
+        timeOffset = dateTime.substr(lastPos - len);
+    }
+
+    return std::make_pair(dateTime, timeOffset);
+}
+
 } // namespace time_utils
 } // namespace redfish
diff --git a/redfish-core/lib/certificate_service.hpp b/redfish-core/lib/certificate_service.hpp
index fc347dc..471b45a 100644
--- a/redfish-core/lib/certificate_service.hpp
+++ b/redfish-core/lib/certificate_service.hpp
@@ -690,7 +690,7 @@
                 if (value != nullptr)
                 {
                     asyncResp->res.jsonValue["ValidNotAfter"] =
-                        crow::utility::getDateTimeUint(*value);
+                        redfish::time_utils::getDateTimeUint(*value);
                 }
             }
             else if (property.first == "ValidNotBefore")
@@ -699,7 +699,7 @@
                 if (value != nullptr)
                 {
                     asyncResp->res.jsonValue["ValidNotBefore"] =
-                        crow::utility::getDateTimeUint(*value);
+                        redfish::time_utils::getDateTimeUint(*value);
                 }
             }
         }
diff --git a/redfish-core/lib/log_services.hpp b/redfish-core/lib/log_services.hpp
index e806bfa..32afd36 100644
--- a/redfish-core/lib/log_services.hpp
+++ b/redfish-core/lib/log_services.hpp
@@ -38,6 +38,7 @@
 #include <error_messages.hpp>
 #include <query.hpp>
 #include <registries/privilege_registry.hpp>
+#include <utils/time_utils.hpp>
 
 #include <charconv>
 #include <filesystem>
@@ -178,7 +179,8 @@
                          << strerror(-ret);
         return false;
     }
-    entryTimestamp = crow::utility::getDateTimeUint(timestamp / 1000 / 1000);
+    entryTimestamp =
+        redfish::time_utils::getDateTimeUint(timestamp / 1000 / 1000);
     return true;
 }
 
@@ -495,7 +497,8 @@
             thisEntry["@odata.id"] = entriesPath + entryID;
             thisEntry["Id"] = entryID;
             thisEntry["EntryType"] = "Event";
-            thisEntry["Created"] = crow::utility::getDateTimeUint(timestamp);
+            thisEntry["Created"] =
+                redfish::time_utils::getDateTimeUint(timestamp);
             thisEntry["Name"] = dumpType + " Dump Entry";
 
             if (dumpType == "BMC")
@@ -580,7 +583,7 @@
             asyncResp->res.jsonValue["Id"] = entryID;
             asyncResp->res.jsonValue["EntryType"] = "Event";
             asyncResp->res.jsonValue["Created"] =
-                crow::utility::getDateTimeUint(timestamp);
+                redfish::time_utils::getDateTimeUint(timestamp);
             asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entry";
 
             if (dumpType == "BMC")
@@ -990,7 +993,7 @@
         asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
 
         std::pair<std::string, std::string> redfishDateTimeOffset =
-            crow::utility::getDateTimeOffsetNow();
+            redfish::time_utils::getDateTimeOffsetNow();
 
         asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
         asyncResp->res.jsonValue["DateTimeLocalOffset"] =
@@ -1442,9 +1445,9 @@
                 thisEntry["Severity"] =
                     translateSeverityDbusToRedfish(*severity);
                 thisEntry["Created"] =
-                    crow::utility::getDateTimeUintMs(*timestamp);
+                    redfish::time_utils::getDateTimeUintMs(*timestamp);
                 thisEntry["Modified"] =
-                    crow::utility::getDateTimeUintMs(*updateTimestamp);
+                    redfish::time_utils::getDateTimeUintMs(*updateTimestamp);
                 if (filePath != nullptr)
                 {
                     thisEntry["AdditionalDataURI"] =
@@ -1565,9 +1568,9 @@
             asyncResp->res.jsonValue["Severity"] =
                 translateSeverityDbusToRedfish(*severity);
             asyncResp->res.jsonValue["Created"] =
-                crow::utility::getDateTimeUintMs(*timestamp);
+                redfish::time_utils::getDateTimeUintMs(*timestamp);
             asyncResp->res.jsonValue["Modified"] =
-                crow::utility::getDateTimeUintMs(*updateTimestamp);
+                redfish::time_utils::getDateTimeUintMs(*updateTimestamp);
             if (filePath != nullptr)
             {
                 asyncResp->res.jsonValue["AdditionalDataURI"] =
@@ -2106,7 +2109,7 @@
         asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
 
         std::pair<std::string, std::string> redfishDateTimeOffset =
-            crow::utility::getDateTimeOffsetNow();
+            redfish::time_utils::getDateTimeOffsetNow();
         asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
         asyncResp->res.jsonValue["DateTimeLocalOffset"] =
             redfishDateTimeOffset.second;
@@ -2378,7 +2381,7 @@
     asyncResp->res.jsonValue["OverWritePolicy"] = std::move(overWritePolicy);
 
     std::pair<std::string, std::string> redfishDateTimeOffset =
-        crow::utility::getDateTimeOffsetNow();
+        redfish::time_utils::getDateTimeOffsetNow();
     asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
     asyncResp->res.jsonValue["DateTimeLocalOffset"] =
         redfishDateTimeOffset.second;
@@ -2578,7 +2581,7 @@
         asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
 
         std::pair<std::string, std::string> redfishDateTimeOffset =
-            crow::utility::getDateTimeOffsetNow();
+            redfish::time_utils::getDateTimeOffsetNow();
         asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
         asyncResp->res.jsonValue["DateTimeLocalOffset"] =
             redfishDateTimeOffset.second;
@@ -2712,7 +2715,7 @@
         asyncResp->res.jsonValue["MaxNumberOfRecords"] = 3;
 
         std::pair<std::string, std::string> redfishDateTimeOffset =
-            crow::utility::getDateTimeOffsetNow();
+            redfish::time_utils::getDateTimeOffsetNow();
         asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
         asyncResp->res.jsonValue["DateTimeLocalOffset"] =
             redfishDateTimeOffset.second;
@@ -3195,7 +3198,7 @@
             "/redfish/v1/Systems/system/LogServices/PostCodes/Entries";
 
         std::pair<std::string, std::string> redfishDateTimeOffset =
-            crow::utility::getDateTimeOffsetNow();
+            redfish::time_utils::getDateTimeOffsetNow();
         asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
         asyncResp->res.jsonValue["DateTimeLocalOffset"] =
             redfishDateTimeOffset.second;
@@ -3302,7 +3305,7 @@
         // Get the Created time from the timestamp
         std::string entryTimeStr;
         entryTimeStr =
-            crow::utility::getDateTimeUint(usecSinceEpoch / 1000 / 1000);
+            redfish::time_utils::getDateTimeUint(usecSinceEpoch / 1000 / 1000);
 
         // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex)
         std::ostringstream hexCode;
diff --git a/redfish-core/lib/managers.hpp b/redfish-core/lib/managers.hpp
index a98ff22..b8fe156 100644
--- a/redfish-core/lib/managers.hpp
+++ b/redfish-core/lib/managers.hpp
@@ -24,6 +24,7 @@
 #include "utils/dbus_utils.hpp"
 #include "utils/sw_utils.hpp"
 #include "utils/systemd_utils.hpp"
+#include "utils/time_utils.hpp"
 
 #include <boost/date_time.hpp>
 #include <sdbusplus/asio/property.hpp>
@@ -1750,7 +1751,7 @@
 
         // Convert to ISO 8601 standard
         aResp->res.jsonValue["LastResetTime"] =
-            crow::utility::getDateTimeUint(lastResetTimeStamp);
+            redfish::time_utils::getDateTimeUint(lastResetTimeStamp);
         });
 }
 
@@ -1984,7 +1985,7 @@
         resetToDefaults["ResetType@Redfish.AllowableValues"] = {"ResetAll"};
 
         std::pair<std::string, std::string> redfishDateTimeOffset =
-            crow::utility::getDateTimeOffsetNow();
+            redfish::time_utils::getDateTimeOffsetNow();
 
         asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
         asyncResp->res.jsonValue["DateTimeLocalOffset"] =
diff --git a/redfish-core/lib/metric_report.hpp b/redfish-core/lib/metric_report.hpp
index b93483c..18830f1 100644
--- a/redfish-core/lib/metric_report.hpp
+++ b/redfish-core/lib/metric_report.hpp
@@ -2,6 +2,7 @@
 
 #include "utils/collection.hpp"
 #include "utils/telemetry_utils.hpp"
+#include "utils/time_utils.hpp"
 
 #include <app.hpp>
 #include <dbus_utility.hpp>
@@ -32,7 +33,7 @@
             {"MetricId", id},
             {"MetricProperty", metadata},
             {"MetricValue", std::to_string(sensorValue)},
-            {"Timestamp", crow::utility::getDateTimeUintMs(timestamp)},
+            {"Timestamp", redfish::time_utils::getDateTimeUintMs(timestamp)},
         });
     }
 
@@ -55,7 +56,7 @@
             .string();
 
     const auto& [timestamp, readings] = timestampReadings;
-    json["Timestamp"] = crow::utility::getDateTimeUintMs(timestamp);
+    json["Timestamp"] = redfish::time_utils::getDateTimeUintMs(timestamp);
     json["MetricValues"] = toMetricValues(readings);
     return true;
 }
diff --git a/redfish-core/lib/systems.hpp b/redfish-core/lib/systems.hpp
index dd58e1b..0c2c53c 100644
--- a/redfish-core/lib/systems.hpp
+++ b/redfish-core/lib/systems.hpp
@@ -21,6 +21,7 @@
 #include "pcie.hpp"
 #include "query.hpp"
 #include "redfish_util.hpp"
+#include "utils/time_utils.hpp"
 
 #include <app.hpp>
 #include <boost/container/flat_map.hpp>
@@ -1079,7 +1080,7 @@
 
         // Convert to ISO 8601 standard
         aResp->res.jsonValue["LastResetTime"] =
-            crow::utility::getDateTimeUint(lastResetTimeStamp);
+            redfish::time_utils::getDateTimeUint(lastResetTimeStamp);
         });
 }
 
diff --git a/redfish-core/lib/task.hpp b/redfish-core/lib/task.hpp
index 7d96e42..be48a5b 100644
--- a/redfish-core/lib/task.hpp
+++ b/redfish-core/lib/task.hpp
@@ -395,11 +395,11 @@
         asyncResp->res.jsonValue["Name"] = "Task " + strParam;
         asyncResp->res.jsonValue["TaskState"] = ptr->state;
         asyncResp->res.jsonValue["StartTime"] =
-            crow::utility::getDateTimeStdtime(ptr->startTime);
+            redfish::time_utils::getDateTimeStdtime(ptr->startTime);
         if (ptr->endTime)
         {
             asyncResp->res.jsonValue["EndTime"] =
-                crow::utility::getDateTimeStdtime(*(ptr->endTime));
+                redfish::time_utils::getDateTimeStdtime(*(ptr->endTime));
         }
         asyncResp->res.jsonValue["TaskStatus"] = ptr->status;
         asyncResp->res.jsonValue["Messages"] = ptr->messages;
@@ -473,7 +473,7 @@
         asyncResp->res.jsonValue["Name"] = "Task Service";
         asyncResp->res.jsonValue["Id"] = "TaskService";
         asyncResp->res.jsonValue["DateTime"] =
-            crow::utility::getDateTimeOffsetNow().first;
+            redfish::time_utils::getDateTimeOffsetNow().first;
         asyncResp->res.jsonValue["CompletedTaskOverWritePolicy"] = "Oldest";
 
         asyncResp->res.jsonValue["LifeCycleEventOnTaskStateChange"] = true;
diff --git a/redfish-core/ut/time_utils_test.cpp b/redfish-core/ut/time_utils_test.cpp
index e390fbd..035d8ce 100644
--- a/redfish-core/ut/time_utils_test.cpp
+++ b/redfish-core/ut/time_utils_test.cpp
@@ -82,5 +82,62 @@
               std::nullopt);
 }
 
+TEST(GetDateTimeStdtime, ConversionTests)
+{
+    // some time before the epoch
+    EXPECT_EQ(getDateTimeStdtime(std::time_t{-1234567}),
+              "1970-01-01T00:00:00+00:00");
+
+    // epoch
+    EXPECT_EQ(getDateTimeStdtime(std::time_t{0}), "1970-01-01T00:00:00+00:00");
+
+    // Limits
+    EXPECT_EQ(getDateTimeStdtime(std::numeric_limits<std::time_t>::max()),
+              "9999-12-31T23:59:59+00:00");
+    EXPECT_EQ(getDateTimeStdtime(std::numeric_limits<std::time_t>::min()),
+              "1970-01-01T00:00:00+00:00");
+}
+
+TEST(GetDateTimeUint, ConversionTests)
+{
+    EXPECT_EQ(getDateTimeUint(uint64_t{1638312095}),
+              "2021-11-30T22:41:35+00:00");
+    // some time in the future, beyond 2038
+    EXPECT_EQ(getDateTimeUint(uint64_t{41638312095}),
+              "3289-06-18T21:48:15+00:00");
+    // the maximum time we support
+    EXPECT_EQ(getDateTimeUint(uint64_t{253402300799}),
+              "9999-12-31T23:59:59+00:00");
+
+    // returns the maximum Redfish date
+    EXPECT_EQ(getDateTimeUint(std::numeric_limits<uint64_t>::max()),
+              "9999-12-31T23:59:59+00:00");
+
+    EXPECT_EQ(getDateTimeUint(std::numeric_limits<uint64_t>::min()),
+              "1970-01-01T00:00:00+00:00");
+}
+
+TEST(GetDateTimeUintMs, ConverstionTests)
+{
+    EXPECT_EQ(getDateTimeUintMs(uint64_t{1638312095123}),
+              "2021-11-30T22:41:35.123+00:00");
+    // returns the maximum Redfish date
+    EXPECT_EQ(getDateTimeUintMs(std::numeric_limits<uint64_t>::max()),
+              "9999-12-31T23:59:59.999+00:00");
+    EXPECT_EQ(getDateTimeUintMs(std::numeric_limits<uint64_t>::min()),
+              "1970-01-01T00:00:00.000+00:00");
+}
+
+TEST(Utility, GetDateTimeUintUs)
+{
+    EXPECT_EQ(getDateTimeUintUs(uint64_t{1638312095123456}),
+              "2021-11-30T22:41:35.123456+00:00");
+    // returns the maximum Redfish date
+    EXPECT_EQ(getDateTimeUintUs(std::numeric_limits<uint64_t>::max()),
+              "9999-12-31T23:59:59.999999+00:00");
+    EXPECT_EQ(getDateTimeUintUs(std::numeric_limits<uint64_t>::min()),
+              "1970-01-01T00:00:00.000000+00:00");
+}
+
 } // namespace
 } // namespace redfish::time_utils