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