Description
spdlog uses the function utc_minutes_offset
in the z_formatter
to format the '%z' part of a format string (UTC-offset) when logging time. The function has three implementations, one of which is chosen at compile time via marcro defines (Windows, SunOS/Solaris, default).
The SunOS/Solaris implementation, however, returns the difference of the given tm
and gmtime(now)
instead, which can be an arbitrary value. If a unit test for a logging subsystem logs a message at a defined point in time to get identical output in every test run, for instance, the difference could amount to years.
The function returns the correct value only in case tm
is at most the fractional part of a second before localtime(now)
or roughly a minute after, otherwise the truncation in the return statement will produce wrong values.
spdlog/include/spdlog/details/os-inl.h
Line 298 in 3335c38
A better solution could look like this:
const auto now = std::time(nullptr);
const auto local_now = localtime(now);
auto offset_seconds = helper::calculate_gmt_offset(local_now, gmtime(now));
if (tm.tm_isdst >= 0 && local_now.tm_isdst >=0) {
offset_seconds += (tm.tm_isdst > 0) ? 3600 : 0;
offset_seconds -= (local_now.tm_isdst > 0) ? 3600 : 0;
}
This assumes that tm
has the same timezone as the local time, which seems like the only reasonable assumption on platforms missing the tm_gmtoff
-field.
It also assumes that daylight savings time advances the clock by 1h, which is not universally true, e.g. in parts of Australia.