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