util: fix Y2038 problem in time::toString()
Avoid using time_t, which cannot correctly represent
dates after 19 January 2038 on 32-bit systems.
Change-Id: I04e8d31a1c04a112cbc81810143fe2233e6dcc22
Refs: #3915
diff --git a/src/util/time.cpp b/src/util/time.cpp
index d3e546a..64b43e3 100644
--- a/src/util/time.cpp
+++ b/src/util/time.cpp
@@ -105,7 +105,7 @@
const system_clock::TimePoint&
getUnixEpoch()
{
- static auto epoch = system_clock::from_time_t(0);
+ static constexpr system_clock::TimePoint epoch(seconds::zero());
return epoch;
}
@@ -121,23 +121,30 @@
return getUnixEpoch() + duration;
}
-std::string
-toIsoString(const system_clock::TimePoint& timePoint)
+static boost::posix_time::ptime
+convertToPosixTime(const system_clock::TimePoint& timePoint)
{
namespace bpt = boost::posix_time;
static bpt::ptime epoch(boost::gregorian::date(1970, 1, 1));
-#ifdef BOOST_DATE_TIME_POSIX_TIME_STD_CONFIG
- using BptResolutionUnit = nanoseconds;
+ using BptResolution =
+#if defined(BOOST_DATE_TIME_HAS_NANOSECONDS)
+ nanoseconds;
+#elif defined(BOOST_DATE_TIME_HAS_MICROSECONDS)
+ microseconds;
#else
- using BptResolutionUnit = microseconds;
+ milliseconds;
#endif
- constexpr auto unitsPerHour = duration_cast<BptResolutionUnit>(hours(1)).count();
+ constexpr auto unitsPerHour = duration_cast<BptResolution>(1_h).count();
- auto sinceEpoch = duration_cast<BptResolutionUnit>(timePoint - getUnixEpoch()).count();
- bpt::ptime ptime = epoch + bpt::time_duration(sinceEpoch / unitsPerHour, 0, 0, sinceEpoch % unitsPerHour);
+ auto sinceEpoch = duration_cast<BptResolution>(timePoint - getUnixEpoch()).count();
+ return epoch + bpt::time_duration(sinceEpoch / unitsPerHour, 0, 0, sinceEpoch % unitsPerHour);
+}
- return bpt::to_iso_string(ptime);
+std::string
+toIsoString(const system_clock::TimePoint& timePoint)
+{
+ return boost::posix_time::to_iso_string(convertToPosixTime(timePoint));
}
static system_clock::TimePoint
@@ -146,11 +153,11 @@
namespace bpt = boost::posix_time;
static bpt::ptime epoch(boost::gregorian::date(1970, 1, 1));
- // .total_seconds() has issue with large dates until Boost 1.66. See Issue #4478
- // from_time_t has issues with large dates on 32-bit platforms
- auto point = system_clock::time_point(seconds((ptime - epoch).ticks() / bpt::time_duration::ticks_per_second()));
- point += microseconds((ptime - epoch).total_microseconds() % 1000000);
- return point;
+ // .total_seconds() has an issue with large dates until Boost 1.66, see #4478.
+ // time_t overflows for large dates on 32-bit platforms (Y2038 problem).
+ auto sinceEpoch = ptime - epoch;
+ auto point = system_clock::TimePoint(seconds(sinceEpoch.ticks() / bpt::time_duration::ticks_per_second()));
+ return point + microseconds(sinceEpoch.total_microseconds() % 1000000);
}
system_clock::TimePoint
@@ -165,17 +172,13 @@
const std::locale& locale/* = std::locale("C")*/)
{
namespace bpt = boost::posix_time;
- bpt::ptime ptime = bpt::from_time_t(system_clock::to_time_t(timePoint));
- uint64_t micro = duration_cast<microseconds>(timePoint - getUnixEpoch()).count() % 1000000;
- ptime += bpt::microseconds(micro);
+ std::ostringstream os;
+ auto* facet = new bpt::time_facet(format.data());
+ os.imbue(std::locale(locale, facet));
+ os << convertToPosixTime(timePoint);
- bpt::time_facet* facet = new bpt::time_facet(format.c_str());
- std::ostringstream formattedTimePoint;
- formattedTimePoint.imbue(std::locale(locale, facet));
- formattedTimePoint << ptime;
-
- return formattedTimePoint.str();
+ return os.str();
}
system_clock::TimePoint
@@ -185,8 +188,8 @@
{
namespace bpt = boost::posix_time;
- bpt::time_input_facet* facet = new bpt::time_input_facet(format);
std::istringstream is(timePointStr);
+ auto* facet = new bpt::time_input_facet(format);
is.imbue(std::locale(locale, facet));
bpt::ptime ptime;
is >> ptime;