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