Back to index

glibc  2.9
mktime.c
Go to the documentation of this file.
00001 /* Convert a `struct tm' to a time_t value.
00002    Copyright (C) 1993-1999, 2002-2007, 2008 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004    Contributed by Paul Eggert <eggert@twinsun.com>.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 /* Define this to have a standalone program to test this implementation of
00022    mktime.  */
00023 /* #define DEBUG 1 */
00024 
00025 #ifdef HAVE_CONFIG_H
00026 # include <config.h>
00027 #endif
00028 
00029 /* Assume that leap seconds are possible, unless told otherwise.
00030    If the host has a `zic' command with a `-L leapsecondfilename' option,
00031    then it supports leap seconds; otherwise it probably doesn't.  */
00032 #ifndef LEAP_SECONDS_POSSIBLE
00033 # define LEAP_SECONDS_POSSIBLE 1
00034 #endif
00035 
00036 #include <sys/types.h>             /* Some systems define `time_t' here.  */
00037 #include <time.h>
00038 
00039 #include <limits.h>
00040 
00041 #include <string.h>         /* For the real memcpy prototype.  */
00042 
00043 #if DEBUG
00044 # include <stdio.h>
00045 # include <stdlib.h>
00046 /* Make it work even if the system's libc has its own mktime routine.  */
00047 # define mktime my_mktime
00048 #endif /* DEBUG */
00049 
00050 /* Shift A right by B bits portably, by dividing A by 2**B and
00051    truncating towards minus infinity.  A and B should be free of side
00052    effects, and B should be in the range 0 <= B <= INT_BITS - 2, where
00053    INT_BITS is the number of useful bits in an int.  GNU code can
00054    assume that INT_BITS is at least 32.
00055 
00056    ISO C99 says that A >> B is implementation-defined if A < 0.  Some
00057    implementations (e.g., UNICOS 9.0 on a Cray Y-MP EL) don't shift
00058    right in the usual way when A < 0, so SHR falls back on division if
00059    ordinary A >> B doesn't seem to be the usual signed shift.  */
00060 #define SHR(a, b)    \
00061   (-1 >> 1 == -1     \
00062    ? (a) >> (b)             \
00063    : (a) / (1 << (b)) - ((a) % (1 << (b)) < 0))
00064 
00065 /* The extra casts in the following macros work around compiler bugs,
00066    e.g., in Cray C 5.0.3.0.  */
00067 
00068 /* True if the arithmetic type T is an integer type.  bool counts as
00069    an integer.  */
00070 #define TYPE_IS_INTEGER(t) ((t) 1.5 == 1)
00071 
00072 /* True if negative values of the signed integer type T use two's
00073    complement, ones' complement, or signed magnitude representation,
00074    respectively.  Much GNU code assumes two's complement, but some
00075    people like to be portable to all possible C hosts.  */
00076 #define TYPE_TWOS_COMPLEMENT(t) ((t) ~ (t) 0 == (t) -1)
00077 #define TYPE_ONES_COMPLEMENT(t) ((t) ~ (t) 0 == 0)
00078 #define TYPE_SIGNED_MAGNITUDE(t) ((t) ~ (t) 0 < (t) -1)
00079 
00080 /* True if the arithmetic type T is signed.  */
00081 #define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
00082 
00083 /* The maximum and minimum values for the integer type T.  These
00084    macros have undefined behavior if T is signed and has padding bits.
00085    If this is a problem for you, please let us know how to fix it for
00086    your host.  */
00087 #define TYPE_MINIMUM(t) \
00088   ((t) (! TYPE_SIGNED (t) \
00089        ? (t) 0 \
00090        : TYPE_SIGNED_MAGNITUDE (t) \
00091        ? ~ (t) 0 \
00092        : ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1)))
00093 #define TYPE_MAXIMUM(t) \
00094   ((t) (! TYPE_SIGNED (t) \
00095        ? (t) -1 \
00096        : ~ (~ (t) 0 << (sizeof (t) * CHAR_BIT - 1))))
00097 
00098 #ifndef TIME_T_MIN
00099 # define TIME_T_MIN TYPE_MINIMUM (time_t)
00100 #endif
00101 #ifndef TIME_T_MAX
00102 # define TIME_T_MAX TYPE_MAXIMUM (time_t)
00103 #endif
00104 #define TIME_T_MIDPOINT (SHR (TIME_T_MIN + TIME_T_MAX, 1) + 1)
00105 
00106 /* Verify a requirement at compile-time (unlike assert, which is runtime).  */
00107 #define verify(name, assertion) struct name { char a[(assertion) ? 1 : -1]; }
00108 
00109 verify (time_t_is_integer, TYPE_IS_INTEGER (time_t));
00110 verify (twos_complement_arithmetic, TYPE_TWOS_COMPLEMENT (int));
00111 /* The code also assumes that signed integer overflow silently wraps
00112    around, but this assumption can't be stated without causing a
00113    diagnostic on some hosts.  */
00114 
00115 #define EPOCH_YEAR 1970
00116 #define TM_YEAR_BASE 1900
00117 verify (base_year_is_a_multiple_of_100, TM_YEAR_BASE % 100 == 0);
00118 
00119 /* Return 1 if YEAR + TM_YEAR_BASE is a leap year.  */
00120 static inline int
00121 leapyear (long int year)
00122 {
00123   /* Don't add YEAR to TM_YEAR_BASE, as that might overflow.
00124      Also, work even if YEAR is negative.  */
00125   return
00126     ((year & 3) == 0
00127      && (year % 100 != 0
00128         || ((year / 100) & 3) == (- (TM_YEAR_BASE / 100) & 3)));
00129 }
00130 
00131 /* How many days come before each month (0-12).  */
00132 #ifndef _LIBC
00133 static
00134 #endif
00135 const unsigned short int __mon_yday[2][13] =
00136   {
00137     /* Normal years.  */
00138     { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
00139     /* Leap years.  */
00140     { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
00141   };
00142 
00143 
00144 #ifndef _LIBC
00145 /* Portable standalone applications should supply a "time_r.h" that
00146    declares a POSIX-compliant localtime_r, for the benefit of older
00147    implementations that lack localtime_r or have a nonstandard one.
00148    See the gnulib time_r module for one way to implement this.  */
00149 # include "time_r.h"
00150 # undef __localtime_r
00151 # define __localtime_r localtime_r
00152 # define __mktime_internal mktime_internal
00153 #endif
00154 
00155 /* Return an integer value measuring (YEAR1-YDAY1 HOUR1:MIN1:SEC1) -
00156    (YEAR0-YDAY0 HOUR0:MIN0:SEC0) in seconds, assuming that the clocks
00157    were not adjusted between the time stamps.
00158 
00159    The YEAR values uses the same numbering as TP->tm_year.  Values
00160    need not be in the usual range.  However, YEAR1 must not be less
00161    than 2 * INT_MIN or greater than 2 * INT_MAX.
00162 
00163    The result may overflow.  It is the caller's responsibility to
00164    detect overflow.  */
00165 
00166 static inline time_t
00167 ydhms_diff (long int year1, long int yday1, int hour1, int min1, int sec1,
00168            int year0, int yday0, int hour0, int min0, int sec0)
00169 {
00170   verify (C99_integer_division, -1 / 2 == 0);
00171   verify (long_int_year_and_yday_are_wide_enough,
00172          INT_MAX <= LONG_MAX / 2 || TIME_T_MAX <= UINT_MAX);
00173 
00174   /* Compute intervening leap days correctly even if year is negative.
00175      Take care to avoid integer overflow here.  */
00176   int a4 = SHR (year1, 2) + SHR (TM_YEAR_BASE, 2) - ! (year1 & 3);
00177   int b4 = SHR (year0, 2) + SHR (TM_YEAR_BASE, 2) - ! (year0 & 3);
00178   int a100 = a4 / 25 - (a4 % 25 < 0);
00179   int b100 = b4 / 25 - (b4 % 25 < 0);
00180   int a400 = SHR (a100, 2);
00181   int b400 = SHR (b100, 2);
00182   int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
00183 
00184   /* Compute the desired time in time_t precision.  Overflow might
00185      occur here.  */
00186   time_t tyear1 = year1;
00187   time_t years = tyear1 - year0;
00188   time_t days = 365 * years + yday1 - yday0 + intervening_leap_days;
00189   time_t hours = 24 * days + hour1 - hour0;
00190   time_t minutes = 60 * hours + min1 - min0;
00191   time_t seconds = 60 * minutes + sec1 - sec0;
00192   return seconds;
00193 }
00194 
00195 
00196 /* Return a time_t value corresponding to (YEAR-YDAY HOUR:MIN:SEC),
00197    assuming that *T corresponds to *TP and that no clock adjustments
00198    occurred between *TP and the desired time.
00199    If TP is null, return a value not equal to *T; this avoids false matches.
00200    If overflow occurs, yield the minimal or maximal value, except do not
00201    yield a value equal to *T.  */
00202 static time_t
00203 guess_time_tm (long int year, long int yday, int hour, int min, int sec,
00204               const time_t *t, const struct tm *tp)
00205 {
00206   if (tp)
00207     {
00208       time_t d = ydhms_diff (year, yday, hour, min, sec,
00209                           tp->tm_year, tp->tm_yday,
00210                           tp->tm_hour, tp->tm_min, tp->tm_sec);
00211       time_t t1 = *t + d;
00212       if ((t1 < *t) == (TYPE_SIGNED (time_t) ? d < 0 : TIME_T_MAX / 2 < d))
00213        return t1;
00214     }
00215 
00216   /* Overflow occurred one way or another.  Return the nearest result
00217      that is actually in range, except don't report a zero difference
00218      if the actual difference is nonzero, as that would cause a false
00219      match; and don't oscillate between two values, as that would
00220      confuse the spring-forward gap detector.  */
00221   return (*t < TIME_T_MIDPOINT
00222          ? (*t <= TIME_T_MIN + 1 ? *t + 1 : TIME_T_MIN)
00223          : (TIME_T_MAX - 1 <= *t ? *t - 1 : TIME_T_MAX));
00224 }
00225 
00226 /* Use CONVERT to convert *T to a broken down time in *TP.
00227    If *T is out of range for conversion, adjust it so that
00228    it is the nearest in-range value and then convert that.  */
00229 static struct tm *
00230 ranged_convert (struct tm *(*convert) (const time_t *, struct tm *),
00231               time_t *t, struct tm *tp)
00232 {
00233   struct tm *r = convert (t, tp);
00234 
00235   if (!r && *t)
00236     {
00237       time_t bad = *t;
00238       time_t ok = 0;
00239 
00240       /* BAD is a known unconvertible time_t, and OK is a known good one.
00241         Use binary search to narrow the range between BAD and OK until
00242         they differ by 1.  */
00243       while (bad != ok + (bad < 0 ? -1 : 1))
00244        {
00245          time_t mid = *t = (bad < 0
00246                           ? bad + ((ok - bad) >> 1)
00247                           : ok + ((bad - ok) >> 1));
00248          r = convert (t, tp);
00249          if (r)
00250            ok = mid;
00251          else
00252            bad = mid;
00253        }
00254 
00255       if (!r && ok)
00256        {
00257          /* The last conversion attempt failed;
00258             revert to the most recent successful attempt.  */
00259          *t = ok;
00260          r = convert (t, tp);
00261        }
00262     }
00263 
00264   return r;
00265 }
00266 
00267 
00268 /* Convert *TP to a time_t value, inverting
00269    the monotonic and mostly-unit-linear conversion function CONVERT.
00270    Use *OFFSET to keep track of a guess at the offset of the result,
00271    compared to what the result would be for UTC without leap seconds.
00272    If *OFFSET's guess is correct, only one CONVERT call is needed.
00273    This function is external because it is used also by timegm.c.  */
00274 time_t
00275 __mktime_internal (struct tm *tp,
00276                  struct tm *(*convert) (const time_t *, struct tm *),
00277                  time_t *offset)
00278 {
00279   time_t t, gt, t0, t1, t2;
00280   struct tm tm;
00281 
00282   /* The maximum number of probes (calls to CONVERT) should be enough
00283      to handle any combinations of time zone rule changes, solar time,
00284      leap seconds, and oscillations around a spring-forward gap.
00285      POSIX.1 prohibits leap seconds, but some hosts have them anyway.  */
00286   int remaining_probes = 6;
00287 
00288   /* Time requested.  Copy it in case CONVERT modifies *TP; this can
00289      occur if TP is localtime's returned value and CONVERT is localtime.  */
00290   int sec = tp->tm_sec;
00291   int min = tp->tm_min;
00292   int hour = tp->tm_hour;
00293   int mday = tp->tm_mday;
00294   int mon = tp->tm_mon;
00295   int year_requested = tp->tm_year;
00296   /* Normalize the value.  */
00297   int isdst = ((tp->tm_isdst >> (8 * sizeof (tp->tm_isdst) - 1))
00298               | (tp->tm_isdst != 0));
00299 
00300   /* 1 if the previous probe was DST.  */
00301   int dst2;
00302 
00303   /* Ensure that mon is in range, and set year accordingly.  */
00304   int mon_remainder = mon % 12;
00305   int negative_mon_remainder = mon_remainder < 0;
00306   int mon_years = mon / 12 - negative_mon_remainder;
00307   long int lyear_requested = year_requested;
00308   long int year = lyear_requested + mon_years;
00309 
00310   /* The other values need not be in range:
00311      the remaining code handles minor overflows correctly,
00312      assuming int and time_t arithmetic wraps around.
00313      Major overflows are caught at the end.  */
00314 
00315   /* Calculate day of year from year, month, and day of month.
00316      The result need not be in range.  */
00317   int mon_yday = ((__mon_yday[leapyear (year)]
00318                  [mon_remainder + 12 * negative_mon_remainder])
00319                 - 1);
00320   long int lmday = mday;
00321   long int yday = mon_yday + lmday;
00322 
00323   time_t guessed_offset = *offset;
00324 
00325   int sec_requested = sec;
00326 
00327   if (LEAP_SECONDS_POSSIBLE)
00328     {
00329       /* Handle out-of-range seconds specially,
00330         since ydhms_tm_diff assumes every minute has 60 seconds.  */
00331       if (sec < 0)
00332        sec = 0;
00333       if (59 < sec)
00334        sec = 59;
00335     }
00336 
00337   /* Invert CONVERT by probing.  First assume the same offset as last
00338      time.  */
00339 
00340   t0 = ydhms_diff (year, yday, hour, min, sec,
00341                  EPOCH_YEAR - TM_YEAR_BASE, 0, 0, 0, - guessed_offset);
00342 
00343   if (TIME_T_MAX / INT_MAX / 366 / 24 / 60 / 60 < 3)
00344     {
00345       /* time_t isn't large enough to rule out overflows, so check
00346         for major overflows.  A gross check suffices, since if t0
00347         has overflowed, it is off by a multiple of TIME_T_MAX -
00348         TIME_T_MIN + 1.  So ignore any component of the difference
00349         that is bounded by a small value.  */
00350 
00351       /* Approximate log base 2 of the number of time units per
00352         biennium.  A biennium is 2 years; use this unit instead of
00353         years to avoid integer overflow.  For example, 2 average
00354         Gregorian years are 2 * 365.2425 * 24 * 60 * 60 seconds,
00355         which is 63113904 seconds, and rint (log2 (63113904)) is
00356         26.  */
00357       int ALOG2_SECONDS_PER_BIENNIUM = 26;
00358       int ALOG2_MINUTES_PER_BIENNIUM = 20;
00359       int ALOG2_HOURS_PER_BIENNIUM = 14;
00360       int ALOG2_DAYS_PER_BIENNIUM = 10;
00361       int LOG2_YEARS_PER_BIENNIUM = 1;
00362 
00363       int approx_requested_biennia =
00364        (SHR (year_requested, LOG2_YEARS_PER_BIENNIUM)
00365         - SHR (EPOCH_YEAR - TM_YEAR_BASE, LOG2_YEARS_PER_BIENNIUM)
00366         + SHR (mday, ALOG2_DAYS_PER_BIENNIUM)
00367         + SHR (hour, ALOG2_HOURS_PER_BIENNIUM)
00368         + SHR (min, ALOG2_MINUTES_PER_BIENNIUM)
00369         + (LEAP_SECONDS_POSSIBLE
00370            ? 0
00371            : SHR (sec, ALOG2_SECONDS_PER_BIENNIUM)));
00372 
00373       int approx_biennia = SHR (t0, ALOG2_SECONDS_PER_BIENNIUM);
00374       int diff = approx_biennia - approx_requested_biennia;
00375       int abs_diff = diff < 0 ? - diff : diff;
00376 
00377       /* IRIX 4.0.5 cc miscalculates TIME_T_MIN / 3: it erroneously
00378         gives a positive value of 715827882.  Setting a variable
00379         first then doing math on it seems to work.
00380         (ghazi@caip.rutgers.edu) */
00381       time_t time_t_max = TIME_T_MAX;
00382       time_t time_t_min = TIME_T_MIN;
00383       time_t overflow_threshold =
00384        (time_t_max / 3 - time_t_min / 3) >> ALOG2_SECONDS_PER_BIENNIUM;
00385 
00386       if (overflow_threshold < abs_diff)
00387        {
00388          /* Overflow occurred.  Try repairing it; this might work if
00389             the time zone offset is enough to undo the overflow.  */
00390          time_t repaired_t0 = -1 - t0;
00391          approx_biennia = SHR (repaired_t0, ALOG2_SECONDS_PER_BIENNIUM);
00392          diff = approx_biennia - approx_requested_biennia;
00393          abs_diff = diff < 0 ? - diff : diff;
00394          if (overflow_threshold < abs_diff)
00395            return -1;
00396          guessed_offset += repaired_t0 - t0;
00397          t0 = repaired_t0;
00398        }
00399     }
00400 
00401   /* Repeatedly use the error to improve the guess.  */
00402 
00403   for (t = t1 = t2 = t0, dst2 = 0;
00404        (gt = guess_time_tm (year, yday, hour, min, sec, &t,
00405                          ranged_convert (convert, &t, &tm)),
00406        t != gt);
00407        t1 = t2, t2 = t, t = gt, dst2 = tm.tm_isdst != 0)
00408     if (t == t1 && t != t2
00409        && (tm.tm_isdst < 0
00410            || (isdst < 0
00411               ? dst2 <= (tm.tm_isdst != 0)
00412               : (isdst != 0) != (tm.tm_isdst != 0))))
00413       /* We can't possibly find a match, as we are oscillating
00414         between two values.  The requested time probably falls
00415         within a spring-forward gap of size GT - T.  Follow the common
00416         practice in this case, which is to return a time that is GT - T
00417         away from the requested time, preferring a time whose
00418         tm_isdst differs from the requested value.  (If no tm_isdst
00419         was requested and only one of the two values has a nonzero
00420         tm_isdst, prefer that value.)  In practice, this is more
00421         useful than returning -1.  */
00422       goto offset_found;
00423     else if (--remaining_probes == 0)
00424       return -1;
00425 
00426   /* We have a match.  Check whether tm.tm_isdst has the requested
00427      value, if any.  */
00428   if (isdst != tm.tm_isdst && 0 <= isdst && 0 <= tm.tm_isdst)
00429     {
00430       /* tm.tm_isdst has the wrong value.  Look for a neighboring
00431         time with the right value, and use its UTC offset.
00432 
00433         Heuristic: probe the adjacent timestamps in both directions,
00434         looking for the desired isdst.  This should work for all real
00435         time zone histories in the tz database.  */
00436 
00437       /* Distance between probes when looking for a DST boundary.  In
00438         tzdata2003a, the shortest period of DST is 601200 seconds
00439         (e.g., America/Recife starting 2000-10-08 01:00), and the
00440         shortest period of non-DST surrounded by DST is 694800
00441         seconds (Africa/Tunis starting 1943-04-17 01:00).  Use the
00442         minimum of these two values, so we don't miss these short
00443         periods when probing.  */
00444       int stride = 601200;
00445 
00446       /* The longest period of DST in tzdata2003a is 536454000 seconds
00447         (e.g., America/Jujuy starting 1946-10-01 01:00).  The longest
00448         period of non-DST is much longer, but it makes no real sense
00449         to search for more than a year of non-DST, so use the DST
00450         max.  */
00451       int duration_max = 536454000;
00452 
00453       /* Search in both directions, so the maximum distance is half
00454         the duration; add the stride to avoid off-by-1 problems.  */
00455       int delta_bound = duration_max / 2 + stride;
00456 
00457       int delta, direction;
00458 
00459       for (delta = stride; delta < delta_bound; delta += stride)
00460        for (direction = -1; direction <= 1; direction += 2)
00461          {
00462            time_t ot = t + delta * direction;
00463            if ((ot < t) == (direction < 0))
00464              {
00465               struct tm otm;
00466               ranged_convert (convert, &ot, &otm);
00467               if (otm.tm_isdst == isdst)
00468                 {
00469                   /* We found the desired tm_isdst.
00470                      Extrapolate back to the desired time.  */
00471                   t = guess_time_tm (year, yday, hour, min, sec, &ot, &otm);
00472                   ranged_convert (convert, &t, &tm);
00473                   goto offset_found;
00474                 }
00475              }
00476          }
00477     }
00478 
00479  offset_found:
00480   *offset = guessed_offset + t - t0;
00481 
00482   if (LEAP_SECONDS_POSSIBLE && sec_requested != tm.tm_sec)
00483     {
00484       /* Adjust time to reflect the tm_sec requested, not the normalized value.
00485         Also, repair any damage from a false match due to a leap second.  */
00486       int sec_adjustment = (sec == 0 && tm.tm_sec == 60) - sec;
00487       t1 = t + sec_requested;
00488       t2 = t1 + sec_adjustment;
00489       if (((t1 < t) != (sec_requested < 0))
00490          | ((t2 < t1) != (sec_adjustment < 0))
00491          | ! convert (&t2, &tm))
00492        return -1;
00493       t = t2;
00494     }
00495 
00496   *tp = tm;
00497   return t;
00498 }
00499 
00500 
00501 /* FIXME: This should use a signed type wide enough to hold any UTC
00502    offset in seconds.  'int' should be good enough for GNU code.  We
00503    can't fix this unilaterally though, as other modules invoke
00504    __mktime_internal.  */
00505 static time_t localtime_offset;
00506 
00507 /* Convert *TP to a time_t value.  */
00508 time_t
00509 mktime (struct tm *tp)
00510 {
00511 #ifdef _LIBC
00512   /* POSIX.1 8.1.1 requires that whenever mktime() is called, the
00513      time zone names contained in the external variable `tzname' shall
00514      be set as if the tzset() function had been called.  */
00515   __tzset ();
00516 #endif
00517 
00518   return __mktime_internal (tp, __localtime_r, &localtime_offset);
00519 }
00520 
00521 #ifdef weak_alias
00522 weak_alias (mktime, timelocal)
00523 #endif
00524 
00525 #ifdef _LIBC
00526 libc_hidden_def (mktime)
00527 libc_hidden_weak (timelocal)
00528 #endif
00529 
00530 #if DEBUG
00531 
00532 static int
00533 not_equal_tm (const struct tm *a, const struct tm *b)
00534 {
00535   return ((a->tm_sec ^ b->tm_sec)
00536          | (a->tm_min ^ b->tm_min)
00537          | (a->tm_hour ^ b->tm_hour)
00538          | (a->tm_mday ^ b->tm_mday)
00539          | (a->tm_mon ^ b->tm_mon)
00540          | (a->tm_year ^ b->tm_year)
00541          | (a->tm_yday ^ b->tm_yday)
00542          | (a->tm_isdst ^ b->tm_isdst));
00543 }
00544 
00545 static void
00546 print_tm (const struct tm *tp)
00547 {
00548   if (tp)
00549     printf ("%04d-%02d-%02d %02d:%02d:%02d yday %03d wday %d isdst %d",
00550            tp->tm_year + TM_YEAR_BASE, tp->tm_mon + 1, tp->tm_mday,
00551            tp->tm_hour, tp->tm_min, tp->tm_sec,
00552            tp->tm_yday, tp->tm_wday, tp->tm_isdst);
00553   else
00554     printf ("0");
00555 }
00556 
00557 static int
00558 check_result (time_t tk, struct tm tmk, time_t tl, const struct tm *lt)
00559 {
00560   if (tk != tl || !lt || not_equal_tm (&tmk, lt))
00561     {
00562       printf ("mktime (");
00563       print_tm (lt);
00564       printf (")\nyields (");
00565       print_tm (&tmk);
00566       printf (") == %ld, should be %ld\n", (long int) tk, (long int) tl);
00567       return 1;
00568     }
00569 
00570   return 0;
00571 }
00572 
00573 int
00574 main (int argc, char **argv)
00575 {
00576   int status = 0;
00577   struct tm tm, tmk, tml;
00578   struct tm *lt;
00579   time_t tk, tl, tl1;
00580   char trailer;
00581 
00582   if ((argc == 3 || argc == 4)
00583       && (sscanf (argv[1], "%d-%d-%d%c",
00584                 &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &trailer)
00585          == 3)
00586       && (sscanf (argv[2], "%d:%d:%d%c",
00587                 &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &trailer)
00588          == 3))
00589     {
00590       tm.tm_year -= TM_YEAR_BASE;
00591       tm.tm_mon--;
00592       tm.tm_isdst = argc == 3 ? -1 : atoi (argv[3]);
00593       tmk = tm;
00594       tl = mktime (&tmk);
00595       lt = localtime (&tl);
00596       if (lt)
00597        {
00598          tml = *lt;
00599          lt = &tml;
00600        }
00601       printf ("mktime returns %ld == ", (long int) tl);
00602       print_tm (&tmk);
00603       printf ("\n");
00604       status = check_result (tl, tmk, tl, lt);
00605     }
00606   else if (argc == 4 || (argc == 5 && strcmp (argv[4], "-") == 0))
00607     {
00608       time_t from = atol (argv[1]);
00609       time_t by = atol (argv[2]);
00610       time_t to = atol (argv[3]);
00611 
00612       if (argc == 4)
00613        for (tl = from; by < 0 ? to <= tl : tl <= to; tl = tl1)
00614          {
00615            lt = localtime (&tl);
00616            if (lt)
00617              {
00618               tmk = tml = *lt;
00619               tk = mktime (&tmk);
00620               status |= check_result (tk, tmk, tl, &tml);
00621              }
00622            else
00623              {
00624               printf ("localtime (%ld) yields 0\n", (long int) tl);
00625               status = 1;
00626              }
00627            tl1 = tl + by;
00628            if ((tl1 < tl) != (by < 0))
00629              break;
00630          }
00631       else
00632        for (tl = from; by < 0 ? to <= tl : tl <= to; tl = tl1)
00633          {
00634            /* Null benchmark.  */
00635            lt = localtime (&tl);
00636            if (lt)
00637              {
00638               tmk = tml = *lt;
00639               tk = tl;
00640               status |= check_result (tk, tmk, tl, &tml);
00641              }
00642            else
00643              {
00644               printf ("localtime (%ld) yields 0\n", (long int) tl);
00645               status = 1;
00646              }
00647            tl1 = tl + by;
00648            if ((tl1 < tl) != (by < 0))
00649              break;
00650          }
00651     }
00652   else
00653     printf ("Usage:\
00654 \t%s YYYY-MM-DD HH:MM:SS [ISDST] # Test given time.\n\
00655 \t%s FROM BY TO # Test values FROM, FROM+BY, ..., TO.\n\
00656 \t%s FROM BY TO - # Do not test those values (for benchmark).\n",
00657            argv[0], argv[0], argv[0]);
00658 
00659   return status;
00660 }
00661 
00662 #endif /* DEBUG */
00663 
00664 /*
00665 Local Variables:
00666 compile-command: "gcc -DDEBUG -Wall -W -O -g mktime.c -o mktime"
00667 End:
00668 */