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