From: Blake Jones Date: Mon, 5 Nov 2012 15:47:22 +0000 (+1600) Subject: Re: [PATCH 10/10] timegm: add portable implementation (Solaris support) X-Git-Url: http://git.tremily.us/gitweb.cgi?a=commitdiff_plain;h=a481e1f706f2bb6ae1db2856996836921ed77b2e;p=notmuch-archives.git Re: [PATCH 10/10] timegm: add portable implementation (Solaris support) --- diff --git a/83/ac1bf1602c588fb077f351c9510b37dd6a87d2 b/83/ac1bf1602c588fb077f351c9510b37dd6a87d2 new file mode 100644 index 000000000..0b5cd5732 --- /dev/null +++ b/83/ac1bf1602c588fb077f351c9510b37dd6a87d2 @@ -0,0 +1,210 @@ +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--