Add time_r module. Change timegm, mktime, and strftime to use localtime_r
[gnulib.git] / m4 / mktime.m4
1 # mktime.m4 serial 3
2 dnl Copyright (C) 2002, 2003 Free Software Foundation, Inc.
3 dnl This file is free software, distributed under the terms of the GNU
4 dnl General Public License.  As a special exception to the GNU General
5 dnl Public License, this file may be distributed as part of a program
6 dnl that contains a configuration script generated by Autoconf, under
7 dnl the same distribution terms as the rest of that program.
8
9 dnl From Jim Meyering.
10
11 # Redefine AC_FUNC_MKTIME, to fix a bug in Autoconf 2.57 and earlier.
12 # This redefinition can be removed once a new version of Autoconf comes out.
13 # The redefinition is taken from
14 # <http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/autoconf/autoconf/lib/autoconf/functions.m4?rev=1.78>.
15 # AC_FUNC_MKTIME
16 # --------------
17 AC_DEFUN([AC_FUNC_MKTIME],
18 [AC_REQUIRE([AC_HEADER_TIME])dnl
19 AC_CHECK_HEADERS(stdlib.h sys/time.h unistd.h)
20 AC_CHECK_FUNCS(alarm)
21 AC_CACHE_CHECK([for working mktime], ac_cv_func_working_mktime,
22 [AC_RUN_IFELSE([AC_LANG_SOURCE(
23 [[/* Test program from Paul Eggert and Tony Leneis.  */
24 #if TIME_WITH_SYS_TIME
25 # include <sys/time.h>
26 # include <time.h>
27 #else
28 # if HAVE_SYS_TIME_H
29 #  include <sys/time.h>
30 # else
31 #  include <time.h>
32 # endif
33 #endif
34
35 #if HAVE_STDLIB_H
36 # include <stdlib.h>
37 #endif
38
39 #if HAVE_UNISTD_H
40 # include <unistd.h>
41 #endif
42
43 #if !HAVE_ALARM
44 # define alarm(X) /* empty */
45 #endif
46
47 /* Work around redefinition to rpl_putenv by other config tests.  */
48 #undef putenv
49
50 static time_t time_t_max;
51 static time_t time_t_min;
52
53 /* Values we'll use to set the TZ environment variable.  */
54 static char *tz_strings[] = {
55   (char *) 0, "TZ=GMT0", "TZ=JST-9",
56   "TZ=EST+3EDT+2,M10.1.0/00:00:00,M2.3.0/00:00:00"
57 };
58 #define N_STRINGS (sizeof (tz_strings) / sizeof (tz_strings[0]))
59
60 /* Fail if mktime fails to convert a date in the spring-forward gap.
61    Based on a problem report from Andreas Jaeger.  */
62 static void
63 spring_forward_gap ()
64 {
65   /* glibc (up to about 1998-10-07) failed this test. */
66   struct tm tm;
67
68   /* Use the portable POSIX.1 specification "TZ=PST8PDT,M4.1.0,M10.5.0"
69      instead of "TZ=America/Vancouver" in order to detect the bug even
70      on systems that don't support the Olson extension, or don't have the
71      full zoneinfo tables installed.  */
72   putenv ("TZ=PST8PDT,M4.1.0,M10.5.0");
73
74   tm.tm_year = 98;
75   tm.tm_mon = 3;
76   tm.tm_mday = 5;
77   tm.tm_hour = 2;
78   tm.tm_min = 0;
79   tm.tm_sec = 0;
80   tm.tm_isdst = -1;
81   if (mktime (&tm) == (time_t)-1)
82     exit (1);
83 }
84
85 static void
86 mktime_test1 (now)
87      time_t now;
88 {
89   struct tm *lt;
90   if ((lt = localtime (&now)) && mktime (lt) != now)
91     exit (1);
92 }
93
94 static void
95 mktime_test (now)
96      time_t now;
97 {
98   mktime_test1 (now);
99   mktime_test1 ((time_t) (time_t_max - now));
100   mktime_test1 ((time_t) (time_t_min + now));
101 }
102
103 static void
104 irix_6_4_bug ()
105 {
106   /* Based on code from Ariel Faigon.  */
107   struct tm tm;
108   tm.tm_year = 96;
109   tm.tm_mon = 3;
110   tm.tm_mday = 0;
111   tm.tm_hour = 0;
112   tm.tm_min = 0;
113   tm.tm_sec = 0;
114   tm.tm_isdst = -1;
115   mktime (&tm);
116   if (tm.tm_mon != 2 || tm.tm_mday != 31)
117     exit (1);
118 }
119
120 static void
121 bigtime_test (j)
122      int j;
123 {
124   struct tm tm;
125   time_t now;
126   tm.tm_year = tm.tm_mon = tm.tm_mday = tm.tm_hour = tm.tm_min = tm.tm_sec = j;
127   now = mktime (&tm);
128   if (now != (time_t) -1)
129     {
130       struct tm *lt = localtime (&now);
131       if (! (lt
132              && lt->tm_year == tm.tm_year
133              && lt->tm_mon == tm.tm_mon
134              && lt->tm_mday == tm.tm_mday
135              && lt->tm_hour == tm.tm_hour
136              && lt->tm_min == tm.tm_min
137              && lt->tm_sec == tm.tm_sec
138              && lt->tm_yday == tm.tm_yday
139              && lt->tm_wday == tm.tm_wday
140              && ((lt->tm_isdst < 0 ? -1 : 0 < lt->tm_isdst)
141                   == (tm.tm_isdst < 0 ? -1 : 0 < tm.tm_isdst))))
142         exit (1);
143     }
144 }
145
146 int
147 main ()
148 {
149   time_t t, delta;
150   int i, j;
151
152   /* This test makes some buggy mktime implementations loop.
153      Give up after 60 seconds; a mktime slower than that
154      isn't worth using anyway.  */
155   alarm (60);
156
157   for (time_t_max = 1; 0 < time_t_max; time_t_max *= 2)
158     continue;
159   time_t_max--;
160   if ((time_t) -1 < 0)
161     for (time_t_min = -1; (time_t) (time_t_min * 2) < 0; time_t_min *= 2)
162       continue;
163   delta = time_t_max / 997; /* a suitable prime number */
164   for (i = 0; i < N_STRINGS; i++)
165     {
166       if (tz_strings[i])
167         putenv (tz_strings[i]);
168
169       for (t = 0; t <= time_t_max - delta; t += delta)
170         mktime_test (t);
171       mktime_test ((time_t) 1);
172       mktime_test ((time_t) (60 * 60));
173       mktime_test ((time_t) (60 * 60 * 24));
174
175       for (j = 1; 0 < j; j *= 2)
176         bigtime_test (j);
177       bigtime_test (j - 1);
178     }
179   irix_6_4_bug ();
180   spring_forward_gap ();
181   exit (0);
182 }]])],
183                [ac_cv_func_working_mktime=yes],
184                [ac_cv_func_working_mktime=no],
185                [ac_cv_func_working_mktime=no])])
186 if test $ac_cv_func_working_mktime = no; then
187   AC_LIBOBJ([mktime])
188 fi
189 ])# AC_FUNC_MKTIME
190
191 AC_DEFUN([gl_FUNC_MKTIME],
192 [
193   AC_REQUIRE([AC_FUNC_MKTIME])
194   if test $ac_cv_func_working_mktime = no; then
195     AC_DEFINE(mktime, rpl_mktime,
196       [Define to rpl_mktime if the replacement function should be used.])
197     gl_PREREQ_MKTIME
198   fi
199 ])
200
201 # Prerequisites of lib/mktime.c.
202 AC_DEFUN([gl_PREREQ_MKTIME], [
203   AC_REQUIRE([AC_HEADER_STDC])
204 ])