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