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