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