fix the year 2038 problem in getDateTime

The existing codes cast uint64_t into time_t which is int32_t in
most 32-bit systems. It results overflow if the timestamp is larger
than INT_MAX.
time_t will be 64 bits in future releases of glibc. See
https://sourceware.org/bugzilla/show_bug.cgi?id=28182.

This change workarounds the year 2038 problem via boost's ptime.
std::chrono doesn't help since it is still 32 bits.

Tested on QEMU.
Example output for certificate:
{
  "Name": "HTTPS Certificate",
  "Subject": null,
  "ValidNotAfter": "2106-01-28T20:40:31Z",
  "ValidNotBefore": "2106-02-06T18:28:16Z"
}
Previously, the format is like "1969-12-31T12:00:00+00:00". Note
that the ending "+00:00" is the time zone, not ms.

Tested the schema on QEMU. No new Redfish Service Validator errors.

Signed-off-by: Nan Zhou <nanzhoumails@gmail.com>
Signed-off-by: Ed Tanous <edtanous@google.com>
Change-Id: I8ef0bee3d724184d96253c23f3919447828d3f82
diff --git a/http/utility.hpp b/http/utility.hpp
index 6f81be8..d141056 100644
--- a/http/utility.hpp
+++ b/http/utility.hpp
@@ -1,9 +1,10 @@
 #pragma once
-
 #include "nlohmann/json.hpp"
 
 #include <openssl/crypto.h>
 
+#include <boost/date_time/posix_time/posix_time.hpp>
+
 #include <chrono>
 #include <cstdint>
 #include <cstring>
@@ -572,26 +573,28 @@
 }
 
 /**
- * Method returns Date Time information according to requested format
+ * Method returns Date Time information in the ISO extended format
  *
- * @param[in] time time in second since the Epoch
+ * @param[in] timestamp in second since the Epoch; it can be negative
  *
- * @return Date Time according to requested format
+ * @return Date Time in the ISO extended format
  */
-inline std::string getDateTime(const std::time_t& time)
+inline std::string getDateTime(boost::posix_time::seconds secondsSinceEpoch)
 {
-    std::array<char, 128> dateTime;
-    std::string redfishDateTime("0000-00-00T00:00:00Z00:00");
+    boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1));
+    boost::posix_time::ptime time = epoch + secondsSinceEpoch;
+    // append zero offset to the end according to the Redfish spec for Date-Time
+    return boost::posix_time::to_iso_extended_string(time) + 'Z';
+}
 
-    if (std::strftime(dateTime.begin(), dateTime.size(), "%FT%T%z",
-                      std::localtime(&time)))
-    {
-        // insert the colon required by the ISO 8601 standard
-        redfishDateTime = std::string(dateTime.data());
-        redfishDateTime.insert(redfishDateTime.end() - 2, ':');
-    }
+inline std::string getDateTimeUint(uint64_t secondsSinceEpoch)
+{
+    return getDateTime(boost::posix_time::seconds(secondsSinceEpoch));
+}
 
-    return redfishDateTime;
+inline std::string getDateTimeStdtime(std::time_t secondsSinceEpoch)
+{
+    return getDateTime(boost::posix_time::seconds(secondsSinceEpoch));
 }
 
 /**
@@ -606,7 +609,7 @@
 inline std::pair<std::string, std::string> getDateTimeOffsetNow()
 {
     std::time_t time = std::time(nullptr);
-    std::string dateTime = getDateTime(time);
+    std::string dateTime = getDateTimeStdtime(time);
 
     /* extract the local Time Offset value from the
      * recevied dateTime string.