From 25a349f7aed01d1bd8f3626e961e3b350b6aa6fd Mon Sep 17 00:00:00 2001 From: Sergiu Deitsch Date: Sat, 6 Jan 2024 02:56:23 +0100 Subject: [PATCH] feat(time): use tm::tm_gmtoff if present (#1040) This greatly simplifies time computations. --- src/glog/logging.h | 4 -- src/logging.cc | 88 ++++++++++++++++++++++++++++++----------- src/logging_unittest.cc | 8 ++-- 3 files changed, 70 insertions(+), 30 deletions(-) diff --git a/src/glog/logging.h b/src/glog/logging.h index 17c99c116..757824315 100644 --- a/src/glog/logging.h +++ b/src/glog/logging.h @@ -108,10 +108,6 @@ struct GLOG_EXPORT LogMessageTime { const std::tm& tm() const noexcept { return tm_; } private: - void init(const std::tm& t, std::time_t timestamp, - std::chrono::system_clock::time_point now); - void CalcGmtOffset(std::time_t t); - std::tm tm_{}; // Time of creation of LogMessage std::chrono::system_clock::time_point timestamp_; // Time of creation of LogMessage in seconds diff --git a/src/logging.cc b/src/logging.cc index 2325faad1..1fe0457c3 100644 --- a/src/logging.cc +++ b/src/logging.cc @@ -42,6 +42,7 @@ #include #include #include +#include #include #include @@ -2679,39 +2680,82 @@ void DisableLogCleaner() { log_cleaner.Disable(); } LogMessageTime::LogMessageTime() = default; -LogMessageTime::LogMessageTime(std::chrono::system_clock::time_point now) - : timestamp_{now} { +namespace { + +template +struct void_impl { + using type = void; +}; + +template +using void_t = typename void_impl::type; + +template +struct has_member_tm_gmtoff : std::false_type {}; + +template +struct has_member_tm_gmtoff> + : std::true_type {}; + +template +auto Breakdown(const std::chrono::system_clock::time_point& now) + -> std::enable_if_t::value, + std::tuple> { std::time_t timestamp = std::chrono::system_clock::to_time_t(now); + std::tm tm_local; + std::tm tm_utc; + int isdst = 0; + if (FLAGS_log_utc_time) { - gmtime_r(×tamp, &tm_); + gmtime_r(×tamp, &tm_local); + localtime_r(×tamp, &tm_utc); + isdst = tm_utc.tm_isdst; + tm_utc = tm_local; } else { - localtime_r(×tamp, &tm_); + localtime_r(×tamp, &tm_local); + isdst = tm_local.tm_isdst; + gmtime_r(×tamp, &tm_utc); } - usecs_ = std::chrono::duration_cast( - now - std::chrono::system_clock::from_time_t(timestamp)); - CalcGmtOffset(timestamp); + + std::time_t gmt_sec = std::mktime(&tm_utc); + + // If the Daylight Saving Time(isDst) is active subtract an hour from the + // current timestamp. + using namespace std::chrono_literals; + const auto gmtoffset = std::chrono::duration_cast( + now - std::chrono::system_clock::from_time_t(gmt_sec) + + (isdst ? 1h : 0h)); + + return std::make_tuple(tm_local, timestamp, gmtoffset); } -void LogMessageTime::CalcGmtOffset(std::time_t t) { - std::tm gmt_struct; - int isDst = 0; +template +auto Breakdown(const std::chrono::system_clock::time_point& now) + -> std::enable_if_t::value, + std::tuple> { + std::time_t timestamp = std::chrono::system_clock::to_time_t(now); + T tm; + if (FLAGS_log_utc_time) { - localtime_r(&t, &gmt_struct); - isDst = gmt_struct.tm_isdst; - gmt_struct = tm_; + gmtime_r(×tamp, &tm); } else { - isDst = tm_.tm_isdst; - gmtime_r(&t, &gmt_struct); + localtime_r(×tamp, &tm); } - time_t gmt_sec = mktime(&gmt_struct); + const auto gmtoffset = std::chrono::duration_cast( + std::chrono::seconds{tm.tm_gmtoff}); - // If the Daylight Saving Time(isDst) is active subtract an hour from the - // current timestamp. - using namespace std::chrono_literals; - gmtoffset_ = std::chrono::duration_cast( - timestamp_ - std::chrono::system_clock::from_time_t(gmt_sec) + - (isDst ? 1h : 0h)); + return std::make_tuple(tm, timestamp, gmtoffset); +} + +} // namespace + +LogMessageTime::LogMessageTime(std::chrono::system_clock::time_point now) + : timestamp_{now} { + std::time_t timestamp; + std::tie(tm_, timestamp, gmtoffset_) = Breakdown(now); + usecs_ = std::chrono::duration_cast( + now - std::chrono::system_clock::from_time_t(timestamp)); } } // namespace google diff --git a/src/logging_unittest.cc b/src/logging_unittest.cc index 8b3c88681..74d6f4110 100644 --- a/src/logging_unittest.cc +++ b/src/logging_unittest.cc @@ -1537,12 +1537,12 @@ TEST(LogMsgTime, gmtoff) { * */ google::LogMessage log_obj(__FILE__, __LINE__); - std::chrono::seconds nGmtOff = log_obj.time().gmtoffset(); + std::chrono::seconds gmtoff = log_obj.time().gmtoffset(); // GMT offset ranges from UTC-12:00 to UTC+14:00 using namespace std::chrono_literals; - const std::chrono::hours utc_min_offset = -12h; - const std::chrono::hours utc_max_offset = 14h; - EXPECT_TRUE((nGmtOff >= utc_min_offset) && (nGmtOff <= utc_max_offset)); + constexpr std::chrono::hours utc_min_offset = -12h; + constexpr std::chrono::hours utc_max_offset = +14h; + EXPECT_TRUE((gmtoff >= utc_min_offset) && (gmtoff <= utc_max_offset)); } TEST(EmailLogging, ValidAddress) {