make date parsing portable, take 2

the global timezone variable is glibc-specific.
so use timegm() instead of mktime() for the conversion.
as that is specific to the BSDs and glibc, provide a fallback.
amends 62a6099.
This commit is contained in:
Oswald Buddenhagen 2014-01-02 20:50:42 +01:00
parent 6d2fd370a6
commit aee0fa3b68
4 changed files with 73 additions and 3 deletions

View File

@ -29,7 +29,7 @@ if test "x$ob_cv_strftime_z" = x"no"; then
fi fi
AC_CHECK_HEADERS(sys/poll.h sys/select.h) AC_CHECK_HEADERS(sys/poll.h sys/select.h)
AC_CHECK_FUNCS(vasprintf memrchr) AC_CHECK_FUNCS(vasprintf memrchr timegm)
AC_CHECK_LIB(socket, socket, [SOCK_LIBS="-lsocket"]) AC_CHECK_LIB(socket, socket, [SOCK_LIBS="-lsocket"])
AC_CHECK_LIB(nsl, inet_ntoa, [SOCK_LIBS="$SOCK_LIBS -lnsl"]) AC_CHECK_LIB(nsl, inet_ntoa, [SOCK_LIBS="$SOCK_LIBS -lnsl"])

View File

@ -94,6 +94,11 @@ void free_string_list( string_list_t *list );
void *memrchr( const void *s, int c, size_t n ); void *memrchr( const void *s, int c, size_t n );
#endif #endif
#ifndef HAVE_TIMEGM
# include <time.h>
time_t timegm( struct tm *tm );
#endif
void *nfmalloc( size_t sz ); void *nfmalloc( size_t sz );
void *nfcalloc( size_t sz ); void *nfcalloc( size_t sz );
void *nfrealloc( void *mem, size_t sz ); void *nfrealloc( void *mem, size_t sz );

View File

@ -835,11 +835,11 @@ parse_date( const char *str )
memset( &datetime, 0, sizeof(datetime) ); memset( &datetime, 0, sizeof(datetime) );
if (!(end = strptime( str, "%d-%b-%Y %H:%M:%S ", &datetime ))) if (!(end = strptime( str, "%d-%b-%Y %H:%M:%S ", &datetime )))
return -1; return -1;
if ((date = mktime( &datetime )) == -1) if ((date = timegm( &datetime )) == -1)
return -1; return -1;
if (sscanf( end, "%3d%2d", &hours, &mins ) != 2) if (sscanf( end, "%3d%2d", &hours, &mins ) != 2)
return -1; return -1;
return date - (hours * 60 + mins) * 60 - timezone; return date - (hours * 60 + mins) * 60;
} }
static int static int

View File

@ -203,6 +203,71 @@ memrchr( const void *s, int c, size_t n )
} }
#endif #endif
#ifndef HAVE_TIMEGM
/*
Converts struct tm to time_t, assuming the data in tm is UTC rather
than local timezone.
mktime is similar but assumes struct tm, also known as the
"broken-down" form of time, is in local time zone. timegm
uses mktime to make the conversion understanding that an offset
will be introduced by the local time assumption.
mktime_from_utc then measures the introduced offset by applying
gmtime to the initial result and applying mktime to the resulting
"broken-down" form. The difference between the two mktime results
is the measured offset which is then subtracted from the initial
mktime result to yield a calendar time which is the value returned.
tm_isdst in struct tm is set to 0 to force mktime to introduce a
consistent offset (the non DST offset) since tm and tm+o might be
on opposite sides of a DST change.
Some implementations of mktime return -1 for the nonexistent
localtime hour at the beginning of DST. In this event, use
mktime(tm - 1hr) + 3600.
Schematically
mktime(tm) --> t+o
gmtime(t+o) --> tm+o
mktime(tm+o) --> t+2o
t+o - (t+2o - t+o) = t
Contributed by Roger Beeman <beeman@cisco.com>, with the help of
Mark Baushke <mdb@cisco.com> and the rest of the Gurus at CISCO.
Further improved by Roger with assistance from Edward J. Sabol
based on input by Jamie Zawinski.
*/
static time_t
my_mktime( struct tm *t )
{
time_t tl = mktime( t );
if (tl == -1) {
t->tm_hour--;
tl = mktime( t );
if (tl != -1)
tl += 3600;
}
return tl;
}
time_t
timegm( struct tm *t )
{
time_t tl, tb;
struct tm *tg;
if ((tl = my_mktime( t )) == -1)
return tl;
tg = gmtime( &tl );
tg->tm_isdst = 0;
if ((tb = my_mktime( tg )) == -1)
return tb;
return tl - (tb - tl);
}
#endif
void void
oob( void ) oob( void )
{ {