Fix daylight savings offset calculation bug

This commit changes the local timezone calculation to use tm.tm_gmtoff,
and falling back to calculating it manually from the output of strftime
when tm_gmtoff is not a member of struct tm.

This also fixes the tests so that they are no longer expected to fail.

Fixes #20.
pull/22/head
nirenjan 2020-06-06 17:48:17 -07:00
parent f5145de36b
commit af49ce6500
3 changed files with 42 additions and 6 deletions

View File

@ -61,6 +61,14 @@ AM_COND_IF([HAVE_DOXYGEN],
[AC_CONFIG_FILES([Doxyfile])], [AC_CONFIG_FILES([Doxyfile])],
[AC_MSG_WARN(["Doxygen not found; continuing without doxygen support"])]) [AC_MSG_WARN(["Doxygen not found; continuing without doxygen support"])])
# Check for the presence of tm_gmtoff in struct tm. If we have this, then we
# can use it to determine the true GMT offset
AC_CHECK_MEMBERS([struct tm.tm_gmtoff],,
[AC_MSG_WARN(["Cannot find tm_gmtoff in struct tm, using slower method"])],
[#define _GNU_SOURCE
#include <time.h>
])
# Configuration headers # Configuration headers
AC_CONFIG_HEADERS([config.h]) AC_CONFIG_HEADERS([config.h])

View File

@ -18,6 +18,33 @@
#include "x52_commands.h" #include "x52_commands.h"
#include "x52_common.h" #include "x52_common.h"
#if !HAVE_STRUCT_TM_TM_GMTOFF
/* Slow method to compute GMT offset */
static int _x52_compute_gmtoff(struct tm *timeval)
{
char buf[20];
size_t written;
int offset;
/* This function uses strftime to get the timezone as a string, then
* converts that back into an integer offset.
*/
written = strftime(buf, sizeof(buf), "%z", timeval);
if (written != 5) {
/* Expect %z to return 5 characters - e.g. +0530, -0700, +0000 */
return 0;
}
offset = 600 * (buf[1] - '0') + 60 * (buf[2] - '0') + 10 * (buf[3] - '0') + (buf[4] - '0');
if (buf[0] == '-') {
offset = -offset;
} else if (buf[0] != '+') {
offset = 0;
}
return offset;
}
#endif
int libx52_set_clock(libx52_device *x52, time_t time, int local) int libx52_set_clock(libx52_device *x52, time_t time, int local)
{ {
struct tm timeval; struct tm timeval;
@ -36,10 +63,14 @@ int libx52_set_clock(libx52_device *x52, time_t time, int local)
if (local) { if (local) {
ptr = localtime_r(&time, &timeval); ptr = localtime_r(&time, &timeval);
/* timezone from time.h presents the offset in seconds west of GMT. #if HAVE_STRUCT_TM_TM_GMTOFF
* Negate and divide by 60 to get the offset in minutes east of GMT. /* If valid, then timeval.tm_gmtoff contains the offset in seconds
* east of GMT. Divide by 60 to get the offset in minutes east of GMT.
*/ */
local_tz = (int)(-timezone / 60); local_tz = (int)(timeval.tm_gmtoff / 60);
#else
local_tz = _x52_compute_gmtoff(&timeval);
#endif
} else { } else {
ptr = gmtime_r(&time, &timeval); ptr = gmtime_r(&time, &timeval);
/* No offset from GMT */ /* No offset from GMT */

View File

@ -33,9 +33,6 @@ timezone_test()
# Pacific Daylight Time # Pacific Daylight Time
# Default offset for clocks 2 & 3 should be +420 minutes # Default offset for clocks 2 & 3 should be +420 minutes
off=420 off=420
# TODO: Remove the following line once #20 is fixed.
TEST_ID="$TEST_ID # TODO Fix issue #20"
else else
# Pacific Standard time # Pacific Standard time
# Default offset for clocks 2 & 3 should be +480 minutes # Default offset for clocks 2 & 3 should be +480 minutes