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