]> git.ipfire.org Git - thirdparty/glibc.git/blame - time/mktime.c
Regenerated: autoconf sysdeps/generic/configure.in
[thirdparty/glibc.git] / time / mktime.c
CommitLineData
3f80a33b 1/* Convert a `struct tm' to a time_t value.
4a10c7fe 2 Copyright (C) 1993-1999, 2002 Free Software Foundation, Inc.
5290baf0 3 This file is part of the GNU C Library.
80fd7387 4 Contributed by Paul Eggert (eggert@twinsun.com).
28f540f4 5
5290baf0 6 The GNU C Library is free software; you can redistribute it and/or
41bdb6e2
AJ
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
28f540f4 10
5290baf0
UD
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41bdb6e2 14 Lesser General Public License for more details.
28f540f4 15
41bdb6e2
AJ
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA. */
28f540f4
RM
20
21/* Define this to have a standalone program to test this implementation of
22 mktime. */
80fd7387 23/* #define DEBUG 1 */
28f540f4
RM
24
25#ifdef HAVE_CONFIG_H
9c2322bc 26# include <config.h>
28f540f4
RM
27#endif
28
c0e45674
UD
29#ifdef _LIBC
30# define HAVE_LIMITS_H 1
c0e45674
UD
31# define STDC_HEADERS 1
32#endif
33
80fd7387
RM
34/* Assume that leap seconds are possible, unless told otherwise.
35 If the host has a `zic' command with a `-L leapsecondfilename' option,
36 then it supports leap seconds; otherwise it probably doesn't. */
37#ifndef LEAP_SECONDS_POSSIBLE
9c2322bc 38# define LEAP_SECONDS_POSSIBLE 1
80fd7387
RM
39#endif
40
28f540f4
RM
41#include <sys/types.h> /* Some systems define `time_t' here. */
42#include <time.h>
43
c0e45674 44#if HAVE_LIMITS_H
9c2322bc 45# include <limits.h>
80fd7387 46#endif
28f540f4 47
80fd7387 48#if DEBUG
9c2322bc
UD
49# include <stdio.h>
50# if STDC_HEADERS
51# include <stdlib.h>
b5ef404e 52# include <string.h>
9c2322bc 53# endif
80fd7387 54/* Make it work even if the system's libc has its own mktime routine. */
9c2322bc 55# define mktime my_mktime
80fd7387 56#endif /* DEBUG */
28f540f4
RM
57
58#ifndef __P
c7a9f249 59# if defined __GNUC__ || (defined __STDC__ && __STDC__)
9c2322bc
UD
60# define __P(args) args
61# else
62# define __P(args) ()
63# endif /* GCC. */
28f540f4
RM
64#endif /* Not __P. */
65
80fd7387 66#ifndef CHAR_BIT
9c2322bc 67# define CHAR_BIT 8
28f540f4
RM
68#endif
69
1dfee75f
UD
70/* The extra casts work around common compiler bugs. */
71#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
72/* The outer cast is needed to work around a bug in Cray C 5.0.3.0.
73 It is necessary at least when t == time_t. */
74#define TYPE_MINIMUM(t) ((t) (TYPE_SIGNED (t) \
75 ? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) : (t) 0))
36fafd9c 76#define TYPE_MAXIMUM(t) ((t) (~ (t) 0 - TYPE_MINIMUM (t)))
1dfee75f 77
80fd7387 78#ifndef INT_MIN
1dfee75f 79# define INT_MIN TYPE_MINIMUM (int)
28f540f4 80#endif
80fd7387 81#ifndef INT_MAX
1dfee75f 82# define INT_MAX TYPE_MAXIMUM (int)
28f540f4 83#endif
28f540f4 84
80fd7387 85#ifndef TIME_T_MIN
1dfee75f 86# define TIME_T_MIN TYPE_MINIMUM (time_t)
28f540f4 87#endif
80fd7387 88#ifndef TIME_T_MAX
1dfee75f 89# define TIME_T_MAX TYPE_MAXIMUM (time_t)
28f540f4 90#endif
28f540f4 91
80fd7387
RM
92#define TM_YEAR_BASE 1900
93#define EPOCH_YEAR 1970
28f540f4 94
80fd7387
RM
95#ifndef __isleap
96/* Nonzero if YEAR is a leap year (every 4 years,
97 except every 100th isn't, and every 400th is). */
9c2322bc 98# define __isleap(year) \
80fd7387 99 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
28f540f4 100#endif
28f540f4 101
80fd7387
RM
102/* How many days come before each month (0-12). */
103const unsigned short int __mon_yday[2][13] =
104 {
105 /* Normal years. */
106 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
107 /* Leap years. */
108 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
109 };
28f540f4 110
28f540f4 111
c2216480 112#ifdef _LIBC
05f732b3 113# define my_mktime_localtime_r __localtime_r
c2216480 114#else
05f732b3
UD
115/* If we're a mktime substitute in a GNU program, then prefer
116 localtime to localtime_r, since many localtime_r implementations
117 are buggy. */
c2216480 118static struct tm *
eda78eec 119my_mktime_localtime_r (const time_t *t, struct tm *tp)
80fd7387 120{
c2216480
RM
121 struct tm *l = localtime (t);
122 if (! l)
3f33a4ce 123 return 0;
c2216480
RM
124 *tp = *l;
125 return tp;
126}
c0e45674 127#endif /* ! _LIBC */
c2216480 128
80fd7387
RM
129
130/* Yield the difference between (YEAR-YDAY HOUR:MIN:SEC) and (*TP),
131 measured in seconds, ignoring leap seconds.
132 YEAR uses the same numbering as TM->tm_year.
133 All values are in range, except possibly YEAR.
fe0ec73e 134 If TP is null, return a nonzero value.
80fd7387
RM
135 If overflow occurs, yield the low order bits of the correct answer. */
136static time_t
eda78eec
UD
137ydhms_tm_diff (int year, int yday, int hour, int min, int sec,
138 const struct tm *tp)
80fd7387 139{
fe0ec73e
UD
140 if (!tp)
141 return 1;
142 else
143 {
144 /* Compute intervening leap days correctly even if year is negative.
145 Take care to avoid int overflow. time_t overflow is OK, since
146 only the low order bits of the correct time_t answer are needed.
147 Don't convert to time_t until after all divisions are done, since
148 time_t might be unsigned. */
149 int a4 = (year >> 2) + (TM_YEAR_BASE >> 2) - ! (year & 3);
150 int b4 = (tp->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (tp->tm_year & 3);
151 int a100 = a4 / 25 - (a4 % 25 < 0);
152 int b100 = b4 / 25 - (b4 % 25 < 0);
153 int a400 = a100 >> 2;
154 int b400 = b100 >> 2;
155 int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
156 time_t years = year - (time_t) tp->tm_year;
157 time_t days = (365 * years + intervening_leap_days
158 + (yday - tp->tm_yday));
159 return (60 * (60 * (24 * days + (hour - tp->tm_hour))
160 + (min - tp->tm_min))
161 + (sec - tp->tm_sec));
162 }
80fd7387
RM
163}
164
fe0ec73e
UD
165/* Use CONVERT to convert *T to a broken down time in *TP.
166 If *T is out of range for conversion, adjust it so that
167 it is the nearest in-range value and then convert that. */
168static struct tm *
eda78eec
UD
169ranged_convert (struct tm *(*convert) (const time_t *, struct tm *),
170 time_t *t, struct tm *tp)
fe0ec73e
UD
171{
172 struct tm *r;
173
174 if (! (r = (*convert) (t, tp)) && *t)
175 {
176 time_t bad = *t;
177 time_t ok = 0;
178 struct tm tm;
179
180 /* BAD is a known unconvertible time_t, and OK is a known good one.
181 Use binary search to narrow the range between BAD and OK until
182 they differ by 1. */
183 while (bad != ok + (bad < 0 ? -1 : 1))
184 {
185 time_t mid = *t = (bad < 0
186 ? bad + ((ok - bad) >> 1)
187 : ok + ((bad - ok) >> 1));
188 if ((r = (*convert) (t, tp)))
189 {
190 tm = *r;
191 ok = mid;
192 }
193 else
194 bad = mid;
195 }
196
197 if (!r && ok)
198 {
199 /* The last conversion attempt failed;
200 revert to the most recent successful attempt. */
201 *t = ok;
202 *tp = tm;
203 r = tp;
204 }
205 }
206
207 return r;
208}
209
210
80fd7387
RM
211/* Convert *TP to a time_t value, inverting
212 the monotonic and mostly-unit-linear conversion function CONVERT.
213 Use *OFFSET to keep track of a guess at the offset of the result,
214 compared to what the result would be for UTC without leap seconds.
215 If *OFFSET's guess is correct, only one CONVERT call is needed. */
216time_t
eda78eec
UD
217__mktime_internal (struct tm *tp,
218 struct tm *(*convert) (const time_t *, struct tm *),
219 time_t *offset)
28f540f4 220{
25b3b17b 221 time_t t, dt, t0, t1, t2;
80fd7387
RM
222 struct tm tm;
223
224 /* The maximum number of probes (calls to CONVERT) should be enough
225 to handle any combinations of time zone rule changes, solar time,
25b3b17b
UD
226 leap seconds, and oscillations around a spring-forward gap.
227 POSIX.1 prohibits leap seconds, but some hosts have them anyway. */
228 int remaining_probes = 6;
80fd7387
RM
229
230 /* Time requested. Copy it in case CONVERT modifies *TP; this can
231 occur if TP is localtime's returned value and CONVERT is localtime. */
232 int sec = tp->tm_sec;
233 int min = tp->tm_min;
234 int hour = tp->tm_hour;
235 int mday = tp->tm_mday;
236 int mon = tp->tm_mon;
237 int year_requested = tp->tm_year;
238 int isdst = tp->tm_isdst;
239
b5ef404e
UD
240 /* 1 if the previous probe was DST. */
241 int dst2;
242
80fd7387
RM
243 /* Ensure that mon is in range, and set year accordingly. */
244 int mon_remainder = mon % 12;
245 int negative_mon_remainder = mon_remainder < 0;
246 int mon_years = mon / 12 - negative_mon_remainder;
247 int year = year_requested + mon_years;
248
4a10c7fe 249 /* The other values need not be in range:
80fd7387
RM
250 the remaining code handles minor overflows correctly,
251 assuming int and time_t arithmetic wraps around.
252 Major overflows are caught at the end. */
253
254 /* Calculate day of year from year, month, and day of month.
255 The result need not be in range. */
256 int yday = ((__mon_yday[__isleap (year + TM_YEAR_BASE)]
257 [mon_remainder + 12 * negative_mon_remainder])
258 + mday - 1);
259
9a0a462c 260 int sec_requested = sec;
55544141 261
78575a84
UD
262 /* Only years after 1970 are defined.
263 If year is 69, it might still be representable due to
264 timezone differences. */
265 if (year < 69)
55544141
UD
266 return -1;
267
80fd7387
RM
268#if LEAP_SECONDS_POSSIBLE
269 /* Handle out-of-range seconds specially,
270 since ydhms_tm_diff assumes every minute has 60 seconds. */
80fd7387
RM
271 if (sec < 0)
272 sec = 0;
273 if (59 < sec)
274 sec = 59;
275#endif
276
277 /* Invert CONVERT by probing. First assume the same offset as last time.
278 Then repeatedly use the error to improve the guess. */
279
280 tm.tm_year = EPOCH_YEAR - TM_YEAR_BASE;
281 tm.tm_yday = tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
282 t0 = ydhms_tm_diff (year, yday, hour, min, sec, &tm);
28f540f4 283
b5ef404e 284 for (t = t1 = t2 = t0 + *offset, dst2 = 0;
fe0ec73e
UD
285 (dt = ydhms_tm_diff (year, yday, hour, min, sec,
286 ranged_convert (convert, &t, &tm)));
b5ef404e 287 t1 = t2, t2 = t, t += dt, dst2 = tm.tm_isdst != 0)
25b3b17b 288 if (t == t1 && t != t2
b5ef404e
UD
289 && (tm.tm_isdst < 0
290 || (isdst < 0
291 ? dst2 <= (tm.tm_isdst != 0)
292 : (isdst != 0) != (tm.tm_isdst != 0))))
25b3b17b
UD
293 /* We can't possibly find a match, as we are oscillating
294 between two values. The requested time probably falls
295 within a spring-forward gap of size DT. Follow the common
296 practice in this case, which is to return a time that is DT
297 away from the requested time, preferring a time whose
b5ef404e
UD
298 tm_isdst differs from the requested value. (If no tm_isdst
299 was requested and only one of the two values has a nonzero
300 tm_isdst, prefer that value.) In practice, this is more
301 useful than returning -1. */
25b3b17b
UD
302 break;
303 else if (--remaining_probes == 0)
80fd7387
RM
304 return -1;
305
25b3b17b
UD
306 /* If we have a match, check whether tm.tm_isdst has the requested
307 value, if any. */
c0016081 308 if (dt == 0 && isdst != tm.tm_isdst && 0 <= isdst && 0 <= tm.tm_isdst)
80fd7387 309 {
c0016081
UD
310 /* tm.tm_isdst has the wrong value. Look for a neighboring
311 time with the right value, and use its UTC offset.
312 Heuristic: probe the previous three calendar quarters (approximately),
313 looking for the desired isdst. This isn't perfect,
314 but it's good enough in practice. */
315 int quarter = 7889238; /* seconds per average 1/4 Gregorian year */
316 int i;
317
318 /* If we're too close to the time_t limit, look in future quarters. */
319 if (t < TIME_T_MIN + 3 * quarter)
320 quarter = -quarter;
321
322 for (i = 1; i <= 3; i++)
28f540f4 323 {
c0016081
UD
324 time_t ot = t - i * quarter;
325 struct tm otm;
326 ranged_convert (convert, &ot, &otm);
327 if (otm.tm_isdst == isdst)
80fd7387 328 {
c0016081
UD
329 /* We found the desired tm_isdst.
330 Extrapolate back to the desired time. */
331 t = ot + ydhms_tm_diff (year, yday, hour, min, sec, &otm);
332 ranged_convert (convert, &t, &tm);
333 break;
80fd7387 334 }
28f540f4 335 }
80fd7387 336 }
28f540f4 337
80fd7387
RM
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);
fe0ec73e
UD
346 if (! (*convert) (&t, &tm))
347 return -1;
28f540f4 348 }
80fd7387
RM
349#endif
350
351 if (TIME_T_MAX / INT_MAX / 366 / 24 / 60 / 60 < 3)
28f540f4 352 {
80fd7387
RM
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
1dfee75f
UD
363 /* On Irix4.0.5 cc, dividing TIME_T_MIN by 3 does not produce
364 correct results, ie., it erroneously gives a positive value
365 of 715827882. Setting a variable first then doing math on it
366 seems to work. (ghazi@caip.rutgers.edu) */
367
368 const time_t time_t_max = TIME_T_MAX;
369 const time_t time_t_min = TIME_T_MIN;
370
371 if (time_t_max / 3 - time_t_min / 3 < (dsec < 0 ? - dsec : dsec))
80fd7387 372 return -1;
28f540f4 373 }
80fd7387 374
78575a84
UD
375 if (year == 69)
376 {
377 /* If year was 69, need to check whether the time was representable
378 or not. */
379 if (t < 0 || t > 2 * 24 * 60 * 60)
380 return -1;
381 }
382
80fd7387
RM
383 *tp = tm;
384 return t;
385}
386
eda78eec
UD
387
388static time_t localtime_offset;
389
390/* Convert *TP to a time_t value. */
391time_t
392mktime (tp)
393 struct tm *tp;
394{
395#ifdef _LIBC
396 /* POSIX.1 8.1.1 requires that whenever mktime() is called, the
397 time zone names contained in the external variable `tzname' shall
398 be set as if the tzset() function had been called. */
399 __tzset ();
400#endif
401
402 return __mktime_internal (tp, my_mktime_localtime_r, &localtime_offset);
403}
404
80fd7387
RM
405#ifdef weak_alias
406weak_alias (mktime, timelocal)
28f540f4 407#endif
c5598d47
RM
408
409#ifdef _LIBC
410libc_hidden_def (mktime)
411libc_hidden_weak (timelocal)
412#endif
80fd7387
RM
413\f
414#if DEBUG
28f540f4 415
80fd7387
RM
416static int
417not_equal_tm (a, b)
418 struct tm *a;
419 struct tm *b;
420{
421 return ((a->tm_sec ^ b->tm_sec)
422 | (a->tm_min ^ b->tm_min)
423 | (a->tm_hour ^ b->tm_hour)
424 | (a->tm_mday ^ b->tm_mday)
425 | (a->tm_mon ^ b->tm_mon)
426 | (a->tm_year ^ b->tm_year)
427 | (a->tm_mday ^ b->tm_mday)
428 | (a->tm_yday ^ b->tm_yday)
429 | (a->tm_isdst ^ b->tm_isdst));
430}
28f540f4 431
80fd7387
RM
432static void
433print_tm (tp)
434 struct tm *tp;
435{
fe0ec73e
UD
436 if (tp)
437 printf ("%04d-%02d-%02d %02d:%02d:%02d yday %03d wday %d isdst %d",
438 tp->tm_year + TM_YEAR_BASE, tp->tm_mon + 1, tp->tm_mday,
439 tp->tm_hour, tp->tm_min, tp->tm_sec,
440 tp->tm_yday, tp->tm_wday, tp->tm_isdst);
441 else
442 printf ("0");
80fd7387 443}
28f540f4 444
80fd7387 445static int
fe0ec73e 446check_result (tk, tmk, tl, lt)
80fd7387
RM
447 time_t tk;
448 struct tm tmk;
449 time_t tl;
fe0ec73e 450 struct tm *lt;
80fd7387 451{
fe0ec73e 452 if (tk != tl || !lt || not_equal_tm (&tmk, lt))
80fd7387
RM
453 {
454 printf ("mktime (");
455 print_tm (&tmk);
456 printf (")\nyields (");
fe0ec73e 457 print_tm (lt);
80fd7387
RM
458 printf (") == %ld, should be %ld\n", (long) tl, (long) tk);
459 return 1;
460 }
461
462 return 0;
463}
28f540f4 464
80fd7387
RM
465int
466main (argc, argv)
467 int argc;
468 char **argv;
469{
470 int status = 0;
471 struct tm tm, tmk, tml;
fe0ec73e 472 struct tm *lt;
80fd7387
RM
473 time_t tk, tl;
474 char trailer;
475
476 if ((argc == 3 || argc == 4)
477 && (sscanf (argv[1], "%d-%d-%d%c",
478 &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &trailer)
479 == 3)
480 && (sscanf (argv[2], "%d:%d:%d%c",
481 &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &trailer)
482 == 3))
483 {
484 tm.tm_year -= TM_YEAR_BASE;
485 tm.tm_mon--;
486 tm.tm_isdst = argc == 3 ? -1 : atoi (argv[3]);
487 tmk = tm;
488 tl = mktime (&tmk);
fe0ec73e
UD
489 lt = localtime (&tl);
490 if (lt)
491 {
492 tml = *lt;
493 lt = &tml;
494 }
80fd7387
RM
495 printf ("mktime returns %ld == ", (long) tl);
496 print_tm (&tmk);
497 printf ("\n");
fe0ec73e 498 status = check_result (tl, tmk, tl, lt);
80fd7387
RM
499 }
500 else if (argc == 4 || (argc == 5 && strcmp (argv[4], "-") == 0))
501 {
502 time_t from = atol (argv[1]);
503 time_t by = atol (argv[2]);
504 time_t to = atol (argv[3]);
28f540f4 505
80fd7387
RM
506 if (argc == 4)
507 for (tl = from; tl <= to; tl += by)
508 {
fe0ec73e
UD
509 lt = localtime (&tl);
510 if (lt)
511 {
512 tmk = tml = *lt;
513 tk = mktime (&tmk);
514 status |= check_result (tk, tmk, tl, tml);
515 }
516 else
517 {
518 printf ("localtime (%ld) yields 0\n", (long) tl);
519 status = 1;
520 }
80fd7387
RM
521 }
522 else
523 for (tl = from; tl <= to; tl += by)
524 {
525 /* Null benchmark. */
fe0ec73e
UD
526 lt = localtime (&tl);
527 if (lt)
528 {
529 tmk = tml = *lt;
530 tk = tl;
531 status |= check_result (tk, tmk, tl, tml);
532 }
533 else
534 {
535 printf ("localtime (%ld) yields 0\n", (long) tl);
536 status = 1;
537 }
80fd7387
RM
538 }
539 }
540 else
541 printf ("Usage:\
542\t%s YYYY-MM-DD HH:MM:SS [ISDST] # Test given time.\n\
543\t%s FROM BY TO # Test values FROM, FROM+BY, ..., TO.\n\
544\t%s FROM BY TO - # Do not test those values (for benchmark).\n",
545 argv[0], argv[0], argv[0]);
546
547 return status;
28f540f4 548}
28f540f4 549
80fd7387 550#endif /* DEBUG */
28f540f4
RM
551\f
552/*
553Local Variables:
05f732b3 554compile-command: "gcc -DDEBUG -DHAVE_LIMITS_H -DSTDC_HEADERS -Wall -W -O -g mktime.c -o mktime"
28f540f4
RM
555End:
556*/