Be sure to direct replies to Guido, who's not on the time zone mailing list. --ado -----Original Message----- From: Guido Flohr [SMTP:gufl0000@stud.uni-sb.de] Sent: Monday, April 26, 1999 9:46 PM To: arthur_david_olson@nih.gov Subject: POSIX-TZ without rules Hello! I'm the current maintainer of the MiNTLib. The MiNTLib is the standard libc for MiNT and MiNT is a free Unix-clone for Atari computers. I've implemented parts of the tzcode and tzdata packages (version 1998c) in the MiNTLib. This went mostly without problems. Two problems arised: First, for testing purposes I set the envariable TZ to "CET-1CEST-2", i. e. a valid POSIX-style string but without explicit rules. I also uninstalled the database for that test. Under these circumstances tzparse() in localtime.c will return an error because it fails to open a default rules file. From what I remember I would say that POSIX demands that the US rules should be applied instead. Anyway, "CET-1CEST-2" is perfectly POSIX-compliant and the library should not return an error then. The GNU libc handles this case by assuming an implicit rule of "M4.1.0,M10.5.0" (commented as "US Federal Law"). My solution is somewhat different: I generated a header "new_york.h" with the disassembled contents of /usr/share/zoneinfo/posix/America/New_York. Now, not giving rules with no time zone database installed has the same effect as linking posixrules to America/New_York (as recommended in the Makefile of tzcode). The second problem: In zic.c, the analysis of the return value of system("yearistype ...") assumes a certain structure of that return value. I think it would be more portable to use the macros from sys/wait.h instead (although this would probably require an additional -D option to cc that determines whether to use POSIX- or BSD-style macros). May sound pedantic, but here's the story: I have happened to introduce a bug in the waitpid() function of the MiNTLib; the upper two bytes of the status pointer weren't zeroed out but contained some garbage. This affected system() because it calls waitpid. The error message from zic was: wild result 27525120 ... australasia line 75, command was "./yearistype 1990 even" Well, I could figure out what happened, but an average user would have had problems, because typing the command literally into the shell simply returned 0. If I understand the sources correctly, the more common error that the yearistype command is not found (e. g. running "zic -y yearistype ..." without "." in $PATH) would also produce quite confusing error messages (but at least the shell would also complain because you don't redirect stderr to /dev/null). Another argument: The specification for system() explicitely demands to use the wait macros to analyse the return value. These macros would have worked in the above described case. From this point of view the garbage in the upper 2 bytes is not even a bug. Apart from that: Thanks for all the work you must have invested into the time zone database! Everything works perfectly fine here. Ciao Guido -- http://stud.uni-sb.de/~gufl0000 mailto:gufl0000@stud.uni-sb.de
[This is a slightly revised version of a message that I sent to the tz mailing list on April 29, when the mailing list wasn't working.] From: Guido Flohr [SMTP:gufl0000@stud.uni-sb.de] Sent: Monday, April 26, 1999 9:46 PM for testing purposes I set the envariable TZ to "CET-1CEST-2", i. e. a valid POSIX-style string but without explicit rules. I also uninstalled the database for that test. Under these circumstances tzparse() in localtime.c will return an error because it fails to open a default rules file. From what I remember I would say that POSIX demands that the US rules should be applied instead. POSIX.1 is not US-centric here; it says that the behavior in this case is implementation-defined. The rationale (POSIX 1003.1-1996 section B.8.1.1 page 493 lines 5609-5612) says ``An implementation may provide those rules [i.e. the DST rules not explicitly specified by the user] in any way it sees fit, as long as the constraints implied by the TZ string as provided by the user are met. Specifically, the implementation may use the string as an index into a table, which may reside either on disk or in memory.'' So the implementation is allowed to do the right thing with "CET-1CEST-2". Anyway, "CET-1CEST-2" is perfectly POSIX-compliant and the library should not return an error then. Yes. My reading of POSIX.1 is that the implementation is allowed to guess the DST rules, but it shouldn't ignore this TZ string entirely. The GNU libc handles this case by assuming an implicit rule of "M4.1.0,M10.5.0" (commented as "US Federal Law"). My solution is somewhat different: I generated a header "new_york.h" Both solutions are suboptimal. The first mishandles old dates; the second assumes the New York City DST rules, whereas it'd be better to assume only the US rules. But clearly something should be done to the tz code to fix the problem, and either solution is acceptable. Going to your other point: In zic.c, the analysis of the return value of system("yearistype ...") assumes a certain structure of that return value. I see how to fix this bug; here's a patch. 1999-04-29 Paul Eggert <eggert@twinsun.com> * zic.c (yearistype): Check exit status portably. * private.h (HAVE_SYS_WAIT_H, WIFEXITED, WEXITSTATUS): New macros. * Makefile: Comment about HAVE_SYS_WAIT_H. =================================================================== RCS file: RCS/private.h,v retrieving revision 1998.7 retrieving revision 1998.7.1.1 diff -u -r1998.7 -r1998.7.1.1 --- private.h 1998/09/24 14:46:42 1998.7 +++ private.h 1999/04/29 23:34:11 1998.7.1.1 @@ -50,6 +50,10 @@ #define HAVE_SYMLINK 1 #endif /* !defined HAVE_SYMLINK */ +#ifndef HAVE_SYS_WAIT_H +#define HAVE_SYS_WAIT_H 1 +#endif /* !defined HAVE_SYS_WAIT_H */ + #ifndef HAVE_UNISTD_H #define HAVE_UNISTD_H 1 #endif /* !defined HAVE_UNISTD_H */ @@ -78,6 +82,17 @@ #include "libintl.h" #endif /* HAVE_GETTEXT - 0 */ +#if HAVE_SYS_WAIT_H - 0 +#include <sys/wait.h> /* for WIFEXITED and WEXITSTATUS */ +#endif /* HAVE_SYS_WAIT_H - 0 */ + +#ifndef WIFEXITED +#define WIFEXITED(status) (((status) & 0xff) == 0) +#endif /* !defined WIFEXITED */ +#ifndef WEXITSTATUS +#define WEXITSTATUS(status) (((status) >> 8) & 0xff) +#endif /* !defined WEXITSTATUS */ + #if HAVE_UNISTD_H - 0 #include "unistd.h" /* for F_OK and R_OK */ #endif /* HAVE_UNISTD_H - 0 */ =================================================================== RCS file: RCS/Makefile,v retrieving revision 1999.4 retrieving revision 1999.4.1.1 diff -u -r1999.4 -r1999.4.1.1 --- Makefile 1999/03/30 16:27:50 1999.4 +++ Makefile 1999/04/29 23:34:11 1999.4.1.1 @@ -92,6 +92,7 @@ # -DHAVE_SETTIMEOFDAY=3 if settimeofday ignores 2nd arg (4.4BSD) # -DHAVE_STRERROR=1 if `strerror' works # -DHAVE_SYMLINK=0 if your system lacks the symlink function +# -DHAVE_SYS_WAIT_H=0 if your compiler lacks a "sys/wait.h" # -DLOCALE_HOME=\"path\" if locales are in "path", not "/usr/lib/locale" # -DHAVE_UNISTD_H=0 if your compiler lacks a "unistd.h" (Microsoft C++ 7?) # -DHAVE_UTMPX_H=1 if your compiler has a "utmpx.h" =================================================================== RCS file: RCS/zic.c,v retrieving revision 1999.2 retrieving revision 1999.2.1.1 diff -u -r1999.2 -r1999.2.1.1 --- zic.c 1999/02/01 22:51:44 1999.2 +++ zic.c 1999/04/29 23:34:11 1999.2.1.1 @@ -1906,10 +1906,12 @@ buf = erealloc(buf, (int) (132 + strlen(yitcommand) + strlen(type))); (void) sprintf(buf, "%s %d %s", yitcommand, year, type); result = system(buf); - if (result == 0) - return TRUE; - if (result == (1 << 8)) - return FALSE; + if (WIFEXITED(result)) switch (WEXITSTATUS(result)) { + case 0: + return TRUE; + case 1: + return FALSE; + } error(_("Wild result from command execution")); (void) fprintf(stderr, _("%s: command was '%s', result was %d\n"), progname, buf, result);
Both solutions are suboptimal. The first mishandles old dates; the second assumes the New York City DST rules, whereas it'd be better to assume only the US rules. But clearly something should be done to the tz code to fix the problem, and either solution is acceptable.
Unfortunately, the optimal solution is to load the rules from a file, which we already do, but that doesn't work if the database is uninstalled. My inclination is to say "the optimal solution depends on the database being installed; if we can't even find 'posixrules', use some possibly-wrong hardcoded rules".
Hi, I already sent a message of similar contents to Paul Eggert. If he had already forwarded that to this list, please accept my apologies for the repetition. On Thu, May 06, 1999 at 02:32:45PM -0700, Guy Harris wrote:
Unfortunately, the optimal solution is to load the rules from a file, which we already do, but that doesn't work if the database is uninstalled.
My inclination is to say "the optimal solution depends on the database being installed; if we can't even find 'posixrules', use some possibly-wrong hardcoded rules".
In the meantime I have changed my mind about the subject and I actually disagree with such a solution: These possibly-wrong hardcoded rules will most probably be rules which may produce acceptable results for only the northern hemisphere. For the southern hemisphere they will be totally wrong, the difference will typically be two hours and that error will appear for most of the year. I would prefer to entirely ignore DST for this case and set the variables that indicate that DST is in use during some part of the year to -1 (undecided). Such an assumption will probably produce better results. An alternative would be to extract the rules and zone names for today (not the past or future) from the source files and hardcode them into the library. It would then be possible to calculate rules which cover the entire range of time_t values at run-time as long as a known zone name is used. Unfortunately, this solution would probably be faster than reading a database file and the results would still be acceptable for 99 % of the users. Ciao Guido -- http://stud.uni-sb.de/~gufl0000 mailto:gufl0000@stud.uni-sb.de
Hi, sorry, it's me again. I have problems with this little piece of code: bash$ cat >mktimetest <<EOF #include <stdio.h> #include <time.h> int main () { struct tm tm; time_t secs; memset (&tm, 0, sizeof tm); tm.year = 99; tm.mon = 4; tm.mday = 13; secs = mktime (&tm); printf ("secs: %ld (%s)\n", secs, strerror (errno)); return 0; } EOF # make mktimetest # TZ=CET-1CEST-2 ./mktimetest secs: -1 (OK) On installations where summertime applies during May mktime returns an error here (happens somewhere in the function time2). If I set tm.tm_isdst = -1; before calling mktime() the function returns the correct time. I have fixed that by inserting the line tmp->tm_isdst = -1; in mktime() before time1() gets called but I'm not sure if this is the right place to do that (or if this is correct at all). Can you verify that behavior or have I messed up my sources? If it is a bug, how should it be fixed? Thanks Guido -- http://stud.uni-sb.de/~gufl0000 mailto:gufl0000@stud.uni-sb.de
participants (4)
-
Guido Flohr -
guy@netapp.com -
Olson, Arthur David (NCI) -
Paul Eggert