update from main archive 970124
[glibc.git] / time / mktime.c
blobfd242b15450036801ac467be1a9a39a2af9d0702
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 /* Assume that leap seconds are possible, unless told otherwise.
29 If the host has a `zic' command with a `-L leapsecondfilename' option,
30 then it supports leap seconds; otherwise it probably doesn't. */
31 #ifndef LEAP_SECONDS_POSSIBLE
32 #define LEAP_SECONDS_POSSIBLE 1
33 #endif
35 #include <sys/types.h> /* Some systems define `time_t' here. */
36 #include <time.h>
38 #if __STDC__ || __GNU_LIBRARY__ || STDC_HEADERS
39 #include <limits.h>
40 #endif
42 #if DEBUG
43 #include <stdio.h>
44 #if __STDC__ || __GNU_LIBRARY__ || STDC_HEADERS
45 #include <stdlib.h>
46 #endif
47 /* Make it work even if the system's libc has its own mktime routine. */
48 #define mktime my_mktime
49 #endif /* DEBUG */
51 #ifndef __P
52 #if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
53 #define __P(args) args
54 #else
55 #define __P(args) ()
56 #endif /* GCC. */
57 #endif /* Not __P. */
59 #ifndef CHAR_BIT
60 #define CHAR_BIT 8
61 #endif
63 #ifndef INT_MIN
64 #define INT_MIN (~0 << (sizeof (int) * CHAR_BIT - 1))
65 #endif
66 #ifndef INT_MAX
67 #define INT_MAX (~0 - INT_MIN)
68 #endif
70 #ifndef TIME_T_MIN
71 #define TIME_T_MIN (0 < (time_t) -1 ? (time_t) 0 \
72 : ~ (time_t) 0 << (sizeof (time_t) * CHAR_BIT - 1))
73 #endif
74 #ifndef TIME_T_MAX
75 #define TIME_T_MAX (~ (time_t) 0 - TIME_T_MIN)
76 #endif
78 #define TM_YEAR_BASE 1900
79 #define EPOCH_YEAR 1970
81 #ifndef __isleap
82 /* Nonzero if YEAR is a leap year (every 4 years,
83 except every 100th isn't, and every 400th is). */
84 #define __isleap(year) \
85 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
86 #endif
88 /* How many days come before each month (0-12). */
89 const unsigned short int __mon_yday[2][13] =
91 /* Normal years. */
92 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
93 /* Leap years. */
94 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
97 static time_t ydhms_tm_diff __P ((int, int, int, int, int, const struct tm *));
98 time_t __mktime_internal __P ((struct tm *,
99 struct tm *(*) (const time_t *, struct tm *),
100 time_t *));
103 #if ! HAVE_LOCALTIME_R && ! defined (localtime_r)
104 #ifdef _LIBC
105 #define localtime_r __localtime_r
106 #else
107 /* Approximate localtime_r as best we can in its absence. */
108 #define localtime_r my_localtime_r
109 static struct tm *localtime_r __P ((const time_t *, struct tm *));
110 static struct tm *
111 localtime_r (t, tp)
112 const time_t *t;
113 struct tm *tp;
115 struct tm *l = localtime (t);
116 if (! l)
117 return 0;
118 *tp = *l;
119 return tp;
121 #endif /* ! _LIBC */
122 #endif /* ! HAVE_LOCALTIME_R && ! defined (localtime_r) */
125 /* Yield the difference between (YEAR-YDAY HOUR:MIN:SEC) and (*TP),
126 measured in seconds, ignoring leap seconds.
127 YEAR uses the same numbering as TM->tm_year.
128 All values are in range, except possibly YEAR.
129 If overflow occurs, yield the low order bits of the correct answer. */
130 static time_t
131 ydhms_tm_diff (year, yday, hour, min, sec, tp)
132 int year, yday, hour, min, sec;
133 const struct tm *tp;
135 /* Compute intervening leap days correctly even if year is negative.
136 Take care to avoid int overflow. time_t overflow is OK, since
137 only the low order bits of the correct time_t answer are needed.
138 Don't convert to time_t until after all divisions are done, since
139 time_t might be unsigned. */
140 int a4 = (year >> 2) + (TM_YEAR_BASE >> 2) - ! (year & 3);
141 int b4 = (tp->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (tp->tm_year & 3);
142 int a100 = a4 / 25 - (a4 % 25 < 0);
143 int b100 = b4 / 25 - (b4 % 25 < 0);
144 int a400 = a100 >> 2;
145 int b400 = b100 >> 2;
146 int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
147 time_t years = year - (time_t) tp->tm_year;
148 time_t days = (365 * years + intervening_leap_days
149 + (yday - tp->tm_yday));
150 return (60 * (60 * (24 * days + (hour - tp->tm_hour))
151 + (min - tp->tm_min))
152 + (sec - tp->tm_sec));
156 static time_t localtime_offset;
158 /* Convert *TP to a time_t value. */
159 time_t
160 mktime (tp)
161 struct tm *tp;
163 #ifdef _LIBC
164 /* POSIX.1 8.1.1 requires that whenever mktime() is called, the
165 time zone names contained in the external variable `tzname' shall
166 be set as if the tzset() function had been called. */
167 __tzset ();
168 #endif
170 return __mktime_internal (tp, localtime_r, &localtime_offset);
173 /* Convert *TP to a time_t value, inverting
174 the monotonic and mostly-unit-linear conversion function CONVERT.
175 Use *OFFSET to keep track of a guess at the offset of the result,
176 compared to what the result would be for UTC without leap seconds.
177 If *OFFSET's guess is correct, only one CONVERT call is needed. */
178 time_t
179 __mktime_internal (tp, convert, offset)
180 struct tm *tp;
181 struct tm *(*convert) __P ((const time_t *, struct tm *));
182 time_t *offset;
184 time_t t, dt, t0;
185 struct tm tm;
187 /* The maximum number of probes (calls to CONVERT) should be enough
188 to handle any combinations of time zone rule changes, solar time,
189 and leap seconds. Posix.1 prohibits leap seconds, but some hosts
190 have them anyway. */
191 int remaining_probes = 4;
193 /* Time requested. Copy it in case CONVERT modifies *TP; this can
194 occur if TP is localtime's returned value and CONVERT is localtime. */
195 int sec = tp->tm_sec;
196 int min = tp->tm_min;
197 int hour = tp->tm_hour;
198 int mday = tp->tm_mday;
199 int mon = tp->tm_mon;
200 int year_requested = tp->tm_year;
201 int isdst = tp->tm_isdst;
203 /* Ensure that mon is in range, and set year accordingly. */
204 int mon_remainder = mon % 12;
205 int negative_mon_remainder = mon_remainder < 0;
206 int mon_years = mon / 12 - negative_mon_remainder;
207 int year = year_requested + mon_years;
209 /* The other values need not be in range:
210 the remaining code handles minor overflows correctly,
211 assuming int and time_t arithmetic wraps around.
212 Major overflows are caught at the end. */
214 /* Calculate day of year from year, month, and day of month.
215 The result need not be in range. */
216 int yday = ((__mon_yday[__isleap (year + TM_YEAR_BASE)]
217 [mon_remainder + 12 * negative_mon_remainder])
218 + mday - 1);
220 #if LEAP_SECONDS_POSSIBLE
221 /* Handle out-of-range seconds specially,
222 since ydhms_tm_diff assumes every minute has 60 seconds. */
223 int sec_requested = sec;
224 if (sec < 0)
225 sec = 0;
226 if (59 < sec)
227 sec = 59;
228 #endif
230 /* Invert CONVERT by probing. First assume the same offset as last time.
231 Then repeatedly use the error to improve the guess. */
233 tm.tm_year = EPOCH_YEAR - TM_YEAR_BASE;
234 tm.tm_yday = tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
235 t0 = ydhms_tm_diff (year, yday, hour, min, sec, &tm);
237 for (t = t0 + *offset;
238 (dt = ydhms_tm_diff (year, yday, hour, min, sec, (*convert) (&t, &tm)));
239 t += dt)
240 if (--remaining_probes == 0)
241 return -1;
243 /* Check whether tm.tm_isdst has the requested value, if any. */
244 if (0 <= isdst && 0 <= tm.tm_isdst)
246 int dst_diff = (isdst != 0) - (tm.tm_isdst != 0);
247 if (dst_diff)
249 /* Move two hours in the direction indicated by the disagreement,
250 probe some more, and switch to a new time if found.
251 The largest known fallback due to daylight savings is two hours:
252 once, in Newfoundland, 1988-10-30 02:00 -> 00:00. */
253 time_t ot = t - 2 * 60 * 60 * dst_diff;
254 while (--remaining_probes != 0)
256 struct tm otm;
257 if (! (dt = ydhms_tm_diff (year, yday, hour, min, sec,
258 (*convert) (&ot, &otm))))
260 t = ot;
261 tm = otm;
262 break;
264 if ((ot += dt) == t)
265 break; /* Avoid a redundant probe. */
270 *offset = t - t0;
272 #if LEAP_SECONDS_POSSIBLE
273 if (sec_requested != tm.tm_sec)
275 /* Adjust time to reflect the tm_sec requested, not the normalized value.
276 Also, repair any damage from a false match due to a leap second. */
277 t += sec_requested - sec + (sec == 0 && tm.tm_sec == 60);
278 (*convert) (&t, &tm);
280 #endif
282 if (TIME_T_MAX / INT_MAX / 366 / 24 / 60 / 60 < 3)
284 /* time_t isn't large enough to rule out overflows in ydhms_tm_diff,
285 so check for major overflows. A gross check suffices,
286 since if t has overflowed, it is off by a multiple of
287 TIME_T_MAX - TIME_T_MIN + 1. So ignore any component of
288 the difference that is bounded by a small value. */
290 double dyear = (double) year_requested + mon_years - tm.tm_year;
291 double dday = 366 * dyear + mday;
292 double dsec = 60 * (60 * (24 * dday + hour) + min) + sec_requested;
294 if (TIME_T_MAX / 3 - TIME_T_MIN / 3 < (dsec < 0 ? - dsec : dsec))
295 return -1;
298 *tp = tm;
299 return t;
302 #ifdef weak_alias
303 weak_alias (mktime, timelocal)
304 #endif
306 #if DEBUG
308 static int
309 not_equal_tm (a, b)
310 struct tm *a;
311 struct tm *b;
313 return ((a->tm_sec ^ b->tm_sec)
314 | (a->tm_min ^ b->tm_min)
315 | (a->tm_hour ^ b->tm_hour)
316 | (a->tm_mday ^ b->tm_mday)
317 | (a->tm_mon ^ b->tm_mon)
318 | (a->tm_year ^ b->tm_year)
319 | (a->tm_mday ^ b->tm_mday)
320 | (a->tm_yday ^ b->tm_yday)
321 | (a->tm_isdst ^ b->tm_isdst));
324 static void
325 print_tm (tp)
326 struct tm *tp;
328 printf ("%04d-%02d-%02d %02d:%02d:%02d yday %03d wday %d isdst %d",
329 tp->tm_year + TM_YEAR_BASE, tp->tm_mon + 1, tp->tm_mday,
330 tp->tm_hour, tp->tm_min, tp->tm_sec,
331 tp->tm_yday, tp->tm_wday, tp->tm_isdst);
334 static int
335 check_result (tk, tmk, tl, tml)
336 time_t tk;
337 struct tm tmk;
338 time_t tl;
339 struct tm tml;
341 if (tk != tl || not_equal_tm (&tmk, &tml))
343 printf ("mktime (");
344 print_tm (&tmk);
345 printf (")\nyields (");
346 print_tm (&tml);
347 printf (") == %ld, should be %ld\n", (long) tl, (long) tk);
348 return 1;
351 return 0;
355 main (argc, argv)
356 int argc;
357 char **argv;
359 int status = 0;
360 struct tm tm, tmk, tml;
361 time_t tk, tl;
362 char trailer;
364 if ((argc == 3 || argc == 4)
365 && (sscanf (argv[1], "%d-%d-%d%c",
366 &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &trailer)
367 == 3)
368 && (sscanf (argv[2], "%d:%d:%d%c",
369 &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &trailer)
370 == 3))
372 tm.tm_year -= TM_YEAR_BASE;
373 tm.tm_mon--;
374 tm.tm_isdst = argc == 3 ? -1 : atoi (argv[3]);
375 tmk = tm;
376 tl = mktime (&tmk);
377 tml = *localtime (&tl);
378 printf ("mktime returns %ld == ", (long) tl);
379 print_tm (&tmk);
380 printf ("\n");
381 status = check_result (tl, tmk, tl, tml);
383 else if (argc == 4 || (argc == 5 && strcmp (argv[4], "-") == 0))
385 time_t from = atol (argv[1]);
386 time_t by = atol (argv[2]);
387 time_t to = atol (argv[3]);
389 if (argc == 4)
390 for (tl = from; tl <= to; tl += by)
392 tml = *localtime (&tl);
393 tmk = tml;
394 tk = mktime (&tmk);
395 status |= check_result (tk, tmk, tl, tml);
397 else
398 for (tl = from; tl <= to; tl += by)
400 /* Null benchmark. */
401 tml = *localtime (&tl);
402 tmk = tml;
403 tk = tl;
404 status |= check_result (tk, tmk, tl, tml);
407 else
408 printf ("Usage:\
409 \t%s YYYY-MM-DD HH:MM:SS [ISDST] # Test given time.\n\
410 \t%s FROM BY TO # Test values FROM, FROM+BY, ..., TO.\n\
411 \t%s FROM BY TO - # Do not test those values (for benchmark).\n",
412 argv[0], argv[0], argv[0]);
414 return status;
417 #endif /* DEBUG */
420 Local Variables:
421 compile-command: "gcc -DDEBUG=1 -Wall -O -g mktime.c -o mktime"
422 End: