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
30 /* Some systems need this in order to declare localtime_r properly. */
36 # define HAVE_LIMITS_H 1
37 # define HAVE_LOCALTIME_R 1
38 # define STDC_HEADERS 1
41 /* Assume that leap seconds are possible, unless told otherwise.
42 If the host has a `zic' command with a `-L leapsecondfilename' option,
43 then it supports leap seconds; otherwise it probably doesn't. */
44 #ifndef LEAP_SECONDS_POSSIBLE
45 # define LEAP_SECONDS_POSSIBLE 1
48 #include <sys/types.h> /* Some systems define `time_t' here. */
60 /* Make it work even if the system's libc has its own mktime routine. */
61 # define mktime my_mktime
65 # if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
66 # define __P(args) args
77 # define INT_MIN (~0 << (sizeof (int) * CHAR_BIT - 1))
80 # define INT_MAX (~0 - INT_MIN)
84 /* The outer cast to time_t works around a bug in Cray C 5.0.3.0. */
85 # define TIME_T_MIN ((time_t) \
86 (0 < (time_t) -1 ? (time_t) 0 \
87 : ~ (time_t) 0 << (sizeof (time_t) * CHAR_BIT - 1)))
90 # define TIME_T_MAX (~ (time_t) 0 - TIME_T_MIN)
93 #define TM_YEAR_BASE 1900
94 #define EPOCH_YEAR 1970
97 /* Nonzero if YEAR is a leap year (every 4 years,
98 except every 100th isn't, and every 400th is). */
99 # define __isleap(year) \
100 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
103 /* How many days come before each month (0-12). */
104 const unsigned short int __mon_yday
[2][13] =
107 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
109 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
112 static struct tm
*ranged_convert
__P ((struct tm
*(*) __P ((const time_t *,
114 time_t *, struct tm
*));
115 static time_t ydhms_tm_diff
__P ((int, int, int, int, int, const struct tm
*));
116 time_t __mktime_internal
__P ((struct tm
*,
117 struct tm
*(*) (const time_t *, struct tm
*),
122 # define localtime_r __localtime_r
124 # if ! HAVE_LOCALTIME_R && ! defined localtime_r
125 /* Approximate localtime_r as best we can in its absence. */
126 # define localtime_r my_mktime_localtime_r
127 static struct tm
*localtime_r
__P ((const time_t *, struct tm
*));
133 struct tm
*l
= localtime (t
);
139 # endif /* ! HAVE_LOCALTIME_R && ! defined (localtime_r) */
143 /* Yield the difference between (YEAR-YDAY HOUR:MIN:SEC) and (*TP),
144 measured in seconds, ignoring leap seconds.
145 YEAR uses the same numbering as TM->tm_year.
146 All values are in range, except possibly YEAR.
147 If TP is null, return a nonzero value.
148 If overflow occurs, yield the low order bits of the correct answer. */
150 ydhms_tm_diff (year
, yday
, hour
, min
, sec
, tp
)
151 int year
, yday
, hour
, min
, sec
;
158 /* Compute intervening leap days correctly even if year is negative.
159 Take care to avoid int overflow. time_t overflow is OK, since
160 only the low order bits of the correct time_t answer are needed.
161 Don't convert to time_t until after all divisions are done, since
162 time_t might be unsigned. */
163 int a4
= (year
>> 2) + (TM_YEAR_BASE
>> 2) - ! (year
& 3);
164 int b4
= (tp
->tm_year
>> 2) + (TM_YEAR_BASE
>> 2) - ! (tp
->tm_year
& 3);
165 int a100
= a4
/ 25 - (a4
% 25 < 0);
166 int b100
= b4
/ 25 - (b4
% 25 < 0);
167 int a400
= a100
>> 2;
168 int b400
= b100
>> 2;
169 int intervening_leap_days
= (a4
- b4
) - (a100
- b100
) + (a400
- b400
);
170 time_t years
= year
- (time_t) tp
->tm_year
;
171 time_t days
= (365 * years
+ intervening_leap_days
172 + (yday
- tp
->tm_yday
));
173 return (60 * (60 * (24 * days
+ (hour
- tp
->tm_hour
))
174 + (min
- tp
->tm_min
))
175 + (sec
- tp
->tm_sec
));
180 static time_t localtime_offset
;
182 /* Convert *TP to a time_t value. */
188 /* POSIX.1 8.1.1 requires that whenever mktime() is called, the
189 time zone names contained in the external variable `tzname' shall
190 be set as if the tzset() function had been called. */
194 return __mktime_internal (tp
, localtime_r
, &localtime_offset
);
197 /* Use CONVERT to convert *T to a broken down time in *TP.
198 If *T is out of range for conversion, adjust it so that
199 it is the nearest in-range value and then convert that. */
201 ranged_convert (convert
, t
, tp
)
202 struct tm
*(*convert
) __P ((const time_t *, struct tm
*));
208 if (! (r
= (*convert
) (t
, tp
)) && *t
)
214 /* BAD is a known unconvertible time_t, and OK is a known good one.
215 Use binary search to narrow the range between BAD and OK until
217 while (bad
!= ok
+ (bad
< 0 ? -1 : 1))
219 time_t mid
= *t
= (bad
< 0
220 ? bad
+ ((ok
- bad
) >> 1)
221 : ok
+ ((bad
- ok
) >> 1));
222 if ((r
= (*convert
) (t
, tp
)))
233 /* The last conversion attempt failed;
234 revert to the most recent successful attempt. */
245 /* Convert *TP to a time_t value, inverting
246 the monotonic and mostly-unit-linear conversion function CONVERT.
247 Use *OFFSET to keep track of a guess at the offset of the result,
248 compared to what the result would be for UTC without leap seconds.
249 If *OFFSET's guess is correct, only one CONVERT call is needed. */
251 __mktime_internal (tp
, convert
, offset
)
253 struct tm
*(*convert
) __P ((const time_t *, struct tm
*));
259 /* The maximum number of probes (calls to CONVERT) should be enough
260 to handle any combinations of time zone rule changes, solar time,
261 and leap seconds. POSIX.1 prohibits leap seconds, but some hosts
263 int remaining_probes
= 4;
265 /* Time requested. Copy it in case CONVERT modifies *TP; this can
266 occur if TP is localtime's returned value and CONVERT is localtime. */
267 int sec
= tp
->tm_sec
;
268 int min
= tp
->tm_min
;
269 int hour
= tp
->tm_hour
;
270 int mday
= tp
->tm_mday
;
271 int mon
= tp
->tm_mon
;
272 int year_requested
= tp
->tm_year
;
273 int isdst
= tp
->tm_isdst
;
275 /* Ensure that mon is in range, and set year accordingly. */
276 int mon_remainder
= mon
% 12;
277 int negative_mon_remainder
= mon_remainder
< 0;
278 int mon_years
= mon
/ 12 - negative_mon_remainder
;
279 int year
= year_requested
+ mon_years
;
281 /* The other values need not be in range:
282 the remaining code handles minor overflows correctly,
283 assuming int and time_t arithmetic wraps around.
284 Major overflows are caught at the end. */
286 /* Calculate day of year from year, month, and day of month.
287 The result need not be in range. */
288 int yday
= ((__mon_yday
[__isleap (year
+ TM_YEAR_BASE
)]
289 [mon_remainder
+ 12 * negative_mon_remainder
])
292 int sec_requested
= sec
;
293 #if LEAP_SECONDS_POSSIBLE
294 /* Handle out-of-range seconds specially,
295 since ydhms_tm_diff assumes every minute has 60 seconds. */
302 /* Invert CONVERT by probing. First assume the same offset as last time.
303 Then repeatedly use the error to improve the guess. */
305 tm
.tm_year
= EPOCH_YEAR
- TM_YEAR_BASE
;
306 tm
.tm_yday
= tm
.tm_hour
= tm
.tm_min
= tm
.tm_sec
= 0;
307 t0
= ydhms_tm_diff (year
, yday
, hour
, min
, sec
, &tm
);
309 for (t
= t0
+ *offset
;
310 (dt
= ydhms_tm_diff (year
, yday
, hour
, min
, sec
,
311 ranged_convert (convert
, &t
, &tm
)));
313 if (--remaining_probes
== 0)
316 /* Check whether tm.tm_isdst has the requested value, if any. */
317 if (0 <= isdst
&& 0 <= tm
.tm_isdst
)
319 int dst_diff
= (isdst
!= 0) - (tm
.tm_isdst
!= 0);
322 /* Move two hours in the direction indicated by the disagreement,
323 probe some more, and switch to a new time if found.
324 The largest known fallback due to daylight savings is two hours:
325 once, in Newfoundland, 1988-10-30 02:00 -> 00:00. */
326 time_t ot
= t
- 2 * 60 * 60 * dst_diff
;
327 while (--remaining_probes
!= 0)
330 if (! (dt
= ydhms_tm_diff (year
, yday
, hour
, min
, sec
,
331 ranged_convert (convert
, &ot
, &otm
))))
338 break; /* Avoid a redundant probe. */
345 #if LEAP_SECONDS_POSSIBLE
346 if (sec_requested
!= tm
.tm_sec
)
348 /* Adjust time to reflect the tm_sec requested, not the normalized value.
349 Also, repair any damage from a false match due to a leap second. */
350 t
+= sec_requested
- sec
+ (sec
== 0 && tm
.tm_sec
== 60);
351 if (! (*convert
) (&t
, &tm
))
356 if (TIME_T_MAX
/ INT_MAX
/ 366 / 24 / 60 / 60 < 3)
358 /* time_t isn't large enough to rule out overflows in ydhms_tm_diff,
359 so check for major overflows. A gross check suffices,
360 since if t has overflowed, it is off by a multiple of
361 TIME_T_MAX - TIME_T_MIN + 1. So ignore any component of
362 the difference that is bounded by a small value. */
364 double dyear
= (double) year_requested
+ mon_years
- tm
.tm_year
;
365 double dday
= 366 * dyear
+ mday
;
366 double dsec
= 60 * (60 * (24 * dday
+ hour
) + min
) + sec_requested
;
368 if (TIME_T_MAX
/ 3 - TIME_T_MIN
/ 3 < (dsec
< 0 ? - dsec
: dsec
))
377 weak_alias (mktime
, timelocal
)
387 return ((a
->tm_sec
^ b
->tm_sec
)
388 | (a
->tm_min
^ b
->tm_min
)
389 | (a
->tm_hour
^ b
->tm_hour
)
390 | (a
->tm_mday
^ b
->tm_mday
)
391 | (a
->tm_mon
^ b
->tm_mon
)
392 | (a
->tm_year
^ b
->tm_year
)
393 | (a
->tm_mday
^ b
->tm_mday
)
394 | (a
->tm_yday
^ b
->tm_yday
)
395 | (a
->tm_isdst
^ b
->tm_isdst
));
403 printf ("%04d-%02d-%02d %02d:%02d:%02d yday %03d wday %d isdst %d",
404 tp
->tm_year
+ TM_YEAR_BASE
, tp
->tm_mon
+ 1, tp
->tm_mday
,
405 tp
->tm_hour
, tp
->tm_min
, tp
->tm_sec
,
406 tp
->tm_yday
, tp
->tm_wday
, tp
->tm_isdst
);
412 check_result (tk
, tmk
, tl
, lt
)
418 if (tk
!= tl
|| !lt
|| not_equal_tm (&tmk
, lt
))
422 printf (")\nyields (");
424 printf (") == %ld, should be %ld\n", (long) tl
, (long) tk
);
437 struct tm tm
, tmk
, tml
;
442 if ((argc
== 3 || argc
== 4)
443 && (sscanf (argv
[1], "%d-%d-%d%c",
444 &tm
.tm_year
, &tm
.tm_mon
, &tm
.tm_mday
, &trailer
)
446 && (sscanf (argv
[2], "%d:%d:%d%c",
447 &tm
.tm_hour
, &tm
.tm_min
, &tm
.tm_sec
, &trailer
)
450 tm
.tm_year
-= TM_YEAR_BASE
;
452 tm
.tm_isdst
= argc
== 3 ? -1 : atoi (argv
[3]);
455 lt
= localtime (&tl
);
461 printf ("mktime returns %ld == ", (long) tl
);
464 status
= check_result (tl
, tmk
, tl
, lt
);
466 else if (argc
== 4 || (argc
== 5 && strcmp (argv
[4], "-") == 0))
468 time_t from
= atol (argv
[1]);
469 time_t by
= atol (argv
[2]);
470 time_t to
= atol (argv
[3]);
473 for (tl
= from
; tl
<= to
; tl
+= by
)
475 lt
= localtime (&tl
);
480 status
|= check_result (tk
, tmk
, tl
, tml
);
484 printf ("localtime (%ld) yields 0\n", (long) tl
);
489 for (tl
= from
; tl
<= to
; tl
+= by
)
491 /* Null benchmark. */
492 lt
= localtime (&tl
);
497 status
|= check_result (tk
, tmk
, tl
, tml
);
501 printf ("localtime (%ld) yields 0\n", (long) tl
);
508 \t%s YYYY-MM-DD HH:MM:SS [ISDST] # Test given time.\n\
509 \t%s FROM BY TO # Test values FROM, FROM+BY, ..., TO.\n\
510 \t%s FROM BY TO - # Do not test those values (for benchmark).\n",
511 argv
[0], argv
[0], argv
[0]);
520 compile-command: "gcc -DDEBUG -D__EXTENSIONS__ -DHAVE_LIMITS_H -DHAVE_LOCALTIME_R -DSTDC_HEADERS -Wall -W -O -g mktime.c -o mktime"