On Sun, Nov 04 2012, Blake Jones wrote: > Hi Jani, > >> I'd prefer to use timegm() where available, and the suggested >> alternative [1] elsewhere. >> >> [1] http://www.kernel.org/doc/man-pages/online/pages/man3/timegm.3.html > > I considered this alternative, but decided against it because it's > completely MT-unsafe. I don't know whether libnotmuch itself is > MT-safe, but a process which called this routine in one thread would > temporarily throw off any timezone-related work that any other threads > were doing, even if they weren't using libnotmuch. Yet another idea for an alternative. Compile by entering 'sh xtimegm.c' and then run ./xtimegm Simple cases seems to work. Dst change may (or then may not) give one hour difference to the expected. The test "coverage" could be easily expanded to that ;) Hmm, I also found this: http://lists.gnu.org/archive/html/bug-gnulib/2003-09/msg00004.html which does 2 mktime's and one gmtime_r (without allocating tg!)... Pick any of these 3 -- or something different (e.g. less NIH if there is) > Blake Tomi
#if 0 /* -*- mode: c; c-file-style: "stroustrup"; tab-width: 8; -*- set -eu; trg=`basename "$0" .c`; rm -f "$trg" WARN="-Wall -Wno-long-long -Wstrict-prototypes -pedantic" WARN="$WARN -Wcast-align -Wpointer-arith " # -Wfloat-equal #-Werror WARN="$WARN -W -Wwrite-strings -Wcast-qual -Wshadow" # -Wconversion case ${1-} in '') set x -O2; shift; esac #case ${1-} in '') set x -ggdb; shift; esac set -x; exec ${CC:-gcc} -std=c99 $WARN "$@" -o "$trg" "$0" exit $? */ #endif /* * $ xtimegm.c $ * * Author: Tomi Ollila -- too ät iki piste fi * * Created: Mon 05 Nov 2012 07:54:35 EET too * Last modified: Mon 05 Nov 2012 08:27:52 EET too * * Public domain. */ #define _POSIX_SOURCE #include <time.h> time_t xtimegm(struct tm * atm) { struct tm ltm; time_t t = mktime(atm); int sd; int dd; (void)gmtime_r(&t, <m); sd = (atm->tm_hour - ltm.tm_hour) * 3600 + (atm->tm_min - ltm.tm_min) * 60 + (atm->tm_sec - ltm.tm_sec); dd = (atm->tm_mday - ltm.tm_mday); if (dd == 0) ; else if (dd == -1) sd -= 86400; /* e.g. 3, 2 */ else if (dd == 1) sd += 86400; /* e.g. 2, 3 */ else if (dd > 1) sd -= 86400; /* e.g. 1, 31 */ else /* dd < 1 */ sd += 86400; /* e.g. 31, 1 */ printf("sd: %d\n", sd); // test line. return t + sd; } #include <stdio.h> void test(int hour, int mday) { struct tm mtm; time_t t; struct tm * otm; mtm.tm_sec = 0; mtm.tm_min = 0; mtm.tm_hour = hour; mtm.tm_mday = mday; mtm.tm_mon = 11; mtm.tm_year = 100; mtm.tm_isdst = -1; t = xtimegm(&mtm); otm = gmtime(&t); printf("%2d %02d:%02d:%02d\n", otm->tm_mday, otm->tm_hour, otm->tm_min, otm->tm_sec); } void tests(const char * tz) { printf("TZ: %s\n", tz); setenv("TZ", tz, 1); tzset(); test(23, 30); test(23, 31); test(23, 1); test(23, 2); printf("--\n"); test(1, 30); test(1, 31); test(1, 1); test(1, 2); } int main(int argc, char * argv[]) { // ls /usr/share/zoneinfo... tests("EET"); tests("MST"); tests("HST"); tests("NZ"); return 0; }