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