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