1 /* mktime: convert a `struct tm' to a time_t value zzzzzz
2 Copyright (C) 1993-1997, 1998 Free Software Foundation, Inc.
3 Contributed by Paul Eggert (eggert@twinsun.com).
5 NOTE: The canonical source of this file is maintained with the GNU C Library.
6 Bugs can be reported to bug-glibc@prep.ai.mit.edu.
8 This program is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 2, or (at your option) any
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
23 /* Define this to have a standalone program to test this implementation of
31 /* Some systems need this in order to declare localtime_r properly. */
37 # define HAVE_LIMITS_H 1
38 # define HAVE_LOCALTIME_R 1
39 # define STDC_HEADERS 1
42 /* Assume that leap seconds are possible, unless told otherwise.
43 If the host has a `zic' command with a `-L leapsecondfilename' option,
44 then it supports leap seconds; otherwise it probably doesn't. */
45 #ifndef LEAP_SECONDS_POSSIBLE
46 # define LEAP_SECONDS_POSSIBLE 1
49 #include <sys/types.h> /* Some systems define `time_t' here. */
61 /* Make it work even if the system's libc has its own mktime routine. */
62 # define mktime my_mktime
66 # if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
67 # define __P(args) args
77 /* The extra casts work around common compiler bugs. */
78 #define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
79 /* The outer cast is needed to work around a bug in Cray C 5.0.3.0.
80 It is necessary at least when t == time_t. */
81 #define TYPE_MINIMUM(t) ((t) (TYPE_SIGNED (t) \
82 ? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) : (t) 0))
83 #define TYPE_MAXIMUM(t) ((t) (~ (t) 0 - TYPE_MINIMUM (t)))
86 # define INT_MIN TYPE_MINIMUM (int)
89 # define INT_MAX TYPE_MAXIMUM (int)
93 # define TIME_T_MIN TYPE_MINIMUM (time_t)
96 # define TIME_T_MAX TYPE_MAXIMUM (time_t)
99 #define TM_YEAR_BASE 1900
100 #define EPOCH_YEAR 1970
103 /* Nonzero if YEAR is a leap year (every 4 years,
104 except every 100th isn't, and every 400th is). */
105 # define __isleap(year) \
106 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
109 /* How many days come before each month (0-12). */
110 const unsigned short int __mon_yday[2][13] =
113 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
115 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
118 static struct tm *ranged_convert __P ((struct tm *(*) __P ((const time_t *,
120 time_t *, struct tm *));
121 static time_t ydhms_tm_diff __P ((int, int, int, int, int, const struct tm *));
122 time_t __mktime_internal __P ((struct tm *,
123 struct tm *(*) (const time_t *, struct tm *),
128 # define localtime_r __localtime_r
130 # if HAVE_LOCALTIME_R == defined (localtime_r)
131 /* Provide our own substitute for a missing or possibly broken localtime_r. */
132 static struct tm *my_mktime_localtime_r __P ((const time_t *, struct tm *));
134 my_mktime_localtime_r (t, tp)
139 /* Digital Unix 4.0A and 4.0D have a macro localtime_r with the
140 standard meaning, along with an unwanted, nonstandard function
141 localtime_r. The placeholder function my_mktime_localtime_r
142 invokes the macro; use that instead of the system's bogus
144 return localtime_r (t, tp);
146 # else /* ! defined (localtime_r) */
147 /* Approximate localtime_r as best we can in its absence. */
148 struct tm *l = localtime (t);
153 # endif /* ! defined (localtime_r) */
155 # define localtime_r my_mktime_localtime_r
156 # endif /* HAVE_LOCALTIME_R == defined (localtime_r) */
160 /* Yield the difference between (YEAR-YDAY HOUR:MIN:SEC) and (*TP),
161 measured in seconds, ignoring leap seconds.
162 YEAR uses the same numbering as TM->tm_year.
163 All values are in range, except possibly YEAR.
164 If TP is null, return a nonzero value.
165 If overflow occurs, yield the low order bits of the correct answer. */
167 ydhms_tm_diff (year, yday, hour, min, sec, tp)
168 int year, yday, hour, min, sec;
175 /* Compute intervening leap days correctly even if year is negative.
176 Take care to avoid int overflow. time_t overflow is OK, since
177 only the low order bits of the correct time_t answer are needed.
178 Don't convert to time_t until after all divisions are done, since
179 time_t might be unsigned. */
180 int a4 = (year >> 2) + (TM_YEAR_BASE >> 2) - ! (year & 3);
181 int b4 = (tp->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (tp->tm_year & 3);
182 int a100 = a4 / 25 - (a4 % 25 < 0);
183 int b100 = b4 / 25 - (b4 % 25 < 0);
184 int a400 = a100 >> 2;
185 int b400 = b100 >> 2;
186 int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
187 time_t years = year - (time_t) tp->tm_year;
188 time_t days = (365 * years + intervening_leap_days
189 + (yday - tp->tm_yday));
190 return (60 * (60 * (24 * days + (hour - tp->tm_hour))
191 + (min - tp->tm_min))
192 + (sec - tp->tm_sec));
197 static time_t localtime_offset;
199 /* Convert *TP to a time_t value. */
205 /* POSIX.1 8.1.1 requires that whenever mktime() is called, the
206 time zone names contained in the external variable `tzname' shall
207 be set as if the tzset() function had been called. */
211 return __mktime_internal (tp, localtime_r, &localtime_offset);
214 /* Use CONVERT to convert *T to a broken down time in *TP.
215 If *T is out of range for conversion, adjust it so that
216 it is the nearest in-range value and then convert that. */
218 ranged_convert (convert, t, tp)
219 struct tm *(*convert) __P ((const time_t *, struct tm *));
225 if (! (r = (*convert) (t, tp)) && *t)
231 /* BAD is a known unconvertible time_t, and OK is a known good one.
232 Use binary search to narrow the range between BAD and OK until
234 while (bad != ok + (bad < 0 ? -1 : 1))
236 time_t mid = *t = (bad < 0
237 ? bad + ((ok - bad) >> 1)
238 : ok + ((bad - ok) >> 1));
239 if ((r = (*convert) (t, tp)))
250 /* The last conversion attempt failed;
251 revert to the most recent successful attempt. */
262 /* Convert *TP to a time_t value, inverting
263 the monotonic and mostly-unit-linear conversion function CONVERT.
264 Use *OFFSET to keep track of a guess at the offset of the result,
265 compared to what the result would be for UTC without leap seconds.
266 If *OFFSET's guess is correct, only one CONVERT call is needed. */
268 __mktime_internal (tp, convert, offset)
270 struct tm *(*convert) __P ((const time_t *, struct tm *));
276 /* The maximum number of probes (calls to CONVERT) should be enough
277 to handle any combinations of time zone rule changes, solar time,
278 and leap seconds. POSIX.1 prohibits leap seconds, but some hosts
280 int remaining_probes = 4;
282 /* Time requested. Copy it in case CONVERT modifies *TP; this can
283 occur if TP is localtime's returned value and CONVERT is localtime. */
284 int sec = tp->tm_sec;
285 int min = tp->tm_min;
286 int hour = tp->tm_hour;
287 int mday = tp->tm_mday;
288 int mon = tp->tm_mon;
289 int year_requested = tp->tm_year;
290 int isdst = tp->tm_isdst;
292 /* Ensure that mon is in range, and set year accordingly. */
293 int mon_remainder = mon % 12;
294 int negative_mon_remainder = mon_remainder < 0;
295 int mon_years = mon / 12 - negative_mon_remainder;
296 int year = year_requested + mon_years;
298 /* The other values need not be in range:
299 the remaining code handles minor overflows correctly,
300 assuming int and time_t arithmetic wraps around.
301 Major overflows are caught at the end. */
303 /* Calculate day of year from year, month, and day of month.
304 The result need not be in range. */
305 int yday = ((__mon_yday[__isleap (year + TM_YEAR_BASE)]
306 [mon_remainder + 12 * negative_mon_remainder])
309 int sec_requested = sec;
310 #if LEAP_SECONDS_POSSIBLE
311 /* Handle out-of-range seconds specially,
312 since ydhms_tm_diff assumes every minute has 60 seconds. */
319 /* Invert CONVERT by probing. First assume the same offset as last time.
320 Then repeatedly use the error to improve the guess. */
322 tm.tm_year = EPOCH_YEAR - TM_YEAR_BASE;
323 tm.tm_yday = tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
324 t0 = ydhms_tm_diff (year, yday, hour, min, sec, &tm);
326 for (t = t0 + *offset;
327 (dt = ydhms_tm_diff (year, yday, hour, min, sec,
328 ranged_convert (convert, &t, &tm)));
330 if (--remaining_probes == 0)
333 /* Check whether tm.tm_isdst has the requested value, if any. */
334 if (0 <= isdst && 0 <= tm.tm_isdst)
336 int dst_diff = (isdst != 0) - (tm.tm_isdst != 0);
339 /* Move two hours in the direction indicated by the disagreement,
340 probe some more, and switch to a new time if found.
341 The largest known fallback due to daylight savings is two hours:
342 once, in Newfoundland, 1988-10-30 02:00 -> 00:00. */
343 time_t ot = t - 2 * 60 * 60 * dst_diff;
344 while (--remaining_probes != 0)
347 if (! (dt = ydhms_tm_diff (year, yday, hour, min, sec,
348 ranged_convert (convert, &ot, &otm))))
355 break; /* Avoid a redundant probe. */
362 #if LEAP_SECONDS_POSSIBLE
363 if (sec_requested != tm.tm_sec)
365 /* Adjust time to reflect the tm_sec requested, not the normalized value.
366 Also, repair any damage from a false match due to a leap second. */
367 t += sec_requested - sec + (sec == 0 && tm.tm_sec == 60);
368 if (! (*convert) (&t, &tm))
373 if (TIME_T_MAX / INT_MAX / 366 / 24 / 60 / 60 < 3)
375 /* time_t isn't large enough to rule out overflows in ydhms_tm_diff,
376 so check for major overflows. A gross check suffices,
377 since if t has overflowed, it is off by a multiple of
378 TIME_T_MAX - TIME_T_MIN + 1. So ignore any component of
379 the difference that is bounded by a small value. */
381 double dyear = (double) year_requested + mon_years - tm.tm_year;
382 double dday = 366 * dyear + mday;
383 double dsec = 60 * (60 * (24 * dday + hour) + min) + sec_requested;
385 /* On Irix4.0.5 cc, dividing TIME_T_MIN by 3 does not produce
386 correct results, ie., it erroneously gives a positive value
387 of 715827882. Setting a variable first then doing math on it
388 seems to work. (ghazi@caip.rutgers.edu) */
390 const time_t time_t_max = TIME_T_MAX;
391 const time_t time_t_min = TIME_T_MIN;
393 if (time_t_max / 3 - time_t_min / 3 < (dsec < 0 ? - dsec : dsec))
402 weak_alias (mktime, timelocal)
412 return ((a->tm_sec ^ b->tm_sec)
413 | (a->tm_min ^ b->tm_min)
414 | (a->tm_hour ^ b->tm_hour)
415 | (a->tm_mday ^ b->tm_mday)
416 | (a->tm_mon ^ b->tm_mon)
417 | (a->tm_year ^ b->tm_year)
418 | (a->tm_mday ^ b->tm_mday)
419 | (a->tm_yday ^ b->tm_yday)
420 | (a->tm_isdst ^ b->tm_isdst));
428 printf ("%04d-%02d-%02d %02d:%02d:%02d yday %03d wday %d isdst %d",
429 tp->tm_year + TM_YEAR_BASE, tp->tm_mon + 1, tp->tm_mday,
430 tp->tm_hour, tp->tm_min, tp->tm_sec,
431 tp->tm_yday, tp->tm_wday, tp->tm_isdst);
437 check_result (tk, tmk, tl, lt)
443 if (tk != tl || !lt || not_equal_tm (&tmk, lt))
447 printf (")\nyields (");
449 printf (") == %ld, should be %ld\n", (long) tl, (long) tk);
462 struct tm tm, tmk, tml;
467 if ((argc == 3 || argc == 4)
468 && (sscanf (argv[1], "%d-%d-%d%c",
469 &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &trailer)
471 && (sscanf (argv[2], "%d:%d:%d%c",
472 &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &trailer)
475 tm.tm_year -= TM_YEAR_BASE;
477 tm.tm_isdst = argc == 3 ? -1 : atoi (argv[3]);
480 lt = localtime (&tl);
486 printf ("mktime returns %ld == ", (long) tl);
489 status = check_result (tl, tmk, tl, lt);
491 else if (argc == 4 || (argc == 5 && strcmp (argv[4], "-") == 0))
493 time_t from = atol (argv[1]);
494 time_t by = atol (argv[2]);
495 time_t to = atol (argv[3]);
498 for (tl = from; tl <= to; tl += by)
500 lt = localtime (&tl);
505 status |= check_result (tk, tmk, tl, tml);
509 printf ("localtime (%ld) yields 0\n", (long) tl);
514 for (tl = from; tl <= to; tl += by)
516 /* Null benchmark. */
517 lt = localtime (&tl);
522 status |= check_result (tk, tmk, tl, tml);
526 printf ("localtime (%ld) yields 0\n", (long) tl);
533 \t%s YYYY-MM-DD HH:MM:SS [ISDST] # Test given time.\n\
534 \t%s FROM BY TO # Test values FROM, FROM+BY, ..., TO.\n\
535 \t%s FROM BY TO - # Do not test those values (for benchmark).\n",
536 argv[0], argv[0], argv[0]);
545 compile-command: "gcc -DDEBUG -D__EXTENSIONS__ -DHAVE_LIMITS_H -DHAVE_LOCALTIME_R -DSTDC_HEADERS -Wall -W -O -g mktime.c -o mktime"