]> code.delx.au - gnu-emacs/blob - src/mktime.c
(Vread_buffer_function): New var.
[gnu-emacs] / 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 /* Some hosts need this in order to declare localtime_r properly. */
31 #ifndef _REENTRANT
32 # define _REENTRANT 1
33 #endif
34
35 #ifdef _LIBC
36 # define HAVE_LIMITS_H 1
37 # define HAVE_LOCALTIME_R 1
38 # define STDC_HEADERS 1
39 #endif
40
41 /* Assume that leap seconds are possible, unless told otherwise.
42 If the host has a `zic' command with a `-L leapsecondfilename' option,
43 then it supports leap seconds; otherwise it probably doesn't. */
44 #ifndef LEAP_SECONDS_POSSIBLE
45 # define LEAP_SECONDS_POSSIBLE 1
46 #endif
47
48 #include <sys/types.h> /* Some systems define `time_t' here. */
49 #include <time.h>
50
51 #if HAVE_LIMITS_H
52 # include <limits.h>
53 #endif
54
55 #if DEBUG
56 # include <stdio.h>
57 # if STDC_HEADERS
58 # include <stdlib.h>
59 # endif
60 /* Make it work even if the system's libc has its own mktime routine. */
61 # define mktime my_mktime
62 #endif /* DEBUG */
63
64 #ifndef __P
65 # if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
66 # define __P(args) args
67 # else
68 # define __P(args) ()
69 # endif /* GCC. */
70 #endif /* Not __P. */
71
72 #ifndef CHAR_BIT
73 # define CHAR_BIT 8
74 #endif
75
76 #ifndef INT_MIN
77 # define INT_MIN (~0 << (sizeof (int) * CHAR_BIT - 1))
78 #endif
79 #ifndef INT_MAX
80 # define INT_MAX (~0 - INT_MIN)
81 #endif
82
83 #ifndef TIME_T_MIN
84 /* The outer cast to time_t works around a bug in Cray C 5.0.3.0. */
85 # define TIME_T_MIN ((time_t) \
86 (0 < (time_t) -1 ? (time_t) 0 \
87 : ~ (time_t) 0 << (sizeof (time_t) * CHAR_BIT - 1)))
88 #endif
89 #ifndef TIME_T_MAX
90 # define TIME_T_MAX (~ (time_t) 0 - TIME_T_MIN)
91 #endif
92
93 #define TM_YEAR_BASE 1900
94 #define EPOCH_YEAR 1970
95
96 #ifndef __isleap
97 /* Nonzero if YEAR is a leap year (every 4 years,
98 except every 100th isn't, and every 400th is). */
99 # define __isleap(year) \
100 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
101 #endif
102
103 /* How many days come before each month (0-12). */
104 const unsigned short int __mon_yday[2][13] =
105 {
106 /* Normal years. */
107 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
108 /* Leap years. */
109 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
110 };
111
112 static struct tm *ranged_convert __P ((struct tm *(*) __P ((const time_t *,
113 struct tm *)),
114 time_t *, struct tm *));
115 static time_t ydhms_tm_diff __P ((int, int, int, int, int, const struct tm *));
116 time_t __mktime_internal __P ((struct tm *,
117 struct tm *(*) (const time_t *, struct tm *),
118 time_t *));
119
120
121 #ifdef _LIBC
122 # define localtime_r __localtime_r
123 #else
124 # if ! HAVE_LOCALTIME_R && ! defined localtime_r
125 /* Approximate localtime_r as best we can in its absence. */
126 # define localtime_r my_mktime_localtime_r
127 static struct tm *localtime_r __P ((const time_t *, struct tm *));
128 static struct tm *
129 localtime_r (t, tp)
130 const time_t *t;
131 struct tm *tp;
132 {
133 struct tm *l = localtime (t);
134 if (! l)
135 return 0;
136 *tp = *l;
137 return tp;
138 }
139 # endif /* ! HAVE_LOCALTIME_R && ! defined (localtime_r) */
140 #endif /* ! _LIBC */
141
142
143 /* Yield the difference between (YEAR-YDAY HOUR:MIN:SEC) and (*TP),
144 measured in seconds, ignoring leap seconds.
145 YEAR uses the same numbering as TM->tm_year.
146 All values are in range, except possibly YEAR.
147 If TP is null, return a nonzero value.
148 If overflow occurs, yield the low order bits of the correct answer. */
149 static time_t
150 ydhms_tm_diff (year, yday, hour, min, sec, tp)
151 int year, yday, hour, min, sec;
152 const struct tm *tp;
153 {
154 if (!tp)
155 return 1;
156 else
157 {
158 /* Compute intervening leap days correctly even if year is negative.
159 Take care to avoid int overflow. time_t overflow is OK, since
160 only the low order bits of the correct time_t answer are needed.
161 Don't convert to time_t until after all divisions are done, since
162 time_t might be unsigned. */
163 int a4 = (year >> 2) + (TM_YEAR_BASE >> 2) - ! (year & 3);
164 int b4 = (tp->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (tp->tm_year & 3);
165 int a100 = a4 / 25 - (a4 % 25 < 0);
166 int b100 = b4 / 25 - (b4 % 25 < 0);
167 int a400 = a100 >> 2;
168 int b400 = b100 >> 2;
169 int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
170 time_t years = year - (time_t) tp->tm_year;
171 time_t days = (365 * years + intervening_leap_days
172 + (yday - tp->tm_yday));
173 return (60 * (60 * (24 * days + (hour - tp->tm_hour))
174 + (min - tp->tm_min))
175 + (sec - tp->tm_sec));
176 }
177 }
178
179
180 static time_t localtime_offset;
181
182 /* Convert *TP to a time_t value. */
183 time_t
184 mktime (tp)
185 struct tm *tp;
186 {
187 #ifdef _LIBC
188 /* POSIX.1 8.1.1 requires that whenever mktime() is called, the
189 time zone names contained in the external variable `tzname' shall
190 be set as if the tzset() function had been called. */
191 __tzset ();
192 #endif
193
194 return __mktime_internal (tp, localtime_r, &localtime_offset);
195 }
196
197 /* Use CONVERT to convert *T to a broken down time in *TP.
198 If *T is out of range for conversion, adjust it so that
199 it is the nearest in-range value and then convert that. */
200 static struct tm *
201 ranged_convert (convert, t, tp)
202 struct tm *(*convert) __P ((const time_t *, struct tm *));
203 time_t *t;
204 struct tm *tp;
205 {
206 struct tm *r;
207
208 if (! (r = (*convert) (t, tp)) && *t)
209 {
210 time_t bad = *t;
211 time_t ok = 0;
212 struct tm tm;
213
214 /* BAD is a known unconvertible time_t, and OK is a known good one.
215 Use binary search to narrow the range between BAD and OK until
216 they differ by 1. */
217 while (bad != ok + (bad < 0 ? -1 : 1))
218 {
219 time_t mid = *t = (bad < 0
220 ? bad + ((ok - bad) >> 1)
221 : ok + ((bad - ok) >> 1));
222 if ((r = (*convert) (t, tp)))
223 {
224 tm = *r;
225 ok = mid;
226 }
227 else
228 bad = mid;
229 }
230
231 if (!r && ok)
232 {
233 /* The last conversion attempt failed;
234 revert to the most recent successful attempt. */
235 *t = ok;
236 *tp = tm;
237 r = tp;
238 }
239 }
240
241 return r;
242 }
243
244
245 /* Convert *TP to a time_t value, inverting
246 the monotonic and mostly-unit-linear conversion function CONVERT.
247 Use *OFFSET to keep track of a guess at the offset of the result,
248 compared to what the result would be for UTC without leap seconds.
249 If *OFFSET's guess is correct, only one CONVERT call is needed. */
250 time_t
251 __mktime_internal (tp, convert, offset)
252 struct tm *tp;
253 struct tm *(*convert) __P ((const time_t *, struct tm *));
254 time_t *offset;
255 {
256 time_t t, dt, t0;
257 struct tm tm;
258
259 /* The maximum number of probes (calls to CONVERT) should be enough
260 to handle any combinations of time zone rule changes, solar time,
261 and leap seconds. POSIX.1 prohibits leap seconds, but some hosts
262 have them anyway. */
263 int remaining_probes = 4;
264
265 /* Time requested. Copy it in case CONVERT modifies *TP; this can
266 occur if TP is localtime's returned value and CONVERT is localtime. */
267 int sec = tp->tm_sec;
268 int min = tp->tm_min;
269 int hour = tp->tm_hour;
270 int mday = tp->tm_mday;
271 int mon = tp->tm_mon;
272 int year_requested = tp->tm_year;
273 int isdst = tp->tm_isdst;
274
275 /* Ensure that mon is in range, and set year accordingly. */
276 int mon_remainder = mon % 12;
277 int negative_mon_remainder = mon_remainder < 0;
278 int mon_years = mon / 12 - negative_mon_remainder;
279 int year = year_requested + mon_years;
280
281 /* The other values need not be in range:
282 the remaining code handles minor overflows correctly,
283 assuming int and time_t arithmetic wraps around.
284 Major overflows are caught at the end. */
285
286 /* Calculate day of year from year, month, and day of month.
287 The result need not be in range. */
288 int yday = ((__mon_yday[__isleap (year + TM_YEAR_BASE)]
289 [mon_remainder + 12 * negative_mon_remainder])
290 + mday - 1);
291
292 int sec_requested = sec;
293 #if LEAP_SECONDS_POSSIBLE
294 /* Handle out-of-range seconds specially,
295 since ydhms_tm_diff assumes every minute has 60 seconds. */
296 if (sec < 0)
297 sec = 0;
298 if (59 < sec)
299 sec = 59;
300 #endif
301
302 /* Invert CONVERT by probing. First assume the same offset as last time.
303 Then repeatedly use the error to improve the guess. */
304
305 tm.tm_year = EPOCH_YEAR - TM_YEAR_BASE;
306 tm.tm_yday = tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
307 t0 = ydhms_tm_diff (year, yday, hour, min, sec, &tm);
308
309 for (t = t0 + *offset;
310 (dt = ydhms_tm_diff (year, yday, hour, min, sec,
311 ranged_convert (convert, &t, &tm)));
312 t += dt)
313 if (--remaining_probes == 0)
314 return -1;
315
316 /* Check whether tm.tm_isdst has the requested value, if any. */
317 if (0 <= isdst && 0 <= tm.tm_isdst)
318 {
319 int dst_diff = (isdst != 0) - (tm.tm_isdst != 0);
320 if (dst_diff)
321 {
322 /* Move two hours in the direction indicated by the disagreement,
323 probe some more, and switch to a new time if found.
324 The largest known fallback due to daylight savings is two hours:
325 once, in Newfoundland, 1988-10-30 02:00 -> 00:00. */
326 time_t ot = t - 2 * 60 * 60 * dst_diff;
327 while (--remaining_probes != 0)
328 {
329 struct tm otm;
330 if (! (dt = ydhms_tm_diff (year, yday, hour, min, sec,
331 ranged_convert (convert, &ot, &otm))))
332 {
333 t = ot;
334 tm = otm;
335 break;
336 }
337 if ((ot += dt) == t)
338 break; /* Avoid a redundant probe. */
339 }
340 }
341 }
342
343 *offset = t - t0;
344
345 #if LEAP_SECONDS_POSSIBLE
346 if (sec_requested != tm.tm_sec)
347 {
348 /* Adjust time to reflect the tm_sec requested, not the normalized value.
349 Also, repair any damage from a false match due to a leap second. */
350 t += sec_requested - sec + (sec == 0 && tm.tm_sec == 60);
351 if (! (*convert) (&t, &tm))
352 return -1;
353 }
354 #endif
355
356 if (TIME_T_MAX / INT_MAX / 366 / 24 / 60 / 60 < 3)
357 {
358 /* time_t isn't large enough to rule out overflows in ydhms_tm_diff,
359 so check for major overflows. A gross check suffices,
360 since if t has overflowed, it is off by a multiple of
361 TIME_T_MAX - TIME_T_MIN + 1. So ignore any component of
362 the difference that is bounded by a small value. */
363
364 double dyear = (double) year_requested + mon_years - tm.tm_year;
365 double dday = 366 * dyear + mday;
366 double dsec = 60 * (60 * (24 * dday + hour) + min) + sec_requested;
367
368 if (TIME_T_MAX / 3 - TIME_T_MIN / 3 < (dsec < 0 ? - dsec : dsec))
369 return -1;
370 }
371
372 *tp = tm;
373 return t;
374 }
375
376 #ifdef weak_alias
377 weak_alias (mktime, timelocal)
378 #endif
379 \f
380 #if DEBUG
381
382 static int
383 not_equal_tm (a, b)
384 struct tm *a;
385 struct tm *b;
386 {
387 return ((a->tm_sec ^ b->tm_sec)
388 | (a->tm_min ^ b->tm_min)
389 | (a->tm_hour ^ b->tm_hour)
390 | (a->tm_mday ^ b->tm_mday)
391 | (a->tm_mon ^ b->tm_mon)
392 | (a->tm_year ^ b->tm_year)
393 | (a->tm_mday ^ b->tm_mday)
394 | (a->tm_yday ^ b->tm_yday)
395 | (a->tm_isdst ^ b->tm_isdst));
396 }
397
398 static void
399 print_tm (tp)
400 struct tm *tp;
401 {
402 if (tp)
403 printf ("%04d-%02d-%02d %02d:%02d:%02d yday %03d wday %d isdst %d",
404 tp->tm_year + TM_YEAR_BASE, tp->tm_mon + 1, tp->tm_mday,
405 tp->tm_hour, tp->tm_min, tp->tm_sec,
406 tp->tm_yday, tp->tm_wday, tp->tm_isdst);
407 else
408 printf ("0");
409 }
410
411 static int
412 check_result (tk, tmk, tl, lt)
413 time_t tk;
414 struct tm tmk;
415 time_t tl;
416 struct tm *lt;
417 {
418 if (tk != tl || !lt || not_equal_tm (&tmk, lt))
419 {
420 printf ("mktime (");
421 print_tm (&tmk);
422 printf (")\nyields (");
423 print_tm (lt);
424 printf (") == %ld, should be %ld\n", (long) tl, (long) tk);
425 return 1;
426 }
427
428 return 0;
429 }
430
431 int
432 main (argc, argv)
433 int argc;
434 char **argv;
435 {
436 int status = 0;
437 struct tm tm, tmk, tml;
438 struct tm *lt;
439 time_t tk, tl;
440 char trailer;
441
442 if ((argc == 3 || argc == 4)
443 && (sscanf (argv[1], "%d-%d-%d%c",
444 &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &trailer)
445 == 3)
446 && (sscanf (argv[2], "%d:%d:%d%c",
447 &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &trailer)
448 == 3))
449 {
450 tm.tm_year -= TM_YEAR_BASE;
451 tm.tm_mon--;
452 tm.tm_isdst = argc == 3 ? -1 : atoi (argv[3]);
453 tmk = tm;
454 tl = mktime (&tmk);
455 lt = localtime (&tl);
456 if (lt)
457 {
458 tml = *lt;
459 lt = &tml;
460 }
461 printf ("mktime returns %ld == ", (long) tl);
462 print_tm (&tmk);
463 printf ("\n");
464 status = check_result (tl, tmk, tl, lt);
465 }
466 else if (argc == 4 || (argc == 5 && strcmp (argv[4], "-") == 0))
467 {
468 time_t from = atol (argv[1]);
469 time_t by = atol (argv[2]);
470 time_t to = atol (argv[3]);
471
472 if (argc == 4)
473 for (tl = from; tl <= to; tl += by)
474 {
475 lt = localtime (&tl);
476 if (lt)
477 {
478 tmk = tml = *lt;
479 tk = mktime (&tmk);
480 status |= check_result (tk, tmk, tl, tml);
481 }
482 else
483 {
484 printf ("localtime (%ld) yields 0\n", (long) tl);
485 status = 1;
486 }
487 }
488 else
489 for (tl = from; tl <= to; tl += by)
490 {
491 /* Null benchmark. */
492 lt = localtime (&tl);
493 if (lt)
494 {
495 tmk = tml = *lt;
496 tk = tl;
497 status |= check_result (tk, tmk, tl, tml);
498 }
499 else
500 {
501 printf ("localtime (%ld) yields 0\n", (long) tl);
502 status = 1;
503 }
504 }
505 }
506 else
507 printf ("Usage:\
508 \t%s YYYY-MM-DD HH:MM:SS [ISDST] # Test given time.\n\
509 \t%s FROM BY TO # Test values FROM, FROM+BY, ..., TO.\n\
510 \t%s FROM BY TO - # Do not test those values (for benchmark).\n",
511 argv[0], argv[0], argv[0]);
512
513 return status;
514 }
515
516 #endif /* DEBUG */
517 \f
518 /*
519 Local Variables:
520 compile-command: "gcc -DDEBUG -D__EXTENSIONS__ -DHAVE_LIMITS_H -DHAVE_LOCALTIME_R -DSTDC_HEADERS -Wall -W -O -g mktime.c -o mktime"
521 End:
522 */