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