update from main archive 970118
[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 /* Assume that leap seconds are possible, unless told otherwise.
29    If the host has a `zic' command with a `-L leapsecondfilename' option,
30    then it supports leap seconds; otherwise it probably doesn't.  */
31 #ifndef LEAP_SECONDS_POSSIBLE
32 #define LEAP_SECONDS_POSSIBLE 1
33 #endif
34
35 #include <sys/types.h>          /* Some systems define `time_t' here.  */
36 #include <time.h>
37
38 #if __STDC__ || __GNU_LIBRARY__ || STDC_HEADERS
39 #include <limits.h>
40 #endif
41
42 #if DEBUG
43 #include <stdio.h>
44 #if __STDC__ || __GNU_LIBRARY__ || STDC_HEADERS
45 #include <stdlib.h>
46 #endif
47 /* Make it work even if the system's libc has its own mktime routine.  */
48 #define mktime my_mktime
49 #endif /* DEBUG */
50
51 #ifndef __P
52 #if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
53 #define __P(args) args
54 #else
55 #define __P(args) ()
56 #endif  /* GCC.  */
57 #endif  /* Not __P.  */
58
59 #ifndef CHAR_BIT
60 #define CHAR_BIT 8
61 #endif
62
63 #ifndef INT_MIN
64 #define INT_MIN (~0 << (sizeof (int) * CHAR_BIT - 1))
65 #endif
66 #ifndef INT_MAX
67 #define INT_MAX (~0 - INT_MIN)
68 #endif
69
70 #ifndef TIME_T_MIN
71 #define TIME_T_MIN (0 < (time_t) -1 ? (time_t) 0 \
72                     : ~ (time_t) 0 << (sizeof (time_t) * CHAR_BIT - 1))
73 #endif
74 #ifndef TIME_T_MAX
75 #define TIME_T_MAX (~ (time_t) 0 - TIME_T_MIN)
76 #endif
77
78 #define TM_YEAR_BASE 1900
79 #define EPOCH_YEAR 1970
80
81 #ifndef __isleap
82 /* Nonzero if YEAR is a leap year (every 4 years,
83    except every 100th isn't, and every 400th is).  */
84 #define __isleap(year)  \
85   ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
86 #endif
87
88 /* Prototype for the internal function to get information based on TZ.  */
89 extern void __tzset_internal __P ((int always));
90
91 /* How many days come before each month (0-12).  */
92 const unsigned short int __mon_yday[2][13] =
93   {
94     /* Normal years.  */
95     { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
96     /* Leap years.  */
97     { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
98   };
99
100 static time_t ydhms_tm_diff __P ((int, int, int, int, int, const struct tm *));
101 time_t __mktime_internal __P ((struct tm *,
102                                struct tm *(*) (const time_t *, struct tm *),
103                                time_t *));
104
105
106 #if ! HAVE_LOCALTIME_R && ! defined (localtime_r)
107 #ifdef _LIBC
108 #define localtime_r __localtime_r
109 #else
110 /* Approximate localtime_r as best we can in its absence.  */
111 #define localtime_r my_localtime_r
112 static struct tm *localtime_r __P ((const time_t *, struct tm *));
113 static struct tm *
114 localtime_r (t, tp)
115      const time_t *t;
116      struct tm *tp;
117 {
118   struct tm *l = localtime (t);
119   if (! l)
120     return 0;
121   *tp = *l;
122   return tp;
123 }
124 #endif /* ! _LIBC */
125 #endif /* ! HAVE_LOCALTIME_R && ! defined (localtime_r) */
126
127
128 /* Yield the difference between (YEAR-YDAY HOUR:MIN:SEC) and (*TP),
129    measured in seconds, ignoring leap seconds.
130    YEAR uses the same numbering as TM->tm_year.
131    All values are in range, except possibly YEAR.
132    If overflow occurs, yield the low order bits of the correct answer.  */
133 static time_t
134 ydhms_tm_diff (year, yday, hour, min, sec, tp)
135      int year, yday, hour, min, sec;
136      const struct tm *tp;
137 {
138   /* Compute intervening leap days correctly even if year is negative.
139      Take care to avoid int overflow.  time_t overflow is OK, since
140      only the low order bits of the correct time_t answer are needed.
141      Don't convert to time_t until after all divisions are done, since
142      time_t might be unsigned.  */
143   int a4 = (year >> 2) + (TM_YEAR_BASE >> 2) - ! (year & 3);
144   int b4 = (tp->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (tp->tm_year & 3);
145   int a100 = a4 / 25 - (a4 % 25 < 0);
146   int b100 = b4 / 25 - (b4 % 25 < 0);
147   int a400 = a100 >> 2;
148   int b400 = b100 >> 2;
149   int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
150   time_t years = year - (time_t) tp->tm_year;
151   time_t days = (365 * years + intervening_leap_days
152                  + (yday - tp->tm_yday));
153   return (60 * (60 * (24 * days + (hour - tp->tm_hour))
154                 + (min - tp->tm_min))
155           + (sec - tp->tm_sec));
156 }
157
158
159 static time_t localtime_offset;
160
161 /* Convert *TP to a time_t value.  */
162 time_t
163 mktime (tp)
164      struct tm *tp;
165 {
166 #ifdef _LIBC
167   /* Update internal database according to current TZ setting.  */
168   __tzset_internal (1);
169 #endif
170
171   return __mktime_internal (tp, localtime_r, &localtime_offset);
172 }
173
174 /* Convert *TP to a time_t value, inverting
175    the monotonic and mostly-unit-linear conversion function CONVERT.
176    Use *OFFSET to keep track of a guess at the offset of the result,
177    compared to what the result would be for UTC without leap seconds.
178    If *OFFSET's guess is correct, only one CONVERT call is needed.  */
179 time_t
180 __mktime_internal (tp, convert, offset)
181      struct tm *tp;
182      struct tm *(*convert) __P ((const time_t *, struct tm *));
183      time_t *offset;
184 {
185   time_t t, dt, t0;
186   struct tm tm;
187
188   /* The maximum number of probes (calls to CONVERT) should be enough
189      to handle any combinations of time zone rule changes, solar time,
190      and leap seconds.  Posix.1 prohibits leap seconds, but some hosts
191      have them anyway.  */
192   int remaining_probes = 4;
193
194   /* Time requested.  Copy it in case CONVERT modifies *TP; this can
195      occur if TP is localtime's returned value and CONVERT is localtime.  */
196   int sec = tp->tm_sec;
197   int min = tp->tm_min;
198   int hour = tp->tm_hour;
199   int mday = tp->tm_mday;
200   int mon = tp->tm_mon;
201   int year_requested = tp->tm_year;
202   int isdst = tp->tm_isdst;
203
204   /* Ensure that mon is in range, and set year accordingly.  */
205   int mon_remainder = mon % 12;
206   int negative_mon_remainder = mon_remainder < 0;
207   int mon_years = mon / 12 - negative_mon_remainder;
208   int year = year_requested + mon_years;
209
210   /* The other values need not be in range:
211      the remaining code handles minor overflows correctly,
212      assuming int and time_t arithmetic wraps around.
213      Major overflows are caught at the end.  */
214
215   /* Calculate day of year from year, month, and day of month.
216      The result need not be in range.  */
217   int yday = ((__mon_yday[__isleap (year + TM_YEAR_BASE)]
218                [mon_remainder + 12 * negative_mon_remainder])
219               + mday - 1);
220
221 #if LEAP_SECONDS_POSSIBLE
222   /* Handle out-of-range seconds specially,
223      since ydhms_tm_diff assumes every minute has 60 seconds.  */
224   int sec_requested = sec;
225   if (sec < 0)
226     sec = 0;
227   if (59 < sec)
228     sec = 59;
229 #endif
230
231   /* Invert CONVERT by probing.  First assume the same offset as last time.
232      Then repeatedly use the error to improve the guess.  */
233
234   tm.tm_year = EPOCH_YEAR - TM_YEAR_BASE;
235   tm.tm_yday = tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
236   t0 = ydhms_tm_diff (year, yday, hour, min, sec, &tm);
237
238   for (t = t0 + *offset;
239        (dt = ydhms_tm_diff (year, yday, hour, min, sec, (*convert) (&t, &tm)));
240        t += dt)
241     if (--remaining_probes == 0)
242       return -1;
243
244   /* Check whether tm.tm_isdst has the requested value, if any.  */
245   if (0 <= isdst && 0 <= tm.tm_isdst)
246     {
247       int dst_diff = (isdst != 0) - (tm.tm_isdst != 0);
248       if (dst_diff)
249         {
250           /* Move two hours in the direction indicated by the disagreement,
251              probe some more, and switch to a new time if found.
252              The largest known fallback due to daylight savings is two hours:
253              once, in Newfoundland, 1988-10-30 02:00 -> 00:00.  */
254           time_t ot = t - 2 * 60 * 60 * dst_diff;
255           while (--remaining_probes != 0)
256             {
257               struct tm otm;
258               if (! (dt = ydhms_tm_diff (year, yday, hour, min, sec,
259                                          (*convert) (&ot, &otm))))
260                 {
261                   t = ot;
262                   tm = otm;
263                   break;
264                 }
265               if ((ot += dt) == t)
266                 break;  /* Avoid a redundant probe.  */
267             }
268         }
269     }
270
271   *offset = t - t0;
272
273 #if LEAP_SECONDS_POSSIBLE
274   if (sec_requested != tm.tm_sec)
275     {
276       /* Adjust time to reflect the tm_sec requested, not the normalized value.
277          Also, repair any damage from a false match due to a leap second.  */
278       t += sec_requested - sec + (sec == 0 && tm.tm_sec == 60);
279       (*convert) (&t, &tm);
280     }
281 #endif
282
283   if (TIME_T_MAX / INT_MAX / 366 / 24 / 60 / 60 < 3)
284     {
285       /* time_t isn't large enough to rule out overflows in ydhms_tm_diff,
286          so check for major overflows.  A gross check suffices,
287          since if t has overflowed, it is off by a multiple of
288          TIME_T_MAX - TIME_T_MIN + 1.  So ignore any component of
289          the difference that is bounded by a small value.  */
290
291       double dyear = (double) year_requested + mon_years - tm.tm_year;
292       double dday = 366 * dyear + mday;
293       double dsec = 60 * (60 * (24 * dday + hour) + min) + sec_requested;
294
295       if (TIME_T_MAX / 3 - TIME_T_MIN / 3 < (dsec < 0 ? - dsec : dsec))
296         return -1;
297     }
298
299   *tp = tm;
300   return t;
301 }
302
303 #ifdef weak_alias
304 weak_alias (mktime, timelocal)
305 #endif
306 \f
307 #if DEBUG
308
309 static int
310 not_equal_tm (a, b)
311      struct tm *a;
312      struct tm *b;
313 {
314   return ((a->tm_sec ^ b->tm_sec)
315           | (a->tm_min ^ b->tm_min)
316           | (a->tm_hour ^ b->tm_hour)
317           | (a->tm_mday ^ b->tm_mday)
318           | (a->tm_mon ^ b->tm_mon)
319           | (a->tm_year ^ b->tm_year)
320           | (a->tm_mday ^ b->tm_mday)
321           | (a->tm_yday ^ b->tm_yday)
322           | (a->tm_isdst ^ b->tm_isdst));
323 }
324
325 static void
326 print_tm (tp)
327      struct tm *tp;
328 {
329   printf ("%04d-%02d-%02d %02d:%02d:%02d yday %03d wday %d isdst %d",
330           tp->tm_year + TM_YEAR_BASE, tp->tm_mon + 1, tp->tm_mday,
331           tp->tm_hour, tp->tm_min, tp->tm_sec,
332           tp->tm_yday, tp->tm_wday, tp->tm_isdst);
333 }
334
335 static int
336 check_result (tk, tmk, tl, tml)
337      time_t tk;
338      struct tm tmk;
339      time_t tl;
340      struct tm tml;
341 {
342   if (tk != tl || not_equal_tm (&tmk, &tml))
343     {
344       printf ("mktime (");
345       print_tm (&tmk);
346       printf (")\nyields (");
347       print_tm (&tml);
348       printf (") == %ld, should be %ld\n", (long) tl, (long) tk);
349       return 1;
350     }
351
352   return 0;
353 }
354
355 int
356 main (argc, argv)
357      int argc;
358      char **argv;
359 {
360   int status = 0;
361   struct tm tm, tmk, tml;
362   time_t tk, tl;
363   char trailer;
364
365   if ((argc == 3 || argc == 4)
366       && (sscanf (argv[1], "%d-%d-%d%c",
367                   &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &trailer)
368           == 3)
369       && (sscanf (argv[2], "%d:%d:%d%c",
370                   &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &trailer)
371           == 3))
372     {
373       tm.tm_year -= TM_YEAR_BASE;
374       tm.tm_mon--;
375       tm.tm_isdst = argc == 3 ? -1 : atoi (argv[3]);
376       tmk = tm;
377       tl = mktime (&tmk);
378       tml = *localtime (&tl);
379       printf ("mktime returns %ld == ", (long) tl);
380       print_tm (&tmk);
381       printf ("\n");
382       status = check_result (tl, tmk, tl, tml);
383     }
384   else if (argc == 4 || (argc == 5 && strcmp (argv[4], "-") == 0))
385     {
386       time_t from = atol (argv[1]);
387       time_t by = atol (argv[2]);
388       time_t to = atol (argv[3]);
389
390       if (argc == 4)
391         for (tl = from; tl <= to; tl += by)
392           {
393             tml = *localtime (&tl);
394             tmk = tml;
395             tk = mktime (&tmk);
396             status |= check_result (tk, tmk, tl, tml);
397           }
398       else
399         for (tl = from; tl <= to; tl += by)
400           {
401             /* Null benchmark.  */
402             tml = *localtime (&tl);
403             tmk = tml;
404             tk = tl;
405             status |= check_result (tk, tmk, tl, tml);
406           }
407     }
408   else
409     printf ("Usage:\
410 \t%s YYYY-MM-DD HH:MM:SS [ISDST] # Test given time.\n\
411 \t%s FROM BY TO # Test values FROM, FROM+BY, ..., TO.\n\
412 \t%s FROM BY TO - # Do not test those values (for benchmark).\n",
413             argv[0], argv[0], argv[0]);
414
415   return status;
416 }
417
418 #endif /* DEBUG */
419 \f
420 /*
421 Local Variables:
422 compile-command: "gcc -DDEBUG=1 -Wall -O -g mktime.c -o mktime"
423 End:
424 */