From 39ae2e8ca4eca6be1c73a70bdd0c45258a527613 Mon Sep 17 00:00:00 2001 From: Julian Brost Date: Wed, 21 Aug 2024 12:31:44 +0200 Subject: [PATCH] Utility::FormatDateTime(): provide an overload for tm* This allows the function to be used both with a double timestamp or a pointer to a tm struct. With this, a similar implementation inside the tests can simply use our regular function. --- lib/base/utility.cpp | 46 +++++++++++++++++--------------- lib/base/utility.hpp | 3 ++- test/icinga-legacytimeperiod.cpp | 11 +------- 3 files changed, 28 insertions(+), 32 deletions(-) diff --git a/lib/base/utility.cpp b/lib/base/utility.cpp index 75b905fe1..338e4f77f 100644 --- a/lib/base/utility.cpp +++ b/lib/base/utility.cpp @@ -1051,8 +1051,31 @@ String Utility::FormatDuration(double duration) return NaturalJoin(tokens); } -String Utility::FormatDateTime(const char *format, double ts) +String Utility::FormatDateTime(const char* format, double ts) { + // Sub-second precision is removed, strftime() has no format specifiers for that anyway. + auto tempts = boost::numeric_cast(ts); + tm tmthen; + +#ifdef _MSC_VER + errno_t err = localtime_s(&tmthen, &tempts); + if (err) { + BOOST_THROW_EXCEPTION(posix_error() + << boost::errinfo_api_function("localtime_s") + << boost::errinfo_errno(err)); + } +#else /* _MSC_VER */ + if (!localtime_r(&tempts, &tmthen)) { + BOOST_THROW_EXCEPTION(posix_error() + << boost::errinfo_api_function("localtime_r") + << boost::errinfo_errno(errno)); + } +#endif /* _MSC_VER */ + + return FormatDateTime(format, &tmthen); +} + +String Utility::FormatDateTime(const char* format, const tm* t) { /* Known limitations of the implementation: Only works if the result is at most 127 bytes, otherwise returns an * empty string. An empty string is also returned in all other error cases as proper error handling for strftime() * is impossible. @@ -1074,25 +1097,6 @@ String Utility::FormatDateTime(const char *format, double ts) * the error was due to the buffer being too small. */ - // Sub-second precision is removed, strftime() has no format specifiers for that anyway. - auto tempts = boost::numeric_cast(ts); - tm tmthen; - -#ifdef _MSC_VER - errno_t err = localtime_s(&tmthen, &tempts); - if (err) { - BOOST_THROW_EXCEPTION(posix_error() - << boost::errinfo_api_function("localtime_s") - << boost::errinfo_errno(err)); - } -#else /* _MSC_VER */ - if (!localtime_r(&tempts, &tmthen)) { - BOOST_THROW_EXCEPTION(posix_error() - << boost::errinfo_api_function("localtime_r") - << boost::errinfo_errno(errno)); - } -#endif /* _MSC_VER */ - #ifdef _MSC_VER /* On Windows, the strftime() function family invokes an invalid parameter handler when the format string is * invalid (see the "Remarks" section in their documentation). std::put_time() shows the same behavior as it @@ -1120,7 +1124,7 @@ String Utility::FormatDateTime(const char *format, double ts) #endif /* _MSC_VER */ char buf[128]; - size_t n = strftime(buf, sizeof(buf), format, &tmthen); + size_t n = strftime(buf, sizeof(buf), format, t); // On error, n == 0 and an empty string is returned. return std::string(buf, n); } diff --git a/lib/base/utility.hpp b/lib/base/utility.hpp index 47b68d251..5132673ca 100644 --- a/lib/base/utility.hpp +++ b/lib/base/utility.hpp @@ -77,7 +77,8 @@ public: static String Join(const Array::Ptr& tokens, char separator, bool escapeSeparator = true); static String FormatDuration(double duration); - static String FormatDateTime(const char *format, double ts); + static String FormatDateTime(const char* format, double ts); + static String FormatDateTime(const char* format, const tm* t); static String FormatErrorNumber(int code); #ifndef _WIN32 diff --git a/test/icinga-legacytimeperiod.cpp b/test/icinga-legacytimeperiod.cpp index 900bb6578..8661b75f7 100644 --- a/test/icinga-legacytimeperiod.cpp +++ b/test/icinga-legacytimeperiod.cpp @@ -527,16 +527,7 @@ struct Segment std::string pretty_time(const tm& t) { -#if defined(__GNUC__) && __GNUC__ < 5 - // GCC did not implement std::put_time() until version 5 - char buf[128]; - size_t n = strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S %Z", &t); - return std::string(buf, n); -#else /* defined(__GNUC__) && __GNUC__ < 5 */ - std::ostringstream stream; - stream << std::put_time(&t, "%Y-%m-%d %H:%M:%S %Z"); - return stream.str(); -#endif /* defined(__GNUC__) && __GNUC__ < 5 */ + return Utility::FormatDateTime("%Y-%m-%d %H:%M:%S %Z", &t); } std::string pretty_time(time_t t)