mktime() fails if it is called with a time that is exactly the moment when daylight saving time is starting. The configure program of certain gnu software tests mktime() for the failure described above. This fails on FreeBSD and so configure assumes there is no working mktime available. This behaviour was observed when configure'ing gnu tar-1.1.3. Fix: Unknown, unfortunatley... How-To-Repeat: The following program is the testing code of gnu's configure plus three printf's to show the returned value and if the problem exists. I have tried it also on HP-UX 10.20 and on IRIX 5.3 where it works. In this cases the result returned by mktime() is 891766800. #include <stdio.h> #include <stdlib.h> #include <time.h> void main () { time_t t; struct tm tm; /* Use the portable POSIX.1 specification "TZ=PST8PDT,M4.1.0,M10.5.0" instead of "TZ=America/Vancouver" in order to detect the bug even on systems that don't support the Olson extension, or don't have the full zoneinfo tables installed. */ putenv ("TZ=PST8PDT,M4.1.0,M10.5.0"); tm.tm_year = 98; tm.tm_mon = 3; tm.tm_mday = 5; tm.tm_hour = 2; tm.tm_min = 0; tm.tm_sec = 0; tm.tm_isdst = -1; t=mktime(&tm); printf("%lu, ", t); if (t== (time_t)-1) { printf("Error\n"); exit (1); } printf("OK\n"); } For better understanding, here is the complete conftest.c that is used by configure: #line 4392 "configure" #include "confdefs.h" /* Test program from Paul Eggert (eggert@twinsun.com) and Tony Leneis (tony@plaza.ds.adp.com). */ #if TIME_WITH_SYS_TIME # include <sys/time.h> # include <time.h> #else # if HAVE_SYS_TIME_H # include <sys/time.h> # else # include <time.h> # endif #endif #if HAVE_UNISTD_H # include <unistd.h> #endif #if !HAVE_ALARM # define alarm(X) /* empty */ #endif /* Work around redefinition to rpl_putenv by other config tests. */ #undef putenv static time_t time_t_max; /* Values we'll use to set the TZ environment variable. */ static const char *const tz_strings[] = { (const char *) 0, "TZ=GMT0", "TZ=JST-9", "TZ=EST+3EDT+2,M10.1.0/00:00:00,M2.3.0/00:00:00" }; #define N_STRINGS (sizeof (tz_strings) / sizeof (tz_strings[0])) /* Fail if mktime fails to convert a date in the spring-forward gap. Based on a problem report from Andreas Jaeger. */ static void spring_forward_gap () { /* glibc (up to about 1998-10-07) failed this test) */ struct tm tm; /* Use the portable POSIX.1 specification "TZ=PST8PDT,M4.1.0,M10.5.0" instead of "TZ=America/Vancouver" in order to detect the bug even on systems that don't support the Olson extension, or don't have the full zoneinfo tables installed. */ putenv ("TZ=PST8PDT,M4.1.0,M10.5.0"); tm.tm_year = 98; tm.tm_mon = 3; tm.tm_mday = 5; tm.tm_hour = 2; tm.tm_min = 0; tm.tm_sec = 0; tm.tm_isdst = -1; if (mktime (&tm) == (time_t)-1) exit (1); } static void mktime_test (now) time_t now; { struct tm *lt; if ((lt = localtime (&now)) && mktime (lt) != now) exit (1); now = time_t_max - now; if ((lt = localtime (&now)) && mktime (lt) != now) exit (1); } static void irix_6_4_bug () { /* Based on code from Ariel Faigon. */ struct tm tm; tm.tm_year = 96; tm.tm_mon = 3; tm.tm_mday = 0; tm.tm_hour = 0; tm.tm_min = 0; tm.tm_sec = 0; tm.tm_isdst = -1; mktime (&tm); if (tm.tm_mon != 2 || tm.tm_mday != 31) exit (1); } static void bigtime_test (j) int j; { struct tm tm; time_t now; tm.tm_year = tm.tm_mon = tm.tm_mday = tm.tm_hour = tm.tm_min = tm.tm_sec = j; now = mktime (&tm); if (now != (time_t) -1) { struct tm *lt = localtime (&now); if (! (lt && lt->tm_year == tm.tm_year && lt->tm_mon == tm.tm_mon && lt->tm_mday == tm.tm_mday && lt->tm_hour == tm.tm_hour && lt->tm_min == tm.tm_min && lt->tm_sec == tm.tm_sec && lt->tm_yday == tm.tm_yday && lt->tm_wday == tm.tm_wday && ((lt->tm_isdst < 0 ? -1 : 0 < lt->tm_isdst) == (tm.tm_isdst < 0 ? -1 : 0 < tm.tm_isdst)))) exit (1); } } int main () { time_t t, delta; int i, j; /* This test makes some buggy mktime implementations loop. Give up after 60 seconds; a mktime slower than that isn't worth using anyway. */ alarm (60); for (time_t_max = 1; 0 < time_t_max; time_t_max *= 2) continue; time_t_max--; delta = time_t_max / 997; /* a suitable prime number */ for (i = 0; i < N_STRINGS; i++) { if (tz_strings[i]) putenv (tz_strings[i]); for (t = 0; t <= time_t_max - delta; t += delta) mktime_test (t); mktime_test ((time_t) 60 * 60); mktime_test ((time_t) 60 * 60 * 24); for (j = 1; 0 < j; j *= 2) bigtime_test (j); bigtime_test (j - 1); } irix_6_4_bug (); spring_forward_gap (); exit (0); }
In message <199912162016.VAA97593@internal>, Andre Albsmeier writes: >mktime() fails if it is called with a time that is exactly >the moment when daylight saving time is starting. Well, at least for the "spring forward case" that time doesn't exist: 01:59:57 01:59:58 01:59:59 03:00:00 There is no 02:00:00 that night. If they test for that, they're crazy. -- Poul-Henning Kamp FreeBSD coreteam member phk@FreeBSD.ORG "Real hackers run -current on their laptop." FreeBSD -- It will take a long time before progress goes too far!
On Thu, 16-Dec-1999 at 21:24:41 +0100, Poul-Henning Kamp wrote: > In message <199912162016.VAA97593@internal>, Andre Albsmeier writes: > > >mktime() fails if it is called with a time that is exactly > >the moment when daylight saving time is starting. > > Well, at least for the "spring forward case" that time doesn't > exist: > > 01:59:57 > 01:59:58 > 01:59:59 > 03:00:00 > > There is no 02:00:00 that night. If they test for that, they're > crazy. Yes, the time does not exist. However, I only wonder it our behaviour of returning an error is correct in this case. I don't trust the GNU/Linux guys as much as I trust FreeBSD :-) but there might be a reason they are testing it. I was already asked in private email if the mktime() should succeed according to POSIX.1... Does somebody know anything about that? -Andre
<<On Thu, 16 Dec 1999 21:16:20 +0100 (CET), Andre Albsmeier <andre.albsmeier@mchp.siemens.de> said: > mktime() fails if it is called with a time that is exactly > the moment when daylight saving time is starting. > The configure program of certain gnu software tests mktime() > for the failure described above. This fails on FreeBSD and > so configure assumes there is no working mktime available. ``certain gnu software'' is broken. Bring it up with the maintainers. -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
In message <19991216213647.A34480@internal>, Andre Albsmeier writes: >On Thu, 16-Dec-1999 at 21:24:41 +0100, Poul-Henning Kamp wrote: >> In message <199912162016.VAA97593@internal>, Andre Albsmeier writes: >> >> There is no 02:00:00 that night. If they test for that, they're >> crazy. > >Yes, the time does not exist. However, I only wonder it our >behaviour of returning an error is correct in this case. I don't >trust the GNU/Linux guys as much as I trust FreeBSD :-) but there >might be a reason they are testing it. > >I was already asked in private email if the mktime() should >succeed according to POSIX.1... Does somebody know anything >about that? Well, Hum. It seems to say that the fields are not constrained to their normal domains: The original values of the tm_wday and tm_yday components of the structure are ignored, and the original values of the other components are not restricted to the ranges described in the <time.h> entry. It does not describe what should happen if I ask it to make a time out of 25:100:100, but I guess most of us can agree what it should do. The trouble with passing it 02:00:00 or for that matter 02:59:00 on the "spring forward" night, is that the time doesn't exist in the first place: Ie, does 02:10:00 represent 01:59:59 + 10:59 = 03:10:00 or 03:00:00 - 50:00 = 01:10:00 Since no sane argument either way really holds water, I think returning an error is correct. -- Poul-Henning Kamp FreeBSD coreteam member phk@FreeBSD.ORG "Real hackers run -current on their laptop." FreeBSD -- It will take a long time before progress goes too far!
On Thu, 16-Dec-1999 at 21:52:17 +0100, Poul-Henning Kamp wrote: > In message <19991216213647.A34480@internal>, Andre Albsmeier writes: > >On Thu, 16-Dec-1999 at 21:24:41 +0100, Poul-Henning Kamp wrote: > >> In message <199912162016.VAA97593@internal>, Andre Albsmeier writes: > >> > >> There is no 02:00:00 that night. If they test for that, they're > >> crazy. > > > >Yes, the time does not exist. However, I only wonder it our > >behaviour of returning an error is correct in this case. I don't > >trust the GNU/Linux guys as much as I trust FreeBSD :-) but there > >might be a reason they are testing it. > > > >I was already asked in private email if the mktime() should > >succeed according to POSIX.1... Does somebody know anything > >about that? > > Well, Hum. It seems to say that the fields are not constrained > to their normal domains: > > The original values of the tm_wday and tm_yday components > of the structure are ignored, and the original values of > the other components are not restricted to the ranges > described in the <time.h> entry. > > It does not describe what should happen if I ask it to make a time > out of 25:100:100, but I guess most of us can agree what it should > do. > > The trouble with passing it 02:00:00 or for that matter 02:59:00 > on the "spring forward" night, is that the time doesn't exist in > the first place: Ie, does 02:10:00 represent > > 01:59:59 + 10:59 = 03:10:00 > or > 03:00:00 - 50:00 = 01:10:00 > > Since no sane argument either way really holds water, I think > returning an error is correct. I just tried to find out how HP-UX 10.20 and IRIX 5.3 interpret this; they both behave in the same way: When setting tm_hour to 2 (the illegal value) the result is 891766800. When using 1 for tm_hour we also get 891766800. When using 0 for tm_hour we get 891763200, this is -3600 from above. When using 3 for tm_hour the result is 891770400, this is +3600 compared to the first two. These two interpret the setting of tm_hour to 2 as 1. (That doesn't imply that I think this is correct). -Andre
On Thu, 16-Dec-1999 at 21:52:17 +0100, Poul-Henning Kamp wrote: > In message <19991216213647.A34480@internal>, Andre Albsmeier writes: > >On Thu, 16-Dec-1999 at 21:24:41 +0100, Poul-Henning Kamp wrote: > >> In message <199912162016.VAA97593@internal>, Andre Albsmeier writes: > >> > >> There is no 02:00:00 that night. If they test for that, they're > >> crazy. > > > >Yes, the time does not exist. However, I only wonder it our > >behaviour of returning an error is correct in this case. I don't > >trust the GNU/Linux guys as much as I trust FreeBSD :-) but there > >might be a reason they are testing it. > > > >I was already asked in private email if the mktime() should > >succeed according to POSIX.1... Does somebody know anything > >about that? > > Well, Hum. It seems to say that the fields are not constrained > to their normal domains: > > The original values of the tm_wday and tm_yday components > of the structure are ignored, and the original values of > the other components are not restricted to the ranges > described in the <time.h> entry. > > It does not describe what should happen if I ask it to make a time > out of 25:100:100, but I guess most of us can agree what it should > do. > > The trouble with passing it 02:00:00 or for that matter 02:59:00 > on the "spring forward" night, is that the time doesn't exist in > the first place: Ie, does 02:10:00 represent > > 01:59:59 + 10:59 = 03:10:00 > or > 03:00:00 - 50:00 = 01:10:00 > > Since no sane argument either way really holds water, I think > returning an error is correct. As I wrote initally, the problem arises when configure tries to determine if mktime() works. I have now looked what happens in this case: The program replaces mktime with its own call. For the record, here is the interesting part (mktime.c, around line 277): if (t == t1 && t != t2 && (isdst < 0 || tm.tm_isdst < 0 || (isdst != 0) != (tm.tm_isdst != 0))) /* We can't possibly find a match, as we are oscillating between two values. The requested time probably falls within a spring-forward gap of size DT. Follow the common practice in this case, which is to return a time that is DT away from the requested time, preferring a time whose tm_isdst differs from the requested value. In practice, this is more useful than returning -1. */ break; else if (--remaining_probes == 0) return -1; -Andre
State Changed From-To: open->closed I (and many others) believe that it is more correct to return an error from mktime() when it's asked to construct a time from some time that can't happen. Others belive that mktime() should succeed during leap-periods. POSIX (I'm told) doesn't specify either. IMHO this is therefore a non-issue. FreeBSD's mktime() returns an error and will stay that way.