automatically generated from GPLed version
[bpt/emacs.git] / src / mktime.c
1 /* Copyright (C) 1993, 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
2 Contributed by Paul Eggert (eggert@twinsun.com).
3
4 NOTE: The canonical source of this file is maintained with the GNU C Library.
5 Bugs can be reported to bug-glibc@prep.ai.mit.edu.
6
7 This program is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 2, or (at your option) any
10 later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
20 USA. */
21
22 /* Define this to have a standalone program to test this implementation of
23 mktime. */
24 /* #define DEBUG 1 */
25
26 #ifdef HAVE_CONFIG_H
27 # include <config.h>
28 #endif
29
30 #ifdef _LIBC
31 # define HAVE_LIMITS_H 1
32 # define HAVE_LOCALTIME_R 1
33 # define STDC_HEADERS 1
34 #endif
35
36 /* Assume that leap seconds are possible, unless told otherwise.
37 If the host has a `zic' command with a `-L leapsecondfilename' option,
38 then it supports leap seconds; otherwise it probably doesn't. */
39 #ifndef LEAP_SECONDS_POSSIBLE
40 # define LEAP_SECONDS_POSSIBLE 1
41 #endif
42
43 #include <sys/types.h> /* Some systems define `time_t' here. */
44 #include <time.h>
45
46 #if HAVE_LIMITS_H
47 # include <limits.h>
48 #endif
49
50 #if DEBUG
51 # include <stdio.h>
52 # if STDC_HEADERS
53 # include <stdlib.h>
54 # endif
55 /* Make it work even if the system's libc has its own mktime routine. */
56 # define mktime my_mktime
57 #endif /* DEBUG */
58
59 #ifndef __P
60 # if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
61 # define __P(args) args
62 # else
63 # define __P(args) ()
64 # endif /* GCC. */
65 #endif /* Not __P. */
66
67 #ifndef CHAR_BIT
68 # define CHAR_BIT 8
69 #endif
70
71 #ifndef INT_MIN
72 # define INT_MIN (~0 << (sizeof (int) * CHAR_BIT - 1))
73 #endif
74 #ifndef INT_MAX
75 # define INT_MAX (~0 - INT_MIN)
76 #endif
77
78 #ifndef TIME_T_MIN
79 /* The outer cast to time_t works around a bug in Cray C 5.0.3.0. */
80 # define TIME_T_MIN ((time_t) \
81 (0 < (time_t) -1 ? (time_t) 0 \
82 : ~ (time_t) 0 << (sizeof (time_t) * CHAR_BIT - 1)))
83 #endif
84 #ifndef TIME_T_MAX
85 # define TIME_T_MAX (~ (time_t) 0 - TIME_T_MIN)
86 #endif
87
88 #define TM_YEAR_BASE 1900
89 #define EPOCH_YEAR 1970
90
91 #ifndef __isleap
92 /* Nonzero if YEAR is a leap year (every 4 years,
93 except every 100th isn't, and every 400th is). */
94 # define __isleap(year) \
95 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
96 #endif
97
98 /* How many days come before each month (0-12). */
99 const unsigned short int __mon_yday[2][13] =
100 {
101 /* Normal years. */
102 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
103 /* Leap years. */
104 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
105 };
106
107 static time_t ydhms_tm_diff __P ((int, int, int, int, int, const struct tm *));
108 time_t __mktime_internal __P ((struct tm *,
109 struct tm *(*) (const time_t *, struct tm *),
110 time_t *));
111
112
113 #ifdef _LIBC
114 # define localtime_r __localtime_r
115 #else
116 # if ! HAVE_LOCALTIME_R && ! defined localtime_r
117 /* Approximate localtime_r as best we can in its absence. */
118 # define localtime_r my_mktime_localtime_r
119 static struct tm *localtime_r __P ((const time_t *, struct tm *));
120 static struct tm *
121 localtime_r (t, tp)
122 const time_t *t;
123 struct tm *tp;
124 {
125 struct tm *l = localtime (t);
126 if (! l)
127 return 0;
128 *tp = *l;
129 return tp;
130 }
131 # endif /* ! HAVE_LOCALTIME_R && ! defined (localtime_r) */
132 #endif /* ! _LIBC */
133
134
135 /* Yield the difference between (YEAR-YDAY HOUR:MIN:SEC) and (*TP),
136 measured in seconds, ignoring leap seconds.
137 YEAR uses the same numbering as TM->tm_year.
138 All values are in range, except possibly YEAR.
139 If overflow occurs, yield the low order bits of the correct answer. */
140 static time_t
141 ydhms_tm_diff (year, yday, hour, min, sec, tp)
142 int year, yday, hour, min, sec;
143 const struct tm *tp;
144 {
145 /* Compute intervening leap days correctly even if year is negative.
146 Take care to avoid int overflow. time_t overflow is OK, since
147 only the low order bits of the correct time_t answer are needed.
148 Don't convert to time_t until after all divisions are done, since
149 time_t might be unsigned. */
150 int a4 = (year >> 2) + (TM_YEAR_BASE >> 2) - ! (year & 3);
151 int b4 = (tp->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (tp->tm_year & 3);
152 int a100 = a4 / 25 - (a4 % 25 < 0);
153 int b100 = b4 / 25 - (b4 % 25 < 0);
154 int a400 = a100 >> 2;
155 int b400 = b100 >> 2;
156 int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
157 time_t years = year - (time_t) tp->tm_year;
158 time_t days = (365 * years + intervening_leap_days
159 + (yday - tp->tm_yday));
160 return (60 * (60 * (24 * days + (hour - tp->tm_hour))
161 + (min - tp->tm_min))
162 + (sec - tp->tm_sec));
163 }
164
165
166 static time_t localtime_offset;
167
168 /* Convert *TP to a time_t value. */
169 time_t
170 mktime (tp)
171 struct tm *tp;
172 {
173 #ifdef _LIBC
174 /* POSIX.1 8.1.1 requires that whenever mktime() is called, the
175 time zone names contained in the external variable `tzname' shall
176 be set as if the tzset() function had been called. */
177 __tzset ();
178 #endif
179
180 return __mktime_internal (tp, localtime_r, &localtime_offset);
181 }
182
183 /* Convert *TP to a time_t value, inverting
184 the monotonic and mostly-unit-linear conversion function CONVERT.
185 Use *OFFSET to keep track of a guess at the offset of the result,
186 compared to what the result would be for UTC without leap seconds.
187 If *OFFSET's guess is correct, only one CONVERT call is needed. */
188 time_t
189 __mktime_internal (tp, convert, offset)
190 struct tm *tp;
191 struct tm *(*convert) __P ((const time_t *, struct tm *));
192 time_t *offset;
193 {
194 time_t t, dt, t0;
195 struct tm tm;
196
197 /* The maximum number of probes (calls to CONVERT) should be enough
198 to handle any combinations of time zone rule changes, solar time,
199 and leap seconds. POSIX.1 prohibits leap seconds, but some hosts
200 have them anyway. */
201 int remaining_probes = 4;
202
203 /* Time requested. Copy it in case CONVERT modifies *TP; this can
204 occur if TP is localtime's returned value and CONVERT is localtime. */
205 int sec = tp->tm_sec;
206 int min = tp->tm_min;
207 int hour = tp->tm_hour;
208 int mday = tp->tm_mday;
209 int mon = tp->tm_mon;
210 int year_requested = tp->tm_year;
211 int isdst = tp->tm_isdst;
212
213 /* Ensure that mon is in range, and set year accordingly. */
214 int mon_remainder = mon % 12;
215 int negative_mon_remainder = mon_remainder < 0;
216 int mon_years = mon / 12 - negative_mon_remainder;
217 int year = year_requested + mon_years;
218
219 /* The other values need not be in range:
220 the remaining code handles minor overflows correctly,
221 assuming int and time_t arithmetic wraps around.
222 Major overflows are caught at the end. */
223
224 /* Calculate day of year from year, month, and day of month.
225 The result need not be in range. */
226 int yday = ((__mon_yday[__isleap (year + TM_YEAR_BASE)]
227 [mon_remainder + 12 * negative_mon_remainder])
228 + mday - 1);
229
230 int sec_requested = sec;
231 #if LEAP_SECONDS_POSSIBLE
232 /* Handle out-of-range seconds specially,
233 since ydhms_tm_diff assumes every minute has 60 seconds. */
234 if (sec < 0)
235 sec = 0;
236 if (59 < sec)
237 sec = 59;
238 #endif
239
240 /* Invert CONVERT by probing. First assume the same offset as last time.
241 Then repeatedly use the error to improve the guess. */
242
243 tm.tm_year = EPOCH_YEAR - TM_YEAR_BASE;
244 tm.tm_yday = tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
245 t0 = ydhms_tm_diff (year, yday, hour, min, sec, &tm);
246
247 for (t = t0 + *offset;
248 (dt = ydhms_tm_diff (year, yday, hour, min, sec, (*convert) (&t, &tm)));
249 t += dt)
250 if (--remaining_probes == 0)
251 return -1;
252
253 /* Check whether tm.tm_isdst has the requested value, if any. */
254 if (0 <= isdst && 0 <= tm.tm_isdst)
255 {
256 int dst_diff = (isdst != 0) - (tm.tm_isdst != 0);
257 if (dst_diff)
258 {
259 /* Move two hours in the direction indicated by the disagreement,
260 probe some more, and switch to a new time if found.
261 The largest known fallback due to daylight savings is two hours:
262 once, in Newfoundland, 1988-10-30 02:00 -> 00:00. */
263 time_t ot = t - 2 * 60 * 60 * dst_diff;
264 while (--remaining_probes != 0)
265 {
266 struct tm otm;
267 if (! (dt = ydhms_tm_diff (year, yday, hour, min, sec,
268 (*convert) (&ot, &otm))))
269 {
270 t = ot;
271 tm = otm;
272 break;
273 }
274 if ((ot += dt) == t)
275 break; /* Avoid a redundant probe. */
276 }
277 }
278 }
279
280 *offset = t - t0;
281
282 #if LEAP_SECONDS_POSSIBLE
283 if (sec_requested != tm.tm_sec)
284 {
285 /* Adjust time to reflect the tm_sec requested, not the normalized value.
286 Also, repair any damage from a false match due to a leap second. */
287 t += sec_requested - sec + (sec == 0 && tm.tm_sec == 60);
288 (*convert) (&t, &tm);
289 }
290 #endif
291
292 if (TIME_T_MAX / INT_MAX / 366 / 24 / 60 / 60 < 3)
293 {
294 /* time_t isn't large enough to rule out overflows in ydhms_tm_diff,
295 so check for major overflows. A gross check suffices,
296 since if t has overflowed, it is off by a multiple of
297 TIME_T_MAX - TIME_T_MIN + 1. So ignore any component of
298 the difference that is bounded by a small value. */
299
300 double dyear = (double) year_requested + mon_years - tm.tm_year;
301 double dday = 366 * dyear + mday;
302 double dsec = 60 * (60 * (24 * dday + hour) + min) + sec_requested;
303
304 if (TIME_T_MAX / 3 - TIME_T_MIN / 3 < (dsec < 0 ? - dsec : dsec))
305 return -1;
306 }
307
308 *tp = tm;
309 return t;
310 }
311
312 #ifdef weak_alias
313 weak_alias (mktime, timelocal)
314 #endif
315 \f
316 #if DEBUG
317
318 static int
319 not_equal_tm (a, b)
320 struct tm *a;
321 struct tm *b;
322 {
323 return ((a->tm_sec ^ b->tm_sec)
324 | (a->tm_min ^ b->tm_min)
325 | (a->tm_hour ^ b->tm_hour)
326 | (a->tm_mday ^ b->tm_mday)
327 | (a->tm_mon ^ b->tm_mon)
328 | (a->tm_year ^ b->tm_year)
329 | (a->tm_mday ^ b->tm_mday)
330 | (a->tm_yday ^ b->tm_yday)
331 | (a->tm_isdst ^ b->tm_isdst));
332 }
333
334 static void
335 print_tm (tp)
336 struct tm *tp;
337 {
338 printf ("%04d-%02d-%02d %02d:%02d:%02d yday %03d wday %d isdst %d",
339 tp->tm_year + TM_YEAR_BASE, tp->tm_mon + 1, tp->tm_mday,
340 tp->tm_hour, tp->tm_min, tp->tm_sec,
341 tp->tm_yday, tp->tm_wday, tp->tm_isdst);
342 }
343
344 static int
345 check_result (tk, tmk, tl, tml)
346 time_t tk;
347 struct tm tmk;
348 time_t tl;
349 struct tm tml;
350 {
351 if (tk != tl || not_equal_tm (&tmk, &tml))
352 {
353 printf ("mktime (");
354 print_tm (&tmk);
355 printf (")\nyields (");
356 print_tm (&tml);
357 printf (") == %ld, should be %ld\n", (long) tl, (long) tk);
358 return 1;
359 }
360
361 return 0;
362 }
363
364 int
365 main (argc, argv)
366 int argc;
367 char **argv;
368 {
369 int status = 0;
370 struct tm tm, tmk, tml;
371 time_t tk, tl;
372 char trailer;
373
374 if ((argc == 3 || argc == 4)
375 && (sscanf (argv[1], "%d-%d-%d%c",
376 &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &trailer)
377 == 3)
378 && (sscanf (argv[2], "%d:%d:%d%c",
379 &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &trailer)
380 == 3))
381 {
382 tm.tm_year -= TM_YEAR_BASE;
383 tm.tm_mon--;
384 tm.tm_isdst = argc == 3 ? -1 : atoi (argv[3]);
385 tmk = tm;
386 tl = mktime (&tmk);
387 tml = *localtime (&tl);
388 printf ("mktime returns %ld == ", (long) tl);
389 print_tm (&tmk);
390 printf ("\n");
391 status = check_result (tl, tmk, tl, tml);
392 }
393 else if (argc == 4 || (argc == 5 && strcmp (argv[4], "-") == 0))
394 {
395 time_t from = atol (argv[1]);
396 time_t by = atol (argv[2]);
397 time_t to = atol (argv[3]);
398
399 if (argc == 4)
400 for (tl = from; tl <= to; tl += by)
401 {
402 tml = *localtime (&tl);
403 tmk = tml;
404 tk = mktime (&tmk);
405 status |= check_result (tk, tmk, tl, tml);
406 }
407 else
408 for (tl = from; tl <= to; tl += by)
409 {
410 /* Null benchmark. */
411 tml = *localtime (&tl);
412 tmk = tml;
413 tk = tl;
414 status |= check_result (tk, tmk, tl, tml);
415 }
416 }
417 else
418 printf ("Usage:\
419 \t%s YYYY-MM-DD HH:MM:SS [ISDST] # Test given time.\n\
420 \t%s FROM BY TO # Test values FROM, FROM+BY, ..., TO.\n\
421 \t%s FROM BY TO - # Do not test those values (for benchmark).\n",
422 argv[0], argv[0], argv[0]);
423
424 return status;
425 }
426
427 #endif /* DEBUG */
428 \f
429 /*
430 Local Variables:
431 compile-command: "gcc -DDEBUG=1 -Wall -O -g mktime.c -o mktime"
432 End:
433 */