]> git.ipfire.org Git - thirdparty/glibc.git/blob - time/mktime.c
mktime: remove incorrect attempt at unusual arithmetics
[thirdparty/glibc.git] / time / mktime.c
1 /* Convert a 'struct tm' to a time_t value.
2 Copyright (C) 1993-2012 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Paul Eggert <eggert@twinsun.com>.
5
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, see
18 <http://www.gnu.org/licenses/>. */
19
20 /* Define this to have a standalone program to test this implementation of
21 mktime. */
22 /* #define DEBUG 1 */
23
24 #ifndef _LIBC
25 # include <config.h>
26 #endif
27
28 /* Assume that leap seconds are possible, unless told otherwise.
29 If the host has a 'zic' command with a '-L leapsecondfilename' option,
30 then it supports leap seconds; otherwise it probably doesn't. */
31 #ifndef LEAP_SECONDS_POSSIBLE
32 # define LEAP_SECONDS_POSSIBLE 1
33 #endif
34
35 #include <time.h>
36
37 #include <limits.h>
38
39 #include <string.h> /* For the real memcpy prototype. */
40
41 #if DEBUG
42 # include <stdio.h>
43 # include <stdlib.h>
44 /* Make it work even if the system's libc has its own mktime routine. */
45 # undef mktime
46 # define mktime my_mktime
47 #endif /* DEBUG */
48
49 /* Some of the code in this file assumes that signed integer overflow
50 silently wraps around. This assumption can't easily be programmed
51 around, nor can it be checked for portably at compile-time or
52 easily eliminated at run-time.
53
54 Define WRAPV to 1 if the assumption is valid and if
55 #pragma GCC optimize ("wrapv")
56 does not trigger GCC bug 51793
57 <http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51793>.
58 Otherwise, define it to 0; this forces the use of slower code that,
59 while not guaranteed by the C Standard, works on all production
60 platforms that we know about. */
61 #ifndef WRAPV
62 # if (((__GNUC__ == 4 && 4 <= __GNUC_MINOR__) || 4 < __GNUC__) \
63 && defined __GLIBC__)
64 # pragma GCC optimize ("wrapv")
65 # define WRAPV 1
66 # else
67 # define WRAPV 0
68 # endif
69 #endif
70
71 /* Verify a requirement at compile-time (unlike assert, which is runtime). */
72 #define verify(name, assertion) struct name { char a[(assertion) ? 1 : -1]; }
73
74 /* A signed type that is at least one bit wider than int. */
75 #if INT_MAX <= LONG_MAX / 2
76 typedef long int long_int;
77 #else
78 typedef long long int long_int;
79 #endif
80 verify (long_int_is_wide_enough, INT_MAX == INT_MAX * (long_int) 2 / 2);
81
82 /* Shift A right by B bits portably, by dividing A by 2**B and
83 truncating towards minus infinity. A and B should be free of side
84 effects, and B should be in the range 0 <= B <= INT_BITS - 2, where
85 INT_BITS is the number of useful bits in an int. GNU code can
86 assume that INT_BITS is at least 32.
87
88 ISO C99 says that A >> B is implementation-defined if A < 0. Some
89 implementations (e.g., UNICOS 9.0 on a Cray Y-MP EL) don't shift
90 right in the usual way when A < 0, so SHR falls back on division if
91 ordinary A >> B doesn't seem to be the usual signed shift. */
92 #define SHR(a, b) \
93 ((-1 >> 1 == -1 \
94 && (long_int) -1 >> 1 == -1 \
95 && ((time_t) -1 >> 1 == -1 || ! TYPE_SIGNED (time_t))) \
96 ? (a) >> (b) \
97 : (a) / (1 << (b)) - ((a) % (1 << (b)) < 0))
98
99 /* The extra casts in the following macros work around compiler bugs,
100 e.g., in Cray C 5.0.3.0. */
101
102 /* True if the arithmetic type T is an integer type. bool counts as
103 an integer. */
104 #define TYPE_IS_INTEGER(t) ((t) 1.5 == 1)
105
106 /* True if negative values of the signed integer type T use two's
107 complement, or if T is an unsigned integer type. */
108 #define TYPE_TWOS_COMPLEMENT(t) ((t) ~ (t) 0 == (t) -1)
109
110 /* True if the arithmetic type T is signed. */
111 #define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
112
113 /* The maximum and minimum values for the integer type T. These
114 macros have undefined behavior if T is signed and has padding bits.
115 If this is a problem for you, please let us know how to fix it for
116 your host. */
117 #define TYPE_MINIMUM(t) \
118 ((t) (! TYPE_SIGNED (t) \
119 ? (t) 0 \
120 : ~ TYPE_MAXIMUM (t)))
121 #define TYPE_MAXIMUM(t) \
122 ((t) (! TYPE_SIGNED (t) \
123 ? (t) -1 \
124 : ~ (~ (t) 0 << (sizeof (t) * CHAR_BIT - 1))))
125
126 #ifndef TIME_T_MIN
127 # define TIME_T_MIN TYPE_MINIMUM (time_t)
128 #endif
129 #ifndef TIME_T_MAX
130 # define TIME_T_MAX TYPE_MAXIMUM (time_t)
131 #endif
132 #define TIME_T_MIDPOINT (SHR (TIME_T_MIN + TIME_T_MAX, 1) + 1)
133
134 verify (time_t_is_integer, TYPE_IS_INTEGER (time_t));
135 verify (twos_complement_arithmetic,
136 (TYPE_TWOS_COMPLEMENT (int)
137 && TYPE_TWOS_COMPLEMENT (long_int)
138 && TYPE_TWOS_COMPLEMENT (time_t)));
139
140 #define EPOCH_YEAR 1970
141 #define TM_YEAR_BASE 1900
142 verify (base_year_is_a_multiple_of_100, TM_YEAR_BASE % 100 == 0);
143
144 /* Return 1 if YEAR + TM_YEAR_BASE is a leap year. */
145 static inline int
146 leapyear (long_int year)
147 {
148 /* Don't add YEAR to TM_YEAR_BASE, as that might overflow.
149 Also, work even if YEAR is negative. */
150 return
151 ((year & 3) == 0
152 && (year % 100 != 0
153 || ((year / 100) & 3) == (- (TM_YEAR_BASE / 100) & 3)));
154 }
155
156 /* How many days come before each month (0-12). */
157 #ifndef _LIBC
158 static
159 #endif
160 const unsigned short int __mon_yday[2][13] =
161 {
162 /* Normal years. */
163 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
164 /* Leap years. */
165 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
166 };
167
168
169 #ifndef _LIBC
170 /* Portable standalone applications should supply a <time.h> that
171 declares a POSIX-compliant localtime_r, for the benefit of older
172 implementations that lack localtime_r or have a nonstandard one.
173 See the gnulib time_r module for one way to implement this. */
174 # undef __localtime_r
175 # define __localtime_r localtime_r
176 # define __mktime_internal mktime_internal
177 # include "mktime-internal.h"
178 #endif
179
180 /* Return an integer value measuring (YEAR1-YDAY1 HOUR1:MIN1:SEC1) -
181 (YEAR0-YDAY0 HOUR0:MIN0:SEC0) in seconds, assuming that the clocks
182 were not adjusted between the time stamps.
183
184 The YEAR values uses the same numbering as TP->tm_year. Values
185 need not be in the usual range. However, YEAR1 must not be less
186 than 2 * INT_MIN or greater than 2 * INT_MAX.
187
188 The result may overflow. It is the caller's responsibility to
189 detect overflow. */
190
191 static inline time_t
192 ydhms_diff (long_int year1, long_int yday1, int hour1, int min1, int sec1,
193 int year0, int yday0, int hour0, int min0, int sec0)
194 {
195 verify (C99_integer_division, -1 / 2 == 0);
196
197 /* Compute intervening leap days correctly even if year is negative.
198 Take care to avoid integer overflow here. */
199 int a4 = SHR (year1, 2) + SHR (TM_YEAR_BASE, 2) - ! (year1 & 3);
200 int b4 = SHR (year0, 2) + SHR (TM_YEAR_BASE, 2) - ! (year0 & 3);
201 int a100 = a4 / 25 - (a4 % 25 < 0);
202 int b100 = b4 / 25 - (b4 % 25 < 0);
203 int a400 = SHR (a100, 2);
204 int b400 = SHR (b100, 2);
205 int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
206
207 /* Compute the desired time in time_t precision. Overflow might
208 occur here. */
209 time_t tyear1 = year1;
210 time_t years = tyear1 - year0;
211 time_t days = 365 * years + yday1 - yday0 + intervening_leap_days;
212 time_t hours = 24 * days + hour1 - hour0;
213 time_t minutes = 60 * hours + min1 - min0;
214 time_t seconds = 60 * minutes + sec1 - sec0;
215 return seconds;
216 }
217
218 /* Return the average of A and B, even if A + B would overflow. */
219 static time_t
220 time_t_avg (time_t a, time_t b)
221 {
222 return SHR (a, 1) + SHR (b, 1) + (a & b & 1);
223 }
224
225 /* Return 1 if A + B does not overflow. If time_t is unsigned and if
226 B's top bit is set, assume that the sum represents A - -B, and
227 return 1 if the subtraction does not wrap around. */
228 static int
229 time_t_add_ok (time_t a, time_t b)
230 {
231 if (! TYPE_SIGNED (time_t))
232 {
233 time_t sum = a + b;
234 return (sum < a) == (TIME_T_MIDPOINT <= b);
235 }
236 else if (WRAPV)
237 {
238 time_t sum = a + b;
239 return (sum < a) == (b < 0);
240 }
241 else
242 {
243 time_t avg = time_t_avg (a, b);
244 return TIME_T_MIN / 2 <= avg && avg <= TIME_T_MAX / 2;
245 }
246 }
247
248 /* Return 1 if A + B does not overflow. */
249 static int
250 time_t_int_add_ok (time_t a, int b)
251 {
252 verify (int_no_wider_than_time_t, INT_MAX <= TIME_T_MAX);
253 if (WRAPV)
254 {
255 time_t sum = a + b;
256 return (sum < a) == (b < 0);
257 }
258 else
259 {
260 int a_odd = a & 1;
261 time_t avg = SHR (a, 1) + (SHR (b, 1) + (a_odd & b));
262 return TIME_T_MIN / 2 <= avg && avg <= TIME_T_MAX / 2;
263 }
264 }
265
266 /* Return a time_t value corresponding to (YEAR-YDAY HOUR:MIN:SEC),
267 assuming that *T corresponds to *TP and that no clock adjustments
268 occurred between *TP and the desired time.
269 If TP is null, return a value not equal to *T; this avoids false matches.
270 If overflow occurs, yield the minimal or maximal value, except do not
271 yield a value equal to *T. */
272 static time_t
273 guess_time_tm (long_int year, long_int yday, int hour, int min, int sec,
274 const time_t *t, const struct tm *tp)
275 {
276 if (tp)
277 {
278 time_t d = ydhms_diff (year, yday, hour, min, sec,
279 tp->tm_year, tp->tm_yday,
280 tp->tm_hour, tp->tm_min, tp->tm_sec);
281 if (time_t_add_ok (*t, d))
282 return *t + d;
283 }
284
285 /* Overflow occurred one way or another. Return the nearest result
286 that is actually in range, except don't report a zero difference
287 if the actual difference is nonzero, as that would cause a false
288 match; and don't oscillate between two values, as that would
289 confuse the spring-forward gap detector. */
290 return (*t < TIME_T_MIDPOINT
291 ? (*t <= TIME_T_MIN + 1 ? *t + 1 : TIME_T_MIN)
292 : (TIME_T_MAX - 1 <= *t ? *t - 1 : TIME_T_MAX));
293 }
294
295 /* Use CONVERT to convert *T to a broken down time in *TP.
296 If *T is out of range for conversion, adjust it so that
297 it is the nearest in-range value and then convert that. */
298 static struct tm *
299 ranged_convert (struct tm *(*convert) (const time_t *, struct tm *),
300 time_t *t, struct tm *tp)
301 {
302 struct tm *r = convert (t, tp);
303
304 if (!r && *t)
305 {
306 time_t bad = *t;
307 time_t ok = 0;
308
309 /* BAD is a known unconvertible time_t, and OK is a known good one.
310 Use binary search to narrow the range between BAD and OK until
311 they differ by 1. */
312 while (bad != ok + (bad < 0 ? -1 : 1))
313 {
314 time_t mid = *t = (bad < 0
315 ? bad + ((ok - bad) >> 1)
316 : ok + ((bad - ok) >> 1));
317 r = convert (t, tp);
318 if (r)
319 ok = mid;
320 else
321 bad = mid;
322 }
323
324 if (!r && ok)
325 {
326 /* The last conversion attempt failed;
327 revert to the most recent successful attempt. */
328 *t = ok;
329 r = convert (t, tp);
330 }
331 }
332
333 return r;
334 }
335
336
337 /* Convert *TP to a time_t value, inverting
338 the monotonic and mostly-unit-linear conversion function CONVERT.
339 Use *OFFSET to keep track of a guess at the offset of the result,
340 compared to what the result would be for UTC without leap seconds.
341 If *OFFSET's guess is correct, only one CONVERT call is needed.
342 This function is external because it is used also by timegm.c. */
343 time_t
344 __mktime_internal (struct tm *tp,
345 struct tm *(*convert) (const time_t *, struct tm *),
346 time_t *offset)
347 {
348 time_t t, gt, t0, t1, t2;
349 struct tm tm;
350
351 /* The maximum number of probes (calls to CONVERT) should be enough
352 to handle any combinations of time zone rule changes, solar time,
353 leap seconds, and oscillations around a spring-forward gap.
354 POSIX.1 prohibits leap seconds, but some hosts have them anyway. */
355 int remaining_probes = 6;
356
357 /* Time requested. Copy it in case CONVERT modifies *TP; this can
358 occur if TP is localtime's returned value and CONVERT is localtime. */
359 int sec = tp->tm_sec;
360 int min = tp->tm_min;
361 int hour = tp->tm_hour;
362 int mday = tp->tm_mday;
363 int mon = tp->tm_mon;
364 int year_requested = tp->tm_year;
365 /* Normalize the value. */
366 int isdst = ((tp->tm_isdst >> (8 * sizeof (tp->tm_isdst) - 1))
367 | (tp->tm_isdst != 0));
368
369 /* 1 if the previous probe was DST. */
370 int dst2;
371
372 /* Ensure that mon is in range, and set year accordingly. */
373 int mon_remainder = mon % 12;
374 int negative_mon_remainder = mon_remainder < 0;
375 int mon_years = mon / 12 - negative_mon_remainder;
376 long_int lyear_requested = year_requested;
377 long_int year = lyear_requested + mon_years;
378
379 /* The other values need not be in range:
380 the remaining code handles minor overflows correctly,
381 assuming int and time_t arithmetic wraps around.
382 Major overflows are caught at the end. */
383
384 /* Calculate day of year from year, month, and day of month.
385 The result need not be in range. */
386 int mon_yday = ((__mon_yday[leapyear (year)]
387 [mon_remainder + 12 * negative_mon_remainder])
388 - 1);
389 long_int lmday = mday;
390 long_int yday = mon_yday + lmday;
391
392 time_t guessed_offset = *offset;
393
394 int sec_requested = sec;
395
396 if (LEAP_SECONDS_POSSIBLE)
397 {
398 /* Handle out-of-range seconds specially,
399 since ydhms_tm_diff assumes every minute has 60 seconds. */
400 if (sec < 0)
401 sec = 0;
402 if (59 < sec)
403 sec = 59;
404 }
405
406 /* Invert CONVERT by probing. First assume the same offset as last
407 time. */
408
409 t0 = ydhms_diff (year, yday, hour, min, sec,
410 EPOCH_YEAR - TM_YEAR_BASE, 0, 0, 0, - guessed_offset);
411
412 if (TIME_T_MAX / INT_MAX / 366 / 24 / 60 / 60 < 3)
413 {
414 /* time_t isn't large enough to rule out overflows, so check
415 for major overflows. A gross check suffices, since if t0
416 has overflowed, it is off by a multiple of TIME_T_MAX -
417 TIME_T_MIN + 1. So ignore any component of the difference
418 that is bounded by a small value. */
419
420 /* Approximate log base 2 of the number of time units per
421 biennium. A biennium is 2 years; use this unit instead of
422 years to avoid integer overflow. For example, 2 average
423 Gregorian years are 2 * 365.2425 * 24 * 60 * 60 seconds,
424 which is 63113904 seconds, and rint (log2 (63113904)) is
425 26. */
426 int ALOG2_SECONDS_PER_BIENNIUM = 26;
427 int ALOG2_MINUTES_PER_BIENNIUM = 20;
428 int ALOG2_HOURS_PER_BIENNIUM = 14;
429 int ALOG2_DAYS_PER_BIENNIUM = 10;
430 int LOG2_YEARS_PER_BIENNIUM = 1;
431
432 int approx_requested_biennia =
433 (SHR (year_requested, LOG2_YEARS_PER_BIENNIUM)
434 - SHR (EPOCH_YEAR - TM_YEAR_BASE, LOG2_YEARS_PER_BIENNIUM)
435 + SHR (mday, ALOG2_DAYS_PER_BIENNIUM)
436 + SHR (hour, ALOG2_HOURS_PER_BIENNIUM)
437 + SHR (min, ALOG2_MINUTES_PER_BIENNIUM)
438 + (LEAP_SECONDS_POSSIBLE
439 ? 0
440 : SHR (sec, ALOG2_SECONDS_PER_BIENNIUM)));
441
442 int approx_biennia = SHR (t0, ALOG2_SECONDS_PER_BIENNIUM);
443 int diff = approx_biennia - approx_requested_biennia;
444 int abs_diff = diff < 0 ? - diff : diff;
445
446 /* IRIX 4.0.5 cc miscalculates TIME_T_MIN / 3: it erroneously
447 gives a positive value of 715827882. Setting a variable
448 first then doing math on it seems to work.
449 (ghazi@caip.rutgers.edu) */
450 time_t time_t_max = TIME_T_MAX;
451 time_t time_t_min = TIME_T_MIN;
452 time_t overflow_threshold =
453 (time_t_max / 3 - time_t_min / 3) >> ALOG2_SECONDS_PER_BIENNIUM;
454
455 if (overflow_threshold < abs_diff)
456 {
457 /* Overflow occurred. Try repairing it; this might work if
458 the time zone offset is enough to undo the overflow. */
459 time_t repaired_t0 = -1 - t0;
460 approx_biennia = SHR (repaired_t0, ALOG2_SECONDS_PER_BIENNIUM);
461 diff = approx_biennia - approx_requested_biennia;
462 abs_diff = diff < 0 ? - diff : diff;
463 if (overflow_threshold < abs_diff)
464 return -1;
465 guessed_offset += repaired_t0 - t0;
466 t0 = repaired_t0;
467 }
468 }
469
470 /* Repeatedly use the error to improve the guess. */
471
472 for (t = t1 = t2 = t0, dst2 = 0;
473 (gt = guess_time_tm (year, yday, hour, min, sec, &t,
474 ranged_convert (convert, &t, &tm)),
475 t != gt);
476 t1 = t2, t2 = t, t = gt, dst2 = tm.tm_isdst != 0)
477 if (t == t1 && t != t2
478 && (tm.tm_isdst < 0
479 || (isdst < 0
480 ? dst2 <= (tm.tm_isdst != 0)
481 : (isdst != 0) != (tm.tm_isdst != 0))))
482 /* We can't possibly find a match, as we are oscillating
483 between two values. The requested time probably falls
484 within a spring-forward gap of size GT - T. Follow the common
485 practice in this case, which is to return a time that is GT - T
486 away from the requested time, preferring a time whose
487 tm_isdst differs from the requested value. (If no tm_isdst
488 was requested and only one of the two values has a nonzero
489 tm_isdst, prefer that value.) In practice, this is more
490 useful than returning -1. */
491 goto offset_found;
492 else if (--remaining_probes == 0)
493 return -1;
494
495 /* We have a match. Check whether tm.tm_isdst has the requested
496 value, if any. */
497 if (isdst != tm.tm_isdst && 0 <= isdst && 0 <= tm.tm_isdst)
498 {
499 /* tm.tm_isdst has the wrong value. Look for a neighboring
500 time with the right value, and use its UTC offset.
501
502 Heuristic: probe the adjacent timestamps in both directions,
503 looking for the desired isdst. This should work for all real
504 time zone histories in the tz database. */
505
506 /* Distance between probes when looking for a DST boundary. In
507 tzdata2003a, the shortest period of DST is 601200 seconds
508 (e.g., America/Recife starting 2000-10-08 01:00), and the
509 shortest period of non-DST surrounded by DST is 694800
510 seconds (Africa/Tunis starting 1943-04-17 01:00). Use the
511 minimum of these two values, so we don't miss these short
512 periods when probing. */
513 int stride = 601200;
514
515 /* The longest period of DST in tzdata2003a is 536454000 seconds
516 (e.g., America/Jujuy starting 1946-10-01 01:00). The longest
517 period of non-DST is much longer, but it makes no real sense
518 to search for more than a year of non-DST, so use the DST
519 max. */
520 int duration_max = 536454000;
521
522 /* Search in both directions, so the maximum distance is half
523 the duration; add the stride to avoid off-by-1 problems. */
524 int delta_bound = duration_max / 2 + stride;
525
526 int delta, direction;
527
528 for (delta = stride; delta < delta_bound; delta += stride)
529 for (direction = -1; direction <= 1; direction += 2)
530 if (time_t_int_add_ok (t, delta * direction))
531 {
532 time_t ot = t + delta * direction;
533 struct tm otm;
534 ranged_convert (convert, &ot, &otm);
535 if (otm.tm_isdst == isdst)
536 {
537 /* We found the desired tm_isdst.
538 Extrapolate back to the desired time. */
539 t = guess_time_tm (year, yday, hour, min, sec, &ot, &otm);
540 ranged_convert (convert, &t, &tm);
541 goto offset_found;
542 }
543 }
544 }
545
546 offset_found:
547 *offset = guessed_offset + t - t0;
548
549 if (LEAP_SECONDS_POSSIBLE && sec_requested != tm.tm_sec)
550 {
551 /* Adjust time to reflect the tm_sec requested, not the normalized value.
552 Also, repair any damage from a false match due to a leap second. */
553 int sec_adjustment = (sec == 0 && tm.tm_sec == 60) - sec;
554 if (! time_t_int_add_ok (t, sec_requested))
555 return -1;
556 t1 = t + sec_requested;
557 if (! time_t_int_add_ok (t1, sec_adjustment))
558 return -1;
559 t2 = t1 + sec_adjustment;
560 if (! convert (&t2, &tm))
561 return -1;
562 t = t2;
563 }
564
565 *tp = tm;
566 return t;
567 }
568
569
570 /* FIXME: This should use a signed type wide enough to hold any UTC
571 offset in seconds. 'int' should be good enough for GNU code. We
572 can't fix this unilaterally though, as other modules invoke
573 __mktime_internal. */
574 static time_t localtime_offset;
575
576 /* Convert *TP to a time_t value. */
577 time_t
578 mktime (struct tm *tp)
579 {
580 #ifdef _LIBC
581 /* POSIX.1 8.1.1 requires that whenever mktime() is called, the
582 time zone names contained in the external variable 'tzname' shall
583 be set as if the tzset() function had been called. */
584 __tzset ();
585 #endif
586
587 return __mktime_internal (tp, __localtime_r, &localtime_offset);
588 }
589
590 #ifdef weak_alias
591 weak_alias (mktime, timelocal)
592 #endif
593
594 #ifdef _LIBC
595 libc_hidden_def (mktime)
596 libc_hidden_weak (timelocal)
597 #endif
598 \f
599 #if DEBUG
600
601 static int
602 not_equal_tm (const struct tm *a, const struct tm *b)
603 {
604 return ((a->tm_sec ^ b->tm_sec)
605 | (a->tm_min ^ b->tm_min)
606 | (a->tm_hour ^ b->tm_hour)
607 | (a->tm_mday ^ b->tm_mday)
608 | (a->tm_mon ^ b->tm_mon)
609 | (a->tm_year ^ b->tm_year)
610 | (a->tm_yday ^ b->tm_yday)
611 | (a->tm_isdst ^ b->tm_isdst));
612 }
613
614 static void
615 print_tm (const struct tm *tp)
616 {
617 if (tp)
618 printf ("%04d-%02d-%02d %02d:%02d:%02d yday %03d wday %d isdst %d",
619 tp->tm_year + TM_YEAR_BASE, tp->tm_mon + 1, tp->tm_mday,
620 tp->tm_hour, tp->tm_min, tp->tm_sec,
621 tp->tm_yday, tp->tm_wday, tp->tm_isdst);
622 else
623 printf ("0");
624 }
625
626 static int
627 check_result (time_t tk, struct tm tmk, time_t tl, const struct tm *lt)
628 {
629 if (tk != tl || !lt || not_equal_tm (&tmk, lt))
630 {
631 printf ("mktime (");
632 print_tm (lt);
633 printf (")\nyields (");
634 print_tm (&tmk);
635 printf (") == %ld, should be %ld\n", (long int) tk, (long int) tl);
636 return 1;
637 }
638
639 return 0;
640 }
641
642 int
643 main (int argc, char **argv)
644 {
645 int status = 0;
646 struct tm tm, tmk, tml;
647 struct tm *lt;
648 time_t tk, tl, tl1;
649 char trailer;
650
651 if ((argc == 3 || argc == 4)
652 && (sscanf (argv[1], "%d-%d-%d%c",
653 &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &trailer)
654 == 3)
655 && (sscanf (argv[2], "%d:%d:%d%c",
656 &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &trailer)
657 == 3))
658 {
659 tm.tm_year -= TM_YEAR_BASE;
660 tm.tm_mon--;
661 tm.tm_isdst = argc == 3 ? -1 : atoi (argv[3]);
662 tmk = tm;
663 tl = mktime (&tmk);
664 lt = localtime (&tl);
665 if (lt)
666 {
667 tml = *lt;
668 lt = &tml;
669 }
670 printf ("mktime returns %ld == ", (long int) tl);
671 print_tm (&tmk);
672 printf ("\n");
673 status = check_result (tl, tmk, tl, lt);
674 }
675 else if (argc == 4 || (argc == 5 && strcmp (argv[4], "-") == 0))
676 {
677 time_t from = atol (argv[1]);
678 time_t by = atol (argv[2]);
679 time_t to = atol (argv[3]);
680
681 if (argc == 4)
682 for (tl = from; by < 0 ? to <= tl : tl <= to; tl = tl1)
683 {
684 lt = localtime (&tl);
685 if (lt)
686 {
687 tmk = tml = *lt;
688 tk = mktime (&tmk);
689 status |= check_result (tk, tmk, tl, &tml);
690 }
691 else
692 {
693 printf ("localtime (%ld) yields 0\n", (long int) tl);
694 status = 1;
695 }
696 tl1 = tl + by;
697 if ((tl1 < tl) != (by < 0))
698 break;
699 }
700 else
701 for (tl = from; by < 0 ? to <= tl : tl <= to; tl = tl1)
702 {
703 /* Null benchmark. */
704 lt = localtime (&tl);
705 if (lt)
706 {
707 tmk = tml = *lt;
708 tk = tl;
709 status |= check_result (tk, tmk, tl, &tml);
710 }
711 else
712 {
713 printf ("localtime (%ld) yields 0\n", (long int) tl);
714 status = 1;
715 }
716 tl1 = tl + by;
717 if ((tl1 < tl) != (by < 0))
718 break;
719 }
720 }
721 else
722 printf ("Usage:\
723 \t%s YYYY-MM-DD HH:MM:SS [ISDST] # Test given time.\n\
724 \t%s FROM BY TO # Test values FROM, FROM+BY, ..., TO.\n\
725 \t%s FROM BY TO - # Do not test those values (for benchmark).\n",
726 argv[0], argv[0], argv[0]);
727
728 return status;
729 }
730
731 #endif /* DEBUG */
732 \f
733 /*
734 Local Variables:
735 compile-command: "gcc -DDEBUG -I. -Wall -W -O2 -g mktime.c -o mktime"
736 End:
737 */