Skip to content

Commit

Permalink
feat(time): use tm::tm_gmtoff if present (#1040)
Browse files Browse the repository at this point in the history
This greatly simplifies time computations.
  • Loading branch information
sergiud authored Jan 6, 2024
1 parent eb72e4c commit 25a349f
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 30 deletions.
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

0 comments on commit 25a349f

Please sign in to comment.