1 /* Copyright (C) 1993-2002 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Paul Eggert (eggert@twinsun.com).
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.
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.
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. */
20 /* Define this to have a standalone program to test this implementation of
29 # define HAVE_LIMITS_H 1
30 # define HAVE_LOCALTIME_R 1
31 # define STDC_HEADERS 1
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
42 #include <sys/types.h> /* Some systems define `time_t' here. */
57 /* Make it work even if the system's libc has its own mktime routine. */
58 #define mktime my_mktime
62 #if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
63 #define __P(args) args
74 #define INT_MIN (~0 << (sizeof (int) * CHAR_BIT - 1))
77 #define INT_MAX (~0 - INT_MIN)
81 #define TIME_T_MIN (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 time_t ydhms_tm_diff __P ((int, int, int, int, int, const struct tm *));
108 time_t __mktime_internal __P ((struct tm *,
109 struct tm *(*) (const time_t *, struct tm *),
113 static struct tm *my_localtime_r __P ((const time_t *, struct tm *));
115 my_localtime_r (t, tp)
119 struct tm *l = localtime (t);
127 /* Yield the difference between (YEAR-YDAY HOUR:MIN:SEC) and (*TP),
128 measured in seconds, ignoring leap seconds.
129 YEAR uses the same numbering as TM->tm_year.
130 All values are in range, except possibly YEAR.
131 If overflow occurs, yield the low order bits of the correct answer. */
133 ydhms_tm_diff (year, yday, hour, min, sec, tp)
134 int year, yday, hour, min, sec;
137 /* Compute intervening leap days correctly even if year is negative.
138 Take care to avoid int overflow. time_t overflow is OK, since
139 only the low order bits of the correct time_t answer are needed.
140 Don't convert to time_t until after all divisions are done, since
141 time_t might be unsigned. */
142 int a4 = (year >> 2) + (TM_YEAR_BASE >> 2) - ! (year & 3);
143 int b4 = (tp->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (tp->tm_year & 3);
144 int a100 = a4 / 25 - (a4 % 25 < 0);
145 int b100 = b4 / 25 - (b4 % 25 < 0);
146 int a400 = a100 >> 2;
147 int b400 = b100 >> 2;
148 int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
149 time_t years = year - (time_t) tp->tm_year;
150 time_t days = (365 * years + intervening_leap_days
151 + (yday - tp->tm_yday));
152 return (60 * (60 * (24 * days + (hour - tp->tm_hour))
153 + (min - tp->tm_min))
154 + (sec - tp->tm_sec));
158 static time_t localtime_offset;
160 /* Convert *TP to a time_t value. */
166 /* POSIX.1 8.1.1 requires that whenever mktime() is called, the
167 time zone names contained in the external variable `tzname' shall
168 be set as if the tzset() function had been called. */
172 return __mktime_internal (tp, my_localtime_r, &localtime_offset);
175 /* Convert *TP to a time_t value, inverting
176 the monotonic and mostly-unit-linear conversion function CONVERT.
177 Use *OFFSET to keep track of a guess at the offset of the result,
178 compared to what the result would be for UTC without leap seconds.
179 If *OFFSET's guess is correct, only one CONVERT call is needed. */
181 __mktime_internal (tp, convert, offset)
183 struct tm *(*convert) __P ((const time_t *, struct tm *));
189 /* The maximum number of probes (calls to CONVERT) should be enough
190 to handle any combinations of time zone rule changes, solar time,
191 and leap seconds. Posix.1 prohibits leap seconds, but some hosts
193 int remaining_probes = 4;
195 /* Time requested. Copy it in case CONVERT modifies *TP; this can
196 occur if TP is localtime's returned value and CONVERT is localtime. */
197 int sec = tp->tm_sec;
198 int min = tp->tm_min;
199 int hour = tp->tm_hour;
200 int mday = tp->tm_mday;
201 int mon = tp->tm_mon;
202 int year_requested = tp->tm_year;
203 int isdst = tp->tm_isdst;
205 /* Ensure that mon is in range, and set year accordingly. */
206 int mon_remainder = mon % 12;
207 int negative_mon_remainder = mon_remainder < 0;
208 int mon_years = mon / 12 - negative_mon_remainder;
209 int year = year_requested + mon_years;
211 /* The other values need not be in range:
212 the remaining code handles minor overflows correctly,
213 assuming int and time_t arithmetic wraps around.
214 Major overflows are caught at the end. */
216 /* Calculate day of year from year, month, and day of month.
217 The result need not be in range. */
218 int yday = ((__mon_yday[__isleap (year + TM_YEAR_BASE)]
219 [mon_remainder + 12 * negative_mon_remainder])
222 #if LEAP_SECONDS_POSSIBLE
223 /* Handle out-of-range seconds specially,
224 since ydhms_tm_diff assumes every minute has 60 seconds. */
225 int sec_requested = sec;
232 /* Invert CONVERT by probing. First assume the same offset as last time.
233 Then repeatedly use the error to improve the guess. */
235 tm.tm_year = EPOCH_YEAR - TM_YEAR_BASE;
236 tm.tm_yday = tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
237 t0 = ydhms_tm_diff (year, yday, hour, min, sec, &tm);
239 for (t = t0 + *offset;
240 (dt = ydhms_tm_diff (year, yday, hour, min, sec, (*convert) (&t, &tm)));
242 if (--remaining_probes == 0)
245 /* Check whether tm.tm_isdst has the requested value, if any. */
246 if (0 <= isdst && 0 <= tm.tm_isdst)
248 int dst_diff = (isdst != 0) - (tm.tm_isdst != 0);
251 /* Move two hours in the direction indicated by the disagreement,
252 probe some more, and switch to a new time if found.
253 The largest known fallback due to daylight savings is two hours:
254 once, in Newfoundland, 1988-10-30 02:00 -> 00:00. */
255 time_t ot = t - 2 * 60 * 60 * dst_diff;
256 while (--remaining_probes != 0)
259 if (! (dt = ydhms_tm_diff (year, yday, hour, min, sec,
260 (*convert) (&ot, &otm))))
267 break; /* Avoid a redundant probe. */
274 #if LEAP_SECONDS_POSSIBLE
275 if (sec_requested != tm.tm_sec)
277 /* Adjust time to reflect the tm_sec requested, not the normalized value.
278 Also, repair any damage from a false match due to a leap second. */
279 t += sec_requested - sec + (sec == 0 && tm.tm_sec == 60);
280 (*convert) (&t, &tm);
284 if (TIME_T_MAX / INT_MAX / 366 / 24 / 60 / 60 < 3)
286 /* time_t isn't large enough to rule out overflows in ydhms_tm_diff,
287 so check for major overflows. A gross check suffices,
288 since if t has overflowed, it is off by a multiple of
289 TIME_T_MAX - TIME_T_MIN + 1. So ignore any component of
290 the difference that is bounded by a small value. */
292 double dyear = (double) year_requested + mon_years - tm.tm_year;
293 double dday = 366 * dyear + mday;
294 double dsec = 60 * (60 * (24 * dday + hour) + min) + sec_requested;
296 if (TIME_T_MAX / 3 - TIME_T_MIN / 3 < (dsec < 0 ? - dsec : dsec))
305 weak_alias (mktime, timelocal)
315 return ((a->tm_sec ^ b->tm_sec)
316 | (a->tm_min ^ b->tm_min)
317 | (a->tm_hour ^ b->tm_hour)
318 | (a->tm_mday ^ b->tm_mday)
319 | (a->tm_mon ^ b->tm_mon)
320 | (a->tm_year ^ b->tm_year)
321 | (a->tm_mday ^ b->tm_mday)
322 | (a->tm_yday ^ b->tm_yday)
323 | (a->tm_isdst ^ b->tm_isdst));
330 printf ("%04d-%02d-%02d %02d:%02d:%02d yday %03d wday %d isdst %d",
331 tp->tm_year + TM_YEAR_BASE, tp->tm_mon + 1, tp->tm_mday,
332 tp->tm_hour, tp->tm_min, tp->tm_sec,
333 tp->tm_yday, tp->tm_wday, tp->tm_isdst);
337 check_result (tk, tmk, tl, tml)
343 if (tk != tl || not_equal_tm (&tmk, &tml))
347 printf (")\nyields (");
349 printf (") == %ld, should be %ld\n", (long) tl, (long) tk);
362 struct tm tm, tmk, tml;
366 if ((argc == 3 || argc == 4)
367 && (sscanf (argv[1], "%d-%d-%d%c",
368 &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &trailer)
370 && (sscanf (argv[2], "%d:%d:%d%c",
371 &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &trailer)
374 tm.tm_year -= TM_YEAR_BASE;
376 tm.tm_isdst = argc == 3 ? -1 : atoi (argv[3]);
379 tml = *localtime (&tl);
380 printf ("mktime returns %ld == ", (long) tl);
383 status = check_result (tl, tmk, tl, tml);
385 else if (argc == 4 || (argc == 5 && strcmp (argv[4], "-") == 0))
387 time_t from = atol (argv[1]);
388 time_t by = atol (argv[2]);
389 time_t to = atol (argv[3]);
392 for (tl = from; tl <= to; tl += by)
394 tml = *localtime (&tl);
397 status |= check_result (tk, tmk, tl, tml);
400 for (tl = from; tl <= to; tl += by)
402 /* Null benchmark. */
403 tml = *localtime (&tl);
406 status |= check_result (tk, tmk, tl, tml);
411 \t%s YYYY-MM-DD HH:MM:SS [ISDST] # Test given time.\n\
412 \t%s FROM BY TO # Test values FROM, FROM+BY, ..., TO.\n\
413 \t%s FROM BY TO - # Do not test those values (for benchmark).\n",
414 argv[0], argv[0], argv[0]);
423 compile-command: "gcc -DDEBUG=1 -Wall -O -g mktime.c -o mktime"