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