feat(time): use tm::tm_gmtoff if present (#1040)
This greatly simplifies time computations.
This commit is contained in:
parent
eb72e4c181
commit
25a349f7ae
@ -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
|
||||
|
||||
@ -42,6 +42,7 @@
|
||||
#include <shared_mutex>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
@ -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 <class... Args>
|
||||
struct void_impl {
|
||||
using type = void;
|
||||
};
|
||||
|
||||
template <class... Args>
|
||||
using void_t = typename void_impl<Args...>::type;
|
||||
|
||||
template <class T, class E = void>
|
||||
struct has_member_tm_gmtoff : std::false_type {};
|
||||
|
||||
template <class T>
|
||||
struct has_member_tm_gmtoff<T, void_t<decltype(&T::tm_gmtoff)>>
|
||||
: std::true_type {};
|
||||
|
||||
template <class T = std::tm>
|
||||
auto Breakdown(const std::chrono::system_clock::time_point& now)
|
||||
-> std::enable_if_t<!has_member_tm_gmtoff<T>::value,
|
||||
std::tuple<std::tm, std::time_t, std::chrono::hours>> {
|
||||
std::time_t timestamp = std::chrono::system_clock::to_time_t(now);
|
||||
if (FLAGS_log_utc_time) {
|
||||
gmtime_r(×tamp, &tm_);
|
||||
} else {
|
||||
localtime_r(×tamp, &tm_);
|
||||
}
|
||||
usecs_ = std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
now - std::chrono::system_clock::from_time_t(timestamp));
|
||||
CalcGmtOffset(timestamp);
|
||||
}
|
||||
std::tm tm_local;
|
||||
std::tm tm_utc;
|
||||
int isdst = 0;
|
||||
|
||||
void LogMessageTime::CalcGmtOffset(std::time_t t) {
|
||||
std::tm gmt_struct;
|
||||
int isDst = 0;
|
||||
if (FLAGS_log_utc_time) {
|
||||
localtime_r(&t, &gmt_struct);
|
||||
isDst = gmt_struct.tm_isdst;
|
||||
gmt_struct = tm_;
|
||||
gmtime_r(×tamp, &tm_local);
|
||||
localtime_r(×tamp, &tm_utc);
|
||||
isdst = tm_utc.tm_isdst;
|
||||
tm_utc = tm_local;
|
||||
} else {
|
||||
isDst = tm_.tm_isdst;
|
||||
gmtime_r(&t, &gmt_struct);
|
||||
localtime_r(×tamp, &tm_local);
|
||||
isdst = tm_local.tm_isdst;
|
||||
gmtime_r(×tamp, &tm_utc);
|
||||
}
|
||||
|
||||
time_t gmt_sec = mktime(&gmt_struct);
|
||||
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;
|
||||
gmtoffset_ = std::chrono::duration_cast<std::chrono::seconds>(
|
||||
timestamp_ - std::chrono::system_clock::from_time_t(gmt_sec) +
|
||||
(isDst ? 1h : 0h));
|
||||
const auto gmtoffset = std::chrono::duration_cast<std::chrono::hours>(
|
||||
now - std::chrono::system_clock::from_time_t(gmt_sec) +
|
||||
(isdst ? 1h : 0h));
|
||||
|
||||
return std::make_tuple(tm_local, timestamp, gmtoffset);
|
||||
}
|
||||
|
||||
template <class T = std::tm>
|
||||
auto Breakdown(const std::chrono::system_clock::time_point& now)
|
||||
-> std::enable_if_t<has_member_tm_gmtoff<T>::value,
|
||||
std::tuple<std::tm, std::time_t, std::chrono::hours>> {
|
||||
std::time_t timestamp = std::chrono::system_clock::to_time_t(now);
|
||||
T tm;
|
||||
|
||||
if (FLAGS_log_utc_time) {
|
||||
gmtime_r(×tamp, &tm);
|
||||
} else {
|
||||
localtime_r(×tamp, &tm);
|
||||
}
|
||||
|
||||
const auto gmtoffset = std::chrono::duration_cast<std::chrono::hours>(
|
||||
std::chrono::seconds{tm.tm_gmtoff});
|
||||
|
||||
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<std::chrono::microseconds>(
|
||||
now - std::chrono::system_clock::from_time_t(timestamp));
|
||||
}
|
||||
|
||||
} // namespace google
|
||||
|
||||
@ -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) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user