diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b7d1288e0..6ef1ce270f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -213,6 +213,12 @@ check_function_exists(fts_open HAVE_FTS_OPEN) check_function_exists(strsep HAVE_STRSEP) check_function_exists(strptime HAVE_STRPTIME) +# struct tm.tm_gmtoff is a BSD/GNU extension (present on glibc, musl, the BSDs +# and macOS, absent on the MSVC runtime). When available it carries the UTC +# offset including daylight saving time, unlike the global timezone variable. +include(CheckStructHasMember) +check_struct_has_member("struct tm" tm_gmtoff time.h HAVE_STRUCT_TM_TM_GMTOFF) + check_include_file(syslog.h HAVE_SYSLOG_H) check_include_file(stdio_ext.h HAVE_STDIO_EXT_H) check_include_file(shadow.h HAVE_SHADOW_H) diff --git a/config.h.in b/config.h.in index 305bd231cf..7479e82299 100644 --- a/config.h.in +++ b/config.h.in @@ -85,6 +85,7 @@ #cmakedefine HAVE_STRSEP #cmakedefine HAVE_FLOCK #cmakedefine HAVE_STRPTIME +#cmakedefine HAVE_STRUCT_TM_TM_GMTOFF #cmakedefine OPENSCAP_PROBE_INDEPENDENT_ENVIRONMENTVARIABLE #cmakedefine OPENSCAP_PROBE_INDEPENDENT_ENVIRONMENTVARIABLE58 diff --git a/src/XCCDF/result.c b/src/XCCDF/result.c index fab6bc512c..1aedd1a3fa 100644 --- a/src/XCCDF/result.c +++ b/src/XCCDF/result.c @@ -1842,7 +1842,10 @@ static inline const char *_get_timestamp(void) if (!lt) return NULL; -#if defined(OS_FREEBSD) +#if defined(HAVE_STRUCT_TM_TM_GMTOFF) + /* tm_gmtoff is the offset east of UTC in seconds and already accounts + * for daylight saving time, so it reflects the actual offset in effect + * at the represented local time. */ tz_diff = lt->tm_gmtoff; if (tz_diff < 0) { @@ -1851,20 +1854,21 @@ static inline const char *_get_timestamp(void) } else { tz_sign = '+'; } - - /* glibc's timezone offset does not account for daylight savings time. - * So we match that behavior here by adding 3600 seconds - */ - if (lt->tm_isdst) - tz_diff += 3600; #else - /* timezone is a global variable set by localtime(3) */ - if (timezone <= 0) { + /* Fallback for platforms without tm_gmtoff (e.g. the MSVC runtime). + * timezone is a global variable set by localtime(3) holding the number + * of seconds west of UTC of standard time. Daylight saving time moves + * the local time one hour east, i.e. closer to UTC, so subtract 3600 + * seconds from the westward offset when DST is in effect. */ + long std_diff = timezone; + if (lt->tm_isdst > 0) + std_diff -= 3600; + if (std_diff <= 0) { tz_sign = '+'; - tz_diff = -timezone; + tz_diff = -std_diff; } else { tz_sign = '-'; - tz_diff = timezone; + tz_diff = std_diff; } #endif tz_diff /= 60;