1 /* Copyright (C) 1993, 1994, 1995, 1996, 1997 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
28 /* Some hosts need this in order to declare localtime_r properly. */
34 # define HAVE_LIMITS_H 1
35 # define HAVE_LOCALTIME_R 1
36 # define STDC_HEADERS 1
39 /* Assume that leap seconds are possible, unless told otherwise.
40 If the host has a `zic' command with a `-L leapsecondfilename' option,
41 then it supports leap seconds; otherwise it probably doesn't. */
42 #ifndef LEAP_SECONDS_POSSIBLE
43 # define LEAP_SECONDS_POSSIBLE 1
46 #include <sys/types.h> /* Some systems define `time_t' here. */
58 /* Make it work even if the system's libc has its own mktime routine. */
59 # define mktime my_mktime
63 # if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
64 # define __P(args) args
75 # define INT_MIN (~0 << (sizeof (int) * CHAR_BIT - 1))
78 # define INT_MAX (~0 - INT_MIN)
82 /* The outer cast to time_t works around a bug in Cray C 5.0.3.0. */
83 # define TIME_T_MIN ((time_t) \
84 (0 < (time_t) -1 ? (time_t) 0 \
85 : ~ (time_t) 0 << (sizeof (time_t) * CHAR_BIT - 1)))
88 # define TIME_T_MAX (~ (time_t) 0 - TIME_T_MIN)
91 #define TM_YEAR_BASE 1900
92 #define EPOCH_YEAR 1970
95 /* Nonzero if YEAR is a leap year (every 4 years,
96 except every 100th isn't, and every 400th is). */
97 # define __isleap(year) \
98 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
101 /* How many days come before each month (0-12). */
102 const unsigned short int __mon_yday
[2][13] =
105 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
107 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
110 static struct tm
*ranged_convert
__P ((struct tm
*(*) __P ((const time_t *,
112 time_t *, struct tm
*));
113 static time_t ydhms_tm_diff
__P ((int, int, int, int, int, const struct tm
*));
114 time_t __mktime_internal
__P ((struct tm
*,
115 struct tm
*(*) (const time_t *, struct tm
*),
120 # define localtime_r __localtime_r
122 # if ! HAVE_LOCALTIME_R && ! defined localtime_r
123 /* Approximate localtime_r as best we can in its absence. */
124 # define localtime_r my_mktime_localtime_r
125 static struct tm
*localtime_r
__P ((const time_t *, struct tm
*));
131 struct tm
*l
= localtime (t
);
137 # endif /* ! HAVE_LOCALTIME_R && ! defined (localtime_r) */
141 /* Yield the difference between (YEAR-YDAY HOUR:MIN:SEC) and (*TP),
142 measured in seconds, ignoring leap seconds.
143 YEAR uses the same numbering as TM->tm_year.
144 All values are in range, except possibly YEAR.
145 If TP is null, return a nonzero value.
146 If overflow occurs, yield the low order bits of the correct answer. */
148 ydhms_tm_diff (year
, yday
, hour
, min
, sec
, tp
)
149 int year
, yday
, hour
, min
, sec
;
156 /* Compute intervening leap days correctly even if year is negative.
157 Take care to avoid int overflow. time_t overflow is OK, since
158 only the low order bits of the correct time_t answer are needed.
159 Don't convert to time_t until after all divisions are done, since
160 time_t might be unsigned. */
161 int a4
= (year
>> 2) + (TM_YEAR_BASE
>> 2) - ! (year
& 3);
162 int b4
= (tp
->tm_year
>> 2) + (TM_YEAR_BASE
>> 2) - ! (tp
->tm_year
& 3);
163 int a100
= a4
/ 25 - (a4
% 25 < 0);
164 int b100
= b4
/ 25 - (b4
% 25 < 0);
165 int a400
= a100
>> 2;
166 int b400
= b100
>> 2;
167 int intervening_leap_days
= (a4
- b4
) - (a100
- b100
) + (a400
- b400
);
168 time_t years
= year
- (time_t) tp
->tm_year
;
169 time_t days
= (365 * years
+ intervening_leap_days
170 + (yday
- tp
->tm_yday
));
171 return (60 * (60 * (24 * days
+ (hour
- tp
->tm_hour
))
172 + (min
- tp
->tm_min
))
173 + (sec
- tp
->tm_sec
));
178 static time_t localtime_offset
;
180 /* Convert *TP to a time_t value. */
186 /* POSIX.1 8.1.1 requires that whenever mktime() is called, the
187 time zone names contained in the external variable `tzname' shall
188 be set as if the tzset() function had been called. */
192 return __mktime_internal (tp
, localtime_r
, &localtime_offset
);
195 /* Use CONVERT to convert *T to a broken down time in *TP.
196 If *T is out of range for conversion, adjust it so that
197 it is the nearest in-range value and then convert that. */
199 ranged_convert (convert
, t
, tp
)
200 struct tm
*(*convert
) __P ((const time_t *, struct tm
*));
206 if (! (r
= (*convert
) (t
, tp
)) && *t
)
212 /* BAD is a known unconvertible time_t, and OK is a known good one.
213 Use binary search to narrow the range between BAD and OK until
215 while (bad
!= ok
+ (bad
< 0 ? -1 : 1))
217 time_t mid
= *t
= (bad
< 0
218 ? bad
+ ((ok
- bad
) >> 1)
219 : ok
+ ((bad
- ok
) >> 1));
220 if ((r
= (*convert
) (t
, tp
)))
231 /* The last conversion attempt failed;
232 revert to the most recent successful attempt. */
243 /* Convert *TP to a time_t value, inverting
244 the monotonic and mostly-unit-linear conversion function CONVERT.
245 Use *OFFSET to keep track of a guess at the offset of the result,
246 compared to what the result would be for UTC without leap seconds.
247 If *OFFSET's guess is correct, only one CONVERT call is needed. */
249 __mktime_internal (tp
, convert
, offset
)
251 struct tm
*(*convert
) __P ((const time_t *, struct tm
*));
257 /* The maximum number of probes (calls to CONVERT) should be enough
258 to handle any combinations of time zone rule changes, solar time,
259 and leap seconds. POSIX.1 prohibits leap seconds, but some hosts
261 int remaining_probes
= 4;
263 /* Time requested. Copy it in case CONVERT modifies *TP; this can
264 occur if TP is localtime's returned value and CONVERT is localtime. */
265 int sec
= tp
->tm_sec
;
266 int min
= tp
->tm_min
;
267 int hour
= tp
->tm_hour
;
268 int mday
= tp
->tm_mday
;
269 int mon
= tp
->tm_mon
;
270 int year_requested
= tp
->tm_year
;
271 int isdst
= tp
->tm_isdst
;
273 /* Ensure that mon is in range, and set year accordingly. */
274 int mon_remainder
= mon
% 12;
275 int negative_mon_remainder
= mon_remainder
< 0;
276 int mon_years
= mon
/ 12 - negative_mon_remainder
;
277 int year
= year_requested
+ mon_years
;
279 /* The other values need not be in range:
280 the remaining code handles minor overflows correctly,
281 assuming int and time_t arithmetic wraps around.
282 Major overflows are caught at the end. */
284 /* Calculate day of year from year, month, and day of month.
285 The result need not be in range. */
286 int yday
= ((__mon_yday
[__isleap (year
+ TM_YEAR_BASE
)]
287 [mon_remainder
+ 12 * negative_mon_remainder
])
290 int sec_requested
= sec
;
291 #if LEAP_SECONDS_POSSIBLE
292 /* Handle out-of-range seconds specially,
293 since ydhms_tm_diff assumes every minute has 60 seconds. */
300 /* Invert CONVERT by probing. First assume the same offset as last time.
301 Then repeatedly use the error to improve the guess. */
303 tm
.tm_year
= EPOCH_YEAR
- TM_YEAR_BASE
;
304 tm
.tm_yday
= tm
.tm_hour
= tm
.tm_min
= tm
.tm_sec
= 0;
305 t0
= ydhms_tm_diff (year
, yday
, hour
, min
, sec
, &tm
);
307 for (t
= t0
+ *offset
;
308 (dt
= ydhms_tm_diff (year
, yday
, hour
, min
, sec
,
309 ranged_convert (convert
, &t
, &tm
)));
311 if (--remaining_probes
== 0)
314 /* Check whether tm.tm_isdst has the requested value, if any. */
315 if (0 <= isdst
&& 0 <= tm
.tm_isdst
)
317 int dst_diff
= (isdst
!= 0) - (tm
.tm_isdst
!= 0);
320 /* Move two hours in the direction indicated by the disagreement,
321 probe some more, and switch to a new time if found.
322 The largest known fallback due to daylight savings is two hours:
323 once, in Newfoundland, 1988-10-30 02:00 -> 00:00. */
324 time_t ot
= t
- 2 * 60 * 60 * dst_diff
;
325 while (--remaining_probes
!= 0)
328 if (! (dt
= ydhms_tm_diff (year
, yday
, hour
, min
, sec
,
329 ranged_convert (convert
, &ot
, &otm
))))
336 break; /* Avoid a redundant probe. */
343 #if LEAP_SECONDS_POSSIBLE
344 if (sec_requested
!= tm
.tm_sec
)
346 /* Adjust time to reflect the tm_sec requested, not the normalized value.
347 Also, repair any damage from a false match due to a leap second. */
348 t
+= sec_requested
- sec
+ (sec
== 0 && tm
.tm_sec
== 60);
349 if (! (*convert
) (&t
, &tm
))
354 if (TIME_T_MAX
/ INT_MAX
/ 366 / 24 / 60 / 60 < 3)
356 /* time_t isn't large enough to rule out overflows in ydhms_tm_diff,
357 so check for major overflows. A gross check suffices,
358 since if t has overflowed, it is off by a multiple of
359 TIME_T_MAX - TIME_T_MIN + 1. So ignore any component of
360 the difference that is bounded by a small value. */
362 double dyear
= (double) year_requested
+ mon_years
- tm
.tm_year
;
363 double dday
= 366 * dyear
+ mday
;
364 double dsec
= 60 * (60 * (24 * dday
+ hour
) + min
) + sec_requested
;
366 if (TIME_T_MAX
/ 3 - TIME_T_MIN
/ 3 < (dsec
< 0 ? - dsec
: dsec
))
375 weak_alias (mktime
, timelocal
)
385 return ((a
->tm_sec
^ b
->tm_sec
)
386 | (a
->tm_min
^ b
->tm_min
)
387 | (a
->tm_hour
^ b
->tm_hour
)
388 | (a
->tm_mday
^ b
->tm_mday
)
389 | (a
->tm_mon
^ b
->tm_mon
)
390 | (a
->tm_year
^ b
->tm_year
)
391 | (a
->tm_mday
^ b
->tm_mday
)
392 | (a
->tm_yday
^ b
->tm_yday
)
393 | (a
->tm_isdst
^ b
->tm_isdst
));
401 printf ("%04d-%02d-%02d %02d:%02d:%02d yday %03d wday %d isdst %d",
402 tp
->tm_year
+ TM_YEAR_BASE
, tp
->tm_mon
+ 1, tp
->tm_mday
,
403 tp
->tm_hour
, tp
->tm_min
, tp
->tm_sec
,
404 tp
->tm_yday
, tp
->tm_wday
, tp
->tm_isdst
);
410 check_result (tk
, tmk
, tl
, lt
)
416 if (tk
!= tl
|| !lt
|| not_equal_tm (&tmk
, lt
))
420 printf (")\nyields (");
422 printf (") == %ld, should be %ld\n", (long) tl
, (long) tk
);
435 struct tm tm
, tmk
, tml
;
440 if ((argc
== 3 || argc
== 4)
441 && (sscanf (argv
[1], "%d-%d-%d%c",
442 &tm
.tm_year
, &tm
.tm_mon
, &tm
.tm_mday
, &trailer
)
444 && (sscanf (argv
[2], "%d:%d:%d%c",
445 &tm
.tm_hour
, &tm
.tm_min
, &tm
.tm_sec
, &trailer
)
448 tm
.tm_year
-= TM_YEAR_BASE
;
450 tm
.tm_isdst
= argc
== 3 ? -1 : atoi (argv
[3]);
453 lt
= localtime (&tl
);
459 printf ("mktime returns %ld == ", (long) tl
);
462 status
= check_result (tl
, tmk
, tl
, lt
);
464 else if (argc
== 4 || (argc
== 5 && strcmp (argv
[4], "-") == 0))
466 time_t from
= atol (argv
[1]);
467 time_t by
= atol (argv
[2]);
468 time_t to
= atol (argv
[3]);
471 for (tl
= from
; tl
<= to
; tl
+= by
)
473 lt
= localtime (&tl
);
478 status
|= check_result (tk
, tmk
, tl
, tml
);
482 printf ("localtime (%ld) yields 0\n", (long) tl
);
487 for (tl
= from
; tl
<= to
; tl
+= by
)
489 /* Null benchmark. */
490 lt
= localtime (&tl
);
495 status
|= check_result (tk
, tmk
, tl
, tml
);
499 printf ("localtime (%ld) yields 0\n", (long) tl
);
506 \t%s YYYY-MM-DD HH:MM:SS [ISDST] # Test given time.\n\
507 \t%s FROM BY TO # Test values FROM, FROM+BY, ..., TO.\n\
508 \t%s FROM BY TO - # Do not test those values (for benchmark).\n",
509 argv
[0], argv
[0], argv
[0]);
518 compile-command: "gcc -DDEBUG -D__EXTENSIONS__ -DHAVE_LIMITS_H -DHAVE_LOCALTIME_R -DSTDC_HEADERS -Wall -W -O -g mktime.c -o mktime"