Return-Path: X-Original-To: notmuch@notmuchmail.org Delivered-To: notmuch@notmuchmail.org Received: from localhost (localhost [127.0.0.1]) by olra.theworths.org (Postfix) with ESMTP id 4C880431FB6 for ; Mon, 5 Nov 2012 07:47:31 -0800 (PST) X-Virus-Scanned: Debian amavisd-new at olra.theworths.org X-Spam-Flag: NO X-Spam-Score: 0 X-Spam-Level: X-Spam-Status: No, score=0 tagged_above=-999 required=5 tests=[none] autolearn=disabled Received: from olra.theworths.org ([127.0.0.1]) by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 0yx8uOLeaIz7 for ; Mon, 5 Nov 2012 07:47:30 -0800 (PST) Received: from foo.net (70-36-235-136.dsl.static.sonic.net [70.36.235.136]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by olra.theworths.org (Postfix) with ESMTPS id 70D62431FAE for ; Mon, 5 Nov 2012 07:47:30 -0800 (PST) Received: from foo.net (localhost [127.0.0.1]) by foo.net (8.14.5+Sun/8.14.5) with ESMTP id qA5FlM1X002593; Mon, 5 Nov 2012 07:47:22 -0800 (PST) To: Tomi Ollila Subject: Re: [PATCH 10/10] timegm: add portable implementation (Solaris support) In-Reply-To: Your message of "Mon, 05 Nov 2012 14:09:33 +0200." MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----- =_aaaaaaaaaa0" Content-ID: <2591.1352130440.0@foo.net> Date: Mon, 05 Nov 2012 07:47:22 -0800 Message-ID: <2592.1352130442@foo.net> From: Blake Jones X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-2.0.2 (foo.net [127.0.0.1]); Mon, 05 Nov 2012 07:47:22 -0800 (PST) Cc: notmuch@notmuchmail.org X-BeenThere: notmuch@notmuchmail.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: "Use and development of the notmuch mail system." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 05 Nov 2012 15:47:31 -0000 ------- =_aaaaaaaaaa0 Content-Type: text/plain; charset="us-ascii" Content-ID: <2591.1352130440.1@foo.net> > 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) Of these two, I would probably lean slightly toward the latter, in that it relies more on libc for the time zone handling logic. But in general, this seems to me like a case where an explicit implementation like mine is less prone to failure, because it doesn't need to worry about time zones at all. The other approaches rely on letting libc do all the hard work of time zone manipulation, and then reading the tea leaves to find a way to undo it. I would guess that if some change in the time standards is going to break one of these implementations, it's going to be some new time zone specification, not a change in the number of days in a month. :) For what it's worth, I used the attached program to test my implementation, and it passed. Blake ------- =_aaaaaaaaaa0 Content-Type: text/plain; charset="us-ascii" Content-ID: <2591.1352130440.2@foo.net> #include static int leapyear(int year) { return ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0)); } /* * This is a simple implementation of timegm() which does what is needed * by parse-time-string.c -- just turns the "struct tm" into a GMT time_t. * It does not normalize any of the fields of the "struct tm", nor does * it set tm_wday or tm_yday. */ static time_t timegm(struct tm *tm) { int monthlen[2][12] = { { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, }; int year, month, days; days = 365 * (tm->tm_year - 70); for (year = 70; year < tm->tm_year; year++) { if (leapyear(1900 + year)) { days++; } } for (month = 0; month < tm->tm_mon; month++) { days += monthlen[leapyear(1900 + year)][month]; } days += tm->tm_mday - 1; return ((((days * 24) + tm->tm_hour) * 60 + tm->tm_min) * 60 + tm->tm_sec); } #include #include #include void tm_test(int niter) { const int monthlen[2][12] = { { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, }; int i; struct tm tm, *tmp; time_t t; for (i = 0; i < niter; i++) { tm.tm_year = (lrand48() % 67) + 70; tm.tm_mon = lrand48() % 12; do { t = (lrand48() % 31) + 1; } while (t > monthlen[leapyear(1900 + tm.tm_year)][tm.tm_mon]); tm.tm_mday = t; tm.tm_hour = lrand48() % 24; tm.tm_min = lrand48() % 60; tm.tm_sec = lrand48() % 60; t = timegm(&tm); tmp = gmtime(&t); if (tmp->tm_sec != tm.tm_sec || tmp->tm_min != tm.tm_min || tmp->tm_hour != tm.tm_hour || tmp->tm_mday != tm.tm_mday || tmp->tm_mon != tm.tm_mon || tmp->tm_year != tm.tm_year) { printf("%4d-%02d-%02d %02d:%02d:%02d -> " "%4d-%02d-%02d %02d:%02d:%02d\n", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec); } } } void time_test(int niter) { int i; time_t st, et; struct tm *tmp; for (i = 0; i < niter; i++) { st = (time_t)lrand48(); tmp = gmtime(&st); et = timegm(tmp); if (st != et) { printf("%d -> %d (%4d-%02d-%02d %02d:%02d:%02d)\n", st, et, tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec); } } } int main(void) { const int niter = 10000000; srand48(getpid()); tm_test(niter); time_test(niter); return (0); } ------- =_aaaaaaaaaa0--