Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(time): use tm::tm_gmtoff if present #1040

Merged
merged 1 commit into from
Jan 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions src/glog/logging.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
88 changes: 66 additions & 22 deletions src/logging.cc
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include <shared_mutex>
#include <string>
#include <thread>
#include <tuple>
#include <type_traits>
#include <utility>

Expand Down Expand Up @@ -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);
std::tm tm_local;
std::tm tm_utc;
int isdst = 0;

if (FLAGS_log_utc_time) {
gmtime_r(&timestamp, &tm_);
gmtime_r(&timestamp, &tm_local);
localtime_r(&timestamp, &tm_utc);
isdst = tm_utc.tm_isdst;
tm_utc = tm_local;
} else {
localtime_r(&timestamp, &tm_);
localtime_r(&timestamp, &tm_local);
isdst = tm_local.tm_isdst;
gmtime_r(&timestamp, &tm_utc);
}
usecs_ = std::chrono::duration_cast<std::chrono::microseconds>(
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<std::chrono::hours>(
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 <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) {
localtime_r(&t, &gmt_struct);
isDst = gmt_struct.tm_isdst;
gmt_struct = tm_;
gmtime_r(&timestamp, &tm);
} else {
isDst = tm_.tm_isdst;
gmtime_r(&t, &gmt_struct);
localtime_r(&timestamp, &tm);
}

time_t gmt_sec = mktime(&gmt_struct);
const auto gmtoffset = std::chrono::duration_cast<std::chrono::hours>(
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<std::chrono::seconds>(
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<std::chrono::microseconds>(
now - std::chrono::system_clock::from_time_t(timestamp));
}

} // namespace google
8 changes: 4 additions & 4 deletions src/logging_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down