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