diff --git a/include/common/standard.h b/include/common/standard.h index 9abdb0643..353d0b023 100644 --- a/include/common/standard.h +++ b/include/common/standard.h @@ -860,9 +860,6 @@ char *human_time(int t, short hz_div); extern const char *monthname[]; -/* numeric timezone (that is, the hour and minute offset from UTC) */ -char localtimezone[6]; - /* date2str_log: write a date in the format : * sprintf(str, "%02d/%s/%04d:%02d:%02d:%02d.%03d", * tm.tm_mday, monthname[tm.tm_mon], tm.tm_year+1900, @@ -873,6 +870,12 @@ char localtimezone[6]; */ char *date2str_log(char *dest, struct tm *tm, struct timeval *date, size_t size); +/* Return the GMT offset for a specific local time. + * The string returned has the same format as returned by strftime(... "%z", tm). + * Offsets are kept in an internal cache for better performances. + */ +const char *get_gmt_offset(struct tm *tm); + /* gmt2str_log: write a date in the format : * "%02d/%s/%04d:%02d:%02d:%02d +0000" without using snprintf * return a pointer to the last char written (\0) or diff --git a/src/haproxy.c b/src/haproxy.c index 4d38d2713..9842f3d3c 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -562,7 +562,6 @@ void init(int argc, char **argv) struct wordlist *wl; char *progname; char *change_dir = NULL; - struct tm curtime; struct proxy *px; chunk_init(&trash, malloc(global.tune.bufsize), global.tune.bufsize); @@ -588,15 +587,12 @@ void init(int argc, char **argv) global.rlimit_memmax_all = HAPROXY_MEMMAX; #endif + tzset(); tv_update_date(-1,-1); start_date = now; srandom(now_ms - getpid()); - /* Get the numeric timezone. */ - get_localtime(start_date.tv_sec, &curtime); - strftime(localtimezone, 6, "%z", &curtime); - init_log(); signal_init(); if (init_acl() != 0) diff --git a/src/log.c b/src/log.c index 3e25bc79d..ab383531e 100644 --- a/src/log.c +++ b/src/log.c @@ -970,6 +970,7 @@ static char *update_log_hdr_rfc5424(const time_t time) { static long tvsec; static char *dataptr = NULL; /* backup of last end of header, NULL first time */ + const char *gmt_offset; if (unlikely(time != tvsec || dataptr == NULL)) { /* this string is rebuild only once a second */ @@ -978,12 +979,13 @@ static char *update_log_hdr_rfc5424(const time_t time) tvsec = time; get_localtime(tvsec, &tm); + gmt_offset = get_gmt_offset(&tm); hdr_len = snprintf(logheader_rfc5424, global.max_syslog_len, "<<<<>1 %4d-%02d-%02dT%02d:%02d:%02d%.3s:%.2s %s ", tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, - localtimezone, localtimezone+3, + gmt_offset, gmt_offset+3, global.log_send_hostname ? global.log_send_hostname : hostname); /* WARNING: depending upon implementations, snprintf may return * either -1 or the number of bytes that would be needed to store diff --git a/src/standard.c b/src/standard.c index 40727b0dd..e08795fd1 100644 --- a/src/standard.c +++ b/src/standard.c @@ -2552,6 +2552,35 @@ char *date2str_log(char *dst, struct tm *tm, struct timeval *date, size_t size) return dst; } +/* Return the GMT offset for a specific local time. + * The string returned has the same format as returned by strftime(... "%z", tm). + * Offsets are kept in an internal cache for better performances. + */ +const char *get_gmt_offset(struct tm *tm) +{ + /* Cache offsets from GMT (depending on whether DST is active or not) */ + static char gmt_offsets[2][5+1] = { "", "" }; + + int old_isdst = tm->tm_isdst; + char *gmt_offset; + + /* Pretend DST not active if its status is unknown, or strftime() will return an empty string for "%z" */ + if (tm->tm_isdst < 0) { + tm->tm_isdst = 0; + } + + /* Fetch the offset and initialize it if needed */ + gmt_offset = gmt_offsets[tm->tm_isdst & 0x01]; + if (unlikely(!*gmt_offset)) { + strftime(gmt_offset, 5+1, "%z", tm); + } + + /* Restore previous DST flag */ + tm->tm_isdst = old_isdst; + + return gmt_offset; +} + /* gmt2str_log: write a date in the format : * "%02d/%s/%04d:%02d:%02d:%02d +0000" without using snprintf * return a pointer to the last char written (\0) or @@ -2592,9 +2621,12 @@ char *gmt2str_log(char *dst, struct tm *tm, size_t size) */ char *localdate2str_log(char *dst, struct tm *tm, size_t size) { + const char *gmt_offset; if (size < 27) /* the size is fixed: 26 chars + \0 */ return NULL; + gmt_offset = get_gmt_offset(tm); + dst = utoa_pad((unsigned int)tm->tm_mday, dst, 3); // day *dst++ = '/'; memcpy(dst, monthname[tm->tm_mon], 3); // month @@ -2608,7 +2640,7 @@ char *localdate2str_log(char *dst, struct tm *tm, size_t size) *dst++ = ':'; dst = utoa_pad((unsigned int)tm->tm_sec, dst, 3); // secondes *dst++ = ' '; - memcpy(dst, localtimezone, 5); // timezone + memcpy(dst, gmt_offset, 5); // Offset from local time to GMT dst += 5; *dst = '\0';