Re: [PATCH 10/10] timegm: add portable implementation (Solaris support)

Subject: Re: [PATCH 10/10] timegm: add portable implementation (Solaris support)

Date: Mon, 05 Nov 2012 14:09:33 +0200

To: Blake Jones, Jani Nikula

Cc: notmuch@notmuchmail.org

From: Tomi Ollila


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, &ltm);

    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;
}

Thread: