FW: tz interface problems

---------- From: D. J. Bernstein[SMTP:djb@cr.yp.to] Sent: Monday, May 18, 1998 3:32 AM To: arthur_david_olson@nih.gov; djb@cr.yp.to Subject: tz interface problems 1. Check out the dates produced by sendmail on one host: Mon, 18 May 1998 16:36:37 +0930 Mon, 18 May 1998 16:36:38 +0930 Mon, 18 May 1998 16:36:39 +0929 Mon, 18 May 1998 16:36:40 +0929 The problem, of course, is that sendmail is figuring out the offset by comparing the hours and minutes shown by localtime() and gmtime(). Mailers don't care about time zone names; they want the UTC offset. Do you have a routine that, given a time, returns the offset? (1-second offsets can't be expressed in mail, but that's a separate problem.) 2. I'm sure you're aware that BSD and Linux now include your routines. Unfortunately, they don't make it easy for typical users to regenerate the time-zone files. Users could download new files, but that's a megabyte of data. The practical effect is that many systems slipped by a second in 1997, and will probably slip by another second at the end of 1998. How difficult would it be for you to get leap-second data from another file? I've been working on the Y2038 problem, and I've put together an /etc/leapsecs.dat format for recording leap seconds. ---Dan

<<On Wed, 20 May 1998 09:47:42 -0400, "Olson, Arthur David" <OLSONA@dc37a.nci.nih.gov> quoted a message from D. J. Bernstein:
The practical effect is that many systems slipped by a second in 1997, and will probably slip by another second at the end of 1998.
FreeBSD follows the PCTS/xntpd model of leap second observance (which is to say, ``it doesn't''). We actually care more about NTP working than PCTS, so until NTP is redesigned to tick TAI, or the NTP daemon redesigned to deal with a leap-second-cognizant operating system, we're stuck with it. In any case, if the user enabled leap seconds, that means they already have the source and were capable of editing the Makefile and reinstalling the timezone data files. It would not be particularly difficult for us to add an additional installation option, ``install timezone source files'', just as we do for the sendfail config kit, but this would not be meaningful to 99% of our new-installation users, and those who care are the sort who would install the source anyway. If we really wanted to deal seriously with leap seconds, we would probably add the functionality to libcalendar. There are essentially three ways one would want to use this information: - for any given time, compute the value of TAI-UTC - for any given time, compute the difference between UTC and POSIX time - convert a specific UTC, POSIX, or TAI time into one of the other systems I can't speak for other systems. -GAWollman -- Garrett A. Wollman | O Siem / We are all family / O Siem / We're all the same wollman@lcs.mit.edu | O Siem / The fires of freedom Opinions not those of| Dance in the burning flame MIT, LCS, CRS, or NSA| - Susan Aglukark and Chad Irschick

From: D. J. Bernstein[SMTP:djb@cr.yp.to] Sent: Monday, May 18, 1998 3:32 AM 1. Check out the dates produced by sendmail on one host: Mon, 18 May 1998 16:36:37 +0930 Mon, 18 May 1998 16:36:38 +0930 Mon, 18 May 1998 16:36:39 +0929 Mon, 18 May 1998 16:36:40 +0929 The problem, of course, is that sendmail is figuring out the offset by comparing the hours and minutes shown by localtime() and gmtime(). That method should be reliable, so long as you pass the same timestamp to both localtime and gmtime. Can you give more details about the problem? Do you have a routine that, given a time, returns the offset? There's not one in the tz packages, but one is commonly included in GNU code. I'll enclose a copy at the end of this message. Of course the Right Way to do it is to use tm_gmtoff, but this isn't blessed by the standards. How difficult would it be for you to get leap-second data from another file? With the tz code, the leapsecond data is already gotten from a separate file called `leapseconds'. Or do you mean distribute the leapsecond data in a separate file, e.g. ftp://elsie.nci.nih.gov/pub/leapseconds as opposed to having people untar it? That shouldn't be hard to arrange -- ado would know for sure. But first I'd like to make sure that this is what you want. Anyway, here's the offset-returning routine. /* This code is derived from FSF copyrighted code, so the GPL applies. */ #include <time.h> #define div(a, b) ((a) / (b) - ((a) % (b) < 0)) #define TM_YEAR_ORIGIN 1900 /* Yield A - B, measured in seconds. */ time_t difftm (a, b) struct tm const *a; struct tm const *b; { int ay = a->tm_year + (TM_YEAR_ORIGIN - 1); int by = b->tm_year + (TM_YEAR_ORIGIN - 1); int ac = div (ay, 100); int bc = div (by, 100); int difference_in_day_of_year = a->tm_yday - b->tm_yday; int intervening_leap_days = (((ay >> 2) - (by >> 2)) - (ac - bc) + ((ac >> 2) - (bc >> 2))); time_t difference_in_years = ay - by; time_t difference_in_days = (difference_in_years * 365 + (intervening_leap_days + difference_in_day_of_year)); return (((((difference_in_days * 24 + (a->tm_hour - b->tm_hour)) * 60) + (a->tm_min - b->tm_min)) * 60) + (a->tm_sec - b->tm_sec)); } /* Yield the number of seconds that local time is ahead of GMT at time T, or 0 if this is not known. */ long gmtoff (t) time_t t; { struct tm gmt, *gmtp, *ltp; if (! (gmtp = gmtime (&t))) return 0; gmt = *gmtp; if (! (ltp = localtime (&t))) return 0; return difftm (ltp, &gmt); }

Paul Eggert writes:
With the tz code, the leapsecond data is already gotten from a separate file called `leapseconds'.
Please pay attention. Running zic is a pain, since the OS doesn't include the necessary input data. What I'm suggesting is a leap-second table read at run time. This will simplify tz maintenance for people who live in stable time zones.
That method should be reliable,
It isn't. Your code is wrong. tm_gmtoff answers my question. ---Dan

I looked further into the problem that you mentioned with sendmail in Australia, and I think I tracked it down to a bug in the way that tz implements leap second support. Here's an instance of the problem, assuming that you installed the tz package in the default way, and that all commands run in the same second: $ TZ=right/Australia/Adelaide sh -c 'date; date -u' Sat May 23 11:14:40 CST 1998 * Sat May 23 01:45:01 UTC 1998 $ TZ=posix/Australia/Adelaide sh -c 'date; date -u' Sat May 23 11:15:01 CST 1998 Sat May 23 01:45:01 UTC 1998 The output line marked '*' is bogus: it's too large by 21 seconds, because the tz code does not adjust for leap seconds when computing gmtime, if TZ specifies leap seconds but the .../zoneinfo/GMT file does not specify leap seconds. Because of this problem, sendmail will currently report an incorrect time zone about 1/3 of the time if (1) you're in the eastern hemisphere, (2) you're using leap seconds, and (3) the system default is no leap seconds. The bug occurs with the above example time stamp, since sendmail subtracts 01:45 from 11:14 and comes up with +0929. The basic problem is that tz code looks at the system file .../zoneinfo/GMT to decide what leap seconds to use when computing GMT; this leads to bogus results if the user wants leap seconds and the system file doesn't (or vice versa). One possible fix is to have the tz code look at the leap seconds information in the file that the TZ environment variable specifies, rather than the .../zoneinfo/GMT file. This would also be a tad more efficient, since it would mean one less file to look at. Arthur David Olson is obviously the best person to evaluate this proposed fix, though. I haven't looked at the GNU C library to see whether it has the same problem.

Date: Fri, 22 May 1998 18:43:43 -0700 From: Paul Eggert <eggert@twinsun.com> $ TZ=right/Australia/Adelaide sh -c 'date; date -u' Sat May 23 11:14:40 CST 1998 * Sat May 23 01:45:01 UTC 1998 $ TZ=posix/Australia/Adelaide sh -c 'date; date -u' Sat May 23 11:15:01 CST 1998 Sat May 23 01:45:01 UTC 1998 On further thought, I should point out that `date' gets the wrong result by a slightly different method from `sendmail'. `sendmail' uses gmtime() and localtime(), whereas `date' uses only localtime() but sets the TZ environment variable to "UTC0" before invoking localtime(). The resulting symptoms are the same, but the mechanisms are different. So I'd guess that `date.c' will also need a bit of hacking in its own right.
participants (4)
-
D. J. Bernstein
-
Garrett Wollman
-
Olson, Arthur David
-
Paul Eggert