Bash-4.3 distribution sources and documentation
[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 #endif
45 #include <time.h>
46
47 #if HAVE_LIMITS_H
48 #include <limits.h>
49 #endif
50
51 #include "bashansi.h"
52
53 #if DEBUG
54 #include <stdio.h>
55 /* Make it work even if the system's libc has its own mktime routine.  */
56 #define mktime my_mktime
57 #endif /* DEBUG */
58
59 #ifndef __P
60 #if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
61 #define __P(args) args
62 #else
63 #define __P(args) ()
64 #endif  /* GCC.  */
65 #endif  /* Not __P.  */
66
67 #ifndef CHAR_BIT
68 #define CHAR_BIT 8
69 #endif
70
71 #ifndef INT_MIN
72 #define INT_MIN (~0 << (sizeof (int) * CHAR_BIT - 1))
73 #endif
74 #ifndef INT_MAX
75 #define INT_MAX (~0 - INT_MIN)
76 #endif
77
78 #ifndef TIME_T_MIN
79 #define TIME_T_MIN (0 < (time_t) -1 ? (time_t) 0 \
80                     : ~ (time_t) 0 << (sizeof (time_t) * CHAR_BIT - 1))
81 #endif
82 #ifndef TIME_T_MAX
83 #define TIME_T_MAX (~ (time_t) 0 - TIME_T_MIN)
84 #endif
85
86 #define TM_YEAR_BASE 1900
87 #define EPOCH_YEAR 1970
88
89 #ifndef __isleap
90 /* Nonzero if YEAR is a leap year (every 4 years,
91    except every 100th isn't, and every 400th is).  */
92 #define __isleap(year)  \
93   ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
94 #endif
95
96 /* How many days come before each month (0-12).  */
97 const unsigned short int __mon_yday[2][13] =
98   {
99     /* Normal years.  */
100     { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
101     /* Leap years.  */
102     { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
103   };
104
105 static time_t ydhms_tm_diff __P ((int, int, int, int, int, const struct tm *));
106 time_t __mktime_internal __P ((struct tm *,
107                                struct tm *(*) (const time_t *, struct tm *),
108                                time_t *));
109
110
111 static struct tm *my_localtime_r __P ((const time_t *, struct tm *));
112 static struct tm *
113 my_localtime_r (t, tp)
114      const time_t *t;
115      struct tm *tp;
116 {
117   struct tm *l = localtime (t);
118   if (! l)
119     return 0;
120   *tp = *l;
121   return tp;
122 }
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, my_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 */