1 /* Copyright (C) 1993, 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
2 Contributed by Paul Eggert (eggert@twinsun.com).
4 NOTE: The canonical source of this file is maintained with the GNU C Library.
5 Bugs can be reported to bug-glibc@prep.ai.mit.edu.
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
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.
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
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
22 /* Define this to have a standalone program to test this implementation of
31 # define HAVE_LIMITS_H 1
32 # define HAVE_LOCALTIME_R 1
33 # define STDC_HEADERS 1
36 /* Assume that leap seconds are possible, unless told otherwise.
37 If the host has a `zic' command with a `-L leapsecondfilename' option,
38 then it supports leap seconds; otherwise it probably doesn't. */
39 #ifndef LEAP_SECONDS_POSSIBLE
40 # define LEAP_SECONDS_POSSIBLE 1
43 #include <sys/types.h> /* Some systems define `time_t' here. */
55 /* Make it work even if the system's libc has its own mktime routine. */
56 # define mktime my_mktime
60 # if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
61 # define __P(args) args
72 # define INT_MIN (~0 << (sizeof (int) * CHAR_BIT - 1))
75 # define INT_MAX (~0 - INT_MIN)
79 /* The outer cast to time_t works around a bug in Cray C 5.0.3.0. */
80 # define TIME_T_MIN ((time_t) \
81 (0 < (time_t) -1 ? (time_t) 0 \
82 : ~ (time_t) 0 << (sizeof (time_t) * CHAR_BIT - 1)))
85 # define TIME_T_MAX (~ (time_t) 0 - TIME_T_MIN)
88 #define TM_YEAR_BASE 1900
89 #define EPOCH_YEAR 1970
92 /* Nonzero if YEAR is a leap year (every 4 years,
93 except every 100th isn't, and every 400th is). */
94 # define __isleap(year) \
95 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
98 /* How many days come before each month (0-12). */
99 const unsigned short int __mon_yday[2][13] =
102 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
104 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
107 static struct tm *ranged_convert __P ((struct tm *(*) __P ((const time_t *,
109 time_t *, struct tm *));
110 static time_t ydhms_tm_diff __P ((int, int, int, int, int, const struct tm *));
111 time_t __mktime_internal __P ((struct tm *,
112 struct tm *(*) (const time_t *, struct tm *),
117 # define localtime_r __localtime_r
119 # if ! HAVE_LOCALTIME_R && ! defined localtime_r
120 /* Approximate localtime_r as best we can in its absence. */
121 # define localtime_r my_mktime_localtime_r
122 static struct tm *localtime_r __P ((const time_t *, struct tm *));
128 struct tm *l = localtime (t);
134 # endif /* ! HAVE_LOCALTIME_R && ! defined (localtime_r) */
138 /* Yield the difference between (YEAR-YDAY HOUR:MIN:SEC) and (*TP),
139 measured in seconds, ignoring leap seconds.
140 YEAR uses the same numbering as TM->tm_year.
141 All values are in range, except possibly YEAR.
142 If TP is null, return a nonzero value.
143 If overflow occurs, yield the low order bits of the correct answer. */
145 ydhms_tm_diff (year, yday, hour, min, sec, tp)
146 int year, yday, hour, min, sec;
153 /* Compute intervening leap days correctly even if year is negative.
154 Take care to avoid int overflow. time_t overflow is OK, since
155 only the low order bits of the correct time_t answer are needed.
156 Don't convert to time_t until after all divisions are done, since
157 time_t might be unsigned. */
158 int a4 = (year >> 2) + (TM_YEAR_BASE >> 2) - ! (year & 3);
159 int b4 = (tp->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (tp->tm_year & 3);
160 int a100 = a4 / 25 - (a4 % 25 < 0);
161 int b100 = b4 / 25 - (b4 % 25 < 0);
162 int a400 = a100 >> 2;
163 int b400 = b100 >> 2;
164 int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
165 time_t years = year - (time_t) tp->tm_year;
166 time_t days = (365 * years + intervening_leap_days
167 + (yday - tp->tm_yday));
168 return (60 * (60 * (24 * days + (hour - tp->tm_hour))
169 + (min - tp->tm_min))
170 + (sec - tp->tm_sec));
175 static time_t localtime_offset;
177 /* Convert *TP to a time_t value. */
183 /* POSIX.1 8.1.1 requires that whenever mktime() is called, the
184 time zone names contained in the external variable `tzname' shall
185 be set as if the tzset() function had been called. */
189 return __mktime_internal (tp, localtime_r, &localtime_offset);
192 /* Use CONVERT to convert *T to a broken down time in *TP.
193 If *T is out of range for conversion, adjust it so that
194 it is the nearest in-range value and then convert that. */
196 ranged_convert (convert, t, tp)
197 struct tm *(*convert) __P ((const time_t *, struct tm *));
203 if (! (r = (*convert) (t, tp)) && *t)
209 /* BAD is a known unconvertible time_t, and OK is a known good one.
210 Use binary search to narrow the range between BAD and OK until
212 while (bad != ok + (bad < 0 ? -1 : 1))
214 time_t mid = *t = (bad < 0
215 ? bad + ((ok - bad) >> 1)
216 : ok + ((bad - ok) >> 1));
217 if ((r = (*convert) (t, tp)))
228 /* The last conversion attempt failed;
229 revert to the most recent successful attempt. */
240 /* Convert *TP to a time_t value, inverting
241 the monotonic and mostly-unit-linear conversion function CONVERT.
242 Use *OFFSET to keep track of a guess at the offset of the result,
243 compared to what the result would be for UTC without leap seconds.
244 If *OFFSET's guess is correct, only one CONVERT call is needed. */
246 __mktime_internal (tp, convert, offset)
248 struct tm *(*convert) __P ((const time_t *, struct tm *));
254 /* The maximum number of probes (calls to CONVERT) should be enough
255 to handle any combinations of time zone rule changes, solar time,
256 and leap seconds. POSIX.1 prohibits leap seconds, but some hosts
258 int remaining_probes = 4;
260 /* Time requested. Copy it in case CONVERT modifies *TP; this can
261 occur if TP is localtime's returned value and CONVERT is localtime. */
262 int sec = tp->tm_sec;
263 int min = tp->tm_min;
264 int hour = tp->tm_hour;
265 int mday = tp->tm_mday;
266 int mon = tp->tm_mon;
267 int year_requested = tp->tm_year;
268 int isdst = tp->tm_isdst;
270 /* Ensure that mon is in range, and set year accordingly. */
271 int mon_remainder = mon % 12;
272 int negative_mon_remainder = mon_remainder < 0;
273 int mon_years = mon / 12 - negative_mon_remainder;
274 int year = year_requested + mon_years;
276 /* The other values need not be in range:
277 the remaining code handles minor overflows correctly,
278 assuming int and time_t arithmetic wraps around.
279 Major overflows are caught at the end. */
281 /* Calculate day of year from year, month, and day of month.
282 The result need not be in range. */
283 int yday = ((__mon_yday[__isleap (year + TM_YEAR_BASE)]
284 [mon_remainder + 12 * negative_mon_remainder])
287 int sec_requested = sec;
288 #if LEAP_SECONDS_POSSIBLE
289 /* Handle out-of-range seconds specially,
290 since ydhms_tm_diff assumes every minute has 60 seconds. */
297 /* Invert CONVERT by probing. First assume the same offset as last time.
298 Then repeatedly use the error to improve the guess. */
300 tm.tm_year = EPOCH_YEAR - TM_YEAR_BASE;
301 tm.tm_yday = tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
302 t0 = ydhms_tm_diff (year, yday, hour, min, sec, &tm);
304 for (t = t0 + *offset;
305 (dt = ydhms_tm_diff (year, yday, hour, min, sec,
306 ranged_convert (convert, &t, &tm)));
308 if (--remaining_probes == 0)
311 /* Check whether tm.tm_isdst has the requested value, if any. */
312 if (0 <= isdst && 0 <= tm.tm_isdst)
314 int dst_diff = (isdst != 0) - (tm.tm_isdst != 0);
317 /* Move two hours in the direction indicated by the disagreement,
318 probe some more, and switch to a new time if found.
319 The largest known fallback due to daylight savings is two hours:
320 once, in Newfoundland, 1988-10-30 02:00 -> 00:00. */
321 time_t ot = t - 2 * 60 * 60 * dst_diff;
322 while (--remaining_probes != 0)
325 if (! (dt = ydhms_tm_diff (year, yday, hour, min, sec,
326 ranged_convert (convert, &ot, &otm))))
333 break; /* Avoid a redundant probe. */
340 #if LEAP_SECONDS_POSSIBLE
341 if (sec_requested != tm.tm_sec)
343 /* Adjust time to reflect the tm_sec requested, not the normalized value.
344 Also, repair any damage from a false match due to a leap second. */
345 t += sec_requested - sec + (sec == 0 && tm.tm_sec == 60);
346 if (! (*convert) (&t, &tm))
351 if (TIME_T_MAX / INT_MAX / 366 / 24 / 60 / 60 < 3)
353 /* time_t isn't large enough to rule out overflows in ydhms_tm_diff,
354 so check for major overflows. A gross check suffices,
355 since if t has overflowed, it is off by a multiple of
356 TIME_T_MAX - TIME_T_MIN + 1. So ignore any component of
357 the difference that is bounded by a small value. */
359 double dyear = (double) year_requested + mon_years - tm.tm_year;
360 double dday = 366 * dyear + mday;
361 double dsec = 60 * (60 * (24 * dday + hour) + min) + sec_requested;
363 if (TIME_T_MAX / 3 - TIME_T_MIN / 3 < (dsec < 0 ? - dsec : dsec))
372 weak_alias (mktime, timelocal)
382 return ((a->tm_sec ^ b->tm_sec)
383 | (a->tm_min ^ b->tm_min)
384 | (a->tm_hour ^ b->tm_hour)
385 | (a->tm_mday ^ b->tm_mday)
386 | (a->tm_mon ^ b->tm_mon)
387 | (a->tm_year ^ b->tm_year)
388 | (a->tm_mday ^ b->tm_mday)
389 | (a->tm_yday ^ b->tm_yday)
390 | (a->tm_isdst ^ b->tm_isdst));
398 printf ("%04d-%02d-%02d %02d:%02d:%02d yday %03d wday %d isdst %d",
399 tp->tm_year + TM_YEAR_BASE, tp->tm_mon + 1, tp->tm_mday,
400 tp->tm_hour, tp->tm_min, tp->tm_sec,
401 tp->tm_yday, tp->tm_wday, tp->tm_isdst);
407 check_result (tk, tmk, tl, lt)
413 if (tk != tl || !lt || not_equal_tm (&tmk, lt))
417 printf (")\nyields (");
419 printf (") == %ld, should be %ld\n", (long) tl, (long) tk);
432 struct tm tm, tmk, tml;
437 if ((argc == 3 || argc == 4)
438 && (sscanf (argv[1], "%d-%d-%d%c",
439 &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &trailer)
441 && (sscanf (argv[2], "%d:%d:%d%c",
442 &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &trailer)
445 tm.tm_year -= TM_YEAR_BASE;
447 tm.tm_isdst = argc == 3 ? -1 : atoi (argv[3]);
450 lt = localtime (&tl);
456 printf ("mktime returns %ld == ", (long) tl);
459 status = check_result (tl, tmk, tl, lt);
461 else if (argc == 4 || (argc == 5 && strcmp (argv[4], "-") == 0))
463 time_t from = atol (argv[1]);
464 time_t by = atol (argv[2]);
465 time_t to = atol (argv[3]);
468 for (tl = from; tl <= to; tl += by)
470 lt = localtime (&tl);
475 status |= check_result (tk, tmk, tl, tml);
479 printf ("localtime (%ld) yields 0\n", (long) tl);
484 for (tl = from; tl <= to; tl += by)
486 /* Null benchmark. */
487 lt = localtime (&tl);
492 status |= check_result (tk, tmk, tl, tml);
496 printf ("localtime (%ld) yields 0\n", (long) tl);
503 \t%s YYYY-MM-DD HH:MM:SS [ISDST] # Test given time.\n\
504 \t%s FROM BY TO # Test values FROM, FROM+BY, ..., TO.\n\
505 \t%s FROM BY TO - # Do not test those values (for benchmark).\n",
506 argv[0], argv[0], argv[0]);
515 compile-command: "gcc -DDEBUG -D__EXTENSIONS__ -DHAVE_LIMITS_H -DHAVE_LOCALTIME_R -DSTDC_HEADERS -Wall -W -O -g mktime.c -o mktime"