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