xref: /dflybsd-src/contrib/cvs-1.12/lib/mktime.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
186d7f5d3SJohn Marino /* Convert a `struct tm' to a time_t value.
286d7f5d3SJohn Marino    Copyright (C) 1993-1999, 2002-2004, 2005 Free Software Foundation, Inc.
386d7f5d3SJohn Marino    This file is part of the GNU C Library.
486d7f5d3SJohn Marino    Contributed by Paul Eggert (eggert@twinsun.com).
586d7f5d3SJohn Marino 
686d7f5d3SJohn Marino    This program is free software; you can redistribute it and/or modify
786d7f5d3SJohn Marino    it under the terms of the GNU General Public License as published by
886d7f5d3SJohn Marino    the Free Software Foundation; either version 2, or (at your option)
986d7f5d3SJohn Marino    any later version.
1086d7f5d3SJohn Marino 
1186d7f5d3SJohn Marino    This program is distributed in the hope that it will be useful,
1286d7f5d3SJohn Marino    but WITHOUT ANY WARRANTY; without even the implied warranty of
1386d7f5d3SJohn Marino    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1486d7f5d3SJohn Marino    GNU General Public License for more details.
1586d7f5d3SJohn Marino 
1686d7f5d3SJohn Marino    You should have received a copy of the GNU General Public License along
1786d7f5d3SJohn Marino    with this program; if not, write to the Free Software Foundation,
1886d7f5d3SJohn Marino    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
1986d7f5d3SJohn Marino 
2086d7f5d3SJohn Marino /* Define this to have a standalone program to test this implementation of
2186d7f5d3SJohn Marino    mktime.  */
2286d7f5d3SJohn Marino /* #define DEBUG 1 */
2386d7f5d3SJohn Marino 
2486d7f5d3SJohn Marino #ifdef HAVE_CONFIG_H
2586d7f5d3SJohn Marino # include <config.h>
2686d7f5d3SJohn Marino #endif
2786d7f5d3SJohn Marino 
2886d7f5d3SJohn Marino /* Assume that leap seconds are possible, unless told otherwise.
2986d7f5d3SJohn Marino    If the host has a `zic' command with a `-L leapsecondfilename' option,
3086d7f5d3SJohn Marino    then it supports leap seconds; otherwise it probably doesn't.  */
3186d7f5d3SJohn Marino #ifndef LEAP_SECONDS_POSSIBLE
3286d7f5d3SJohn Marino # define LEAP_SECONDS_POSSIBLE 1
3386d7f5d3SJohn Marino #endif
3486d7f5d3SJohn Marino 
3586d7f5d3SJohn Marino #include <sys/types.h>		/* Some systems define `time_t' here.  */
3686d7f5d3SJohn Marino #include <time.h>
3786d7f5d3SJohn Marino 
3886d7f5d3SJohn Marino #include <limits.h>
3986d7f5d3SJohn Marino 
4086d7f5d3SJohn Marino #include <string.h>		/* For the real memcpy prototype.  */
4186d7f5d3SJohn Marino 
4286d7f5d3SJohn Marino #if DEBUG
4386d7f5d3SJohn Marino # include <stdio.h>
4486d7f5d3SJohn Marino # include <stdlib.h>
4586d7f5d3SJohn Marino /* Make it work even if the system's libc has its own mktime routine.  */
4686d7f5d3SJohn Marino # define mktime my_mktime
4786d7f5d3SJohn Marino #endif /* DEBUG */
4886d7f5d3SJohn Marino 
4986d7f5d3SJohn Marino /* Shift A right by B bits portably, by dividing A by 2**B and
5086d7f5d3SJohn Marino    truncating towards minus infinity.  A and B should be free of side
5186d7f5d3SJohn Marino    effects, and B should be in the range 0 <= B <= INT_BITS - 2, where
5286d7f5d3SJohn Marino    INT_BITS is the number of useful bits in an int.  GNU code can
5386d7f5d3SJohn Marino    assume that INT_BITS is at least 32.
5486d7f5d3SJohn Marino 
5586d7f5d3SJohn Marino    ISO C99 says that A >> B is implementation-defined if A < 0.  Some
5686d7f5d3SJohn Marino    implementations (e.g., UNICOS 9.0 on a Cray Y-MP EL) don't shift
5786d7f5d3SJohn Marino    right in the usual way when A < 0, so SHR falls back on division if
5886d7f5d3SJohn Marino    ordinary A >> B doesn't seem to be the usual signed shift.  */
5986d7f5d3SJohn Marino #define SHR(a, b)	\
6086d7f5d3SJohn Marino   (-1 >> 1 == -1	\
6186d7f5d3SJohn Marino    ? (a) >> (b)		\
6286d7f5d3SJohn Marino    : (a) / (1 << (b)) - ((a) % (1 << (b)) < 0))
6386d7f5d3SJohn Marino 
6486d7f5d3SJohn Marino /* The extra casts in the following macros work around compiler bugs,
6586d7f5d3SJohn Marino    e.g., in Cray C 5.0.3.0.  */
6686d7f5d3SJohn Marino 
6786d7f5d3SJohn Marino /* True if the arithmetic type T is an integer type.  bool counts as
6886d7f5d3SJohn Marino    an integer.  */
6986d7f5d3SJohn Marino #define TYPE_IS_INTEGER(t) ((t) 1.5 == 1)
7086d7f5d3SJohn Marino 
7186d7f5d3SJohn Marino /* True if negative values of the signed integer type T use two's
7286d7f5d3SJohn Marino    complement, ones' complement, or signed magnitude representation,
7386d7f5d3SJohn Marino    respectively.  Much GNU code assumes two's complement, but some
7486d7f5d3SJohn Marino    people like to be portable to all possible C hosts.  */
7586d7f5d3SJohn Marino #define TYPE_TWOS_COMPLEMENT(t) ((t) ~ (t) 0 == (t) -1)
7686d7f5d3SJohn Marino #define TYPE_ONES_COMPLEMENT(t) ((t) ~ (t) 0 == 0)
7786d7f5d3SJohn Marino #define TYPE_SIGNED_MAGNITUDE(t) ((t) ~ (t) 0 < (t) -1)
7886d7f5d3SJohn Marino 
7986d7f5d3SJohn Marino /* True if the arithmetic type T is signed.  */
8086d7f5d3SJohn Marino #define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
8186d7f5d3SJohn Marino 
8286d7f5d3SJohn Marino /* The maximum and minimum values for the integer type T.  These
8386d7f5d3SJohn Marino    macros have undefined behavior if T is signed and has padding bits.
8486d7f5d3SJohn Marino    If this is a problem for you, please let us know how to fix it for
8586d7f5d3SJohn Marino    your host.  */
8686d7f5d3SJohn Marino #define TYPE_MINIMUM(t) \
8786d7f5d3SJohn Marino   ((t) (! TYPE_SIGNED (t) \
8886d7f5d3SJohn Marino 	? (t) 0 \
8986d7f5d3SJohn Marino 	: TYPE_SIGNED_MAGNITUDE (t) \
9086d7f5d3SJohn Marino 	? ~ (t) 0 \
9186d7f5d3SJohn Marino 	: ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1)))
9286d7f5d3SJohn Marino #define TYPE_MAXIMUM(t) \
9386d7f5d3SJohn Marino   ((t) (! TYPE_SIGNED (t) \
9486d7f5d3SJohn Marino 	? (t) -1 \
9586d7f5d3SJohn Marino 	: ~ (~ (t) 0 << (sizeof (t) * CHAR_BIT - 1))))
9686d7f5d3SJohn Marino 
9786d7f5d3SJohn Marino #ifndef TIME_T_MIN
9886d7f5d3SJohn Marino # define TIME_T_MIN TYPE_MINIMUM (time_t)
9986d7f5d3SJohn Marino #endif
10086d7f5d3SJohn Marino #ifndef TIME_T_MAX
10186d7f5d3SJohn Marino # define TIME_T_MAX TYPE_MAXIMUM (time_t)
10286d7f5d3SJohn Marino #endif
10386d7f5d3SJohn Marino #define TIME_T_MIDPOINT (SHR (TIME_T_MIN + TIME_T_MAX, 1) + 1)
10486d7f5d3SJohn Marino 
10586d7f5d3SJohn Marino /* Verify a requirement at compile-time (unlike assert, which is runtime).  */
10686d7f5d3SJohn Marino #define verify(name, assertion) struct name { char a[(assertion) ? 1 : -1]; }
10786d7f5d3SJohn Marino 
10886d7f5d3SJohn Marino verify (time_t_is_integer, TYPE_IS_INTEGER (time_t));
10986d7f5d3SJohn Marino verify (twos_complement_arithmetic, TYPE_TWOS_COMPLEMENT (int));
11086d7f5d3SJohn Marino /* The code also assumes that signed integer overflow silently wraps
11186d7f5d3SJohn Marino    around, but this assumption can't be stated without causing a
11286d7f5d3SJohn Marino    diagnostic on some hosts.  */
11386d7f5d3SJohn Marino 
11486d7f5d3SJohn Marino #define EPOCH_YEAR 1970
11586d7f5d3SJohn Marino #define TM_YEAR_BASE 1900
11686d7f5d3SJohn Marino verify (base_year_is_a_multiple_of_100, TM_YEAR_BASE % 100 == 0);
11786d7f5d3SJohn Marino 
11886d7f5d3SJohn Marino /* Return 1 if YEAR + TM_YEAR_BASE is a leap year.  */
11986d7f5d3SJohn Marino static inline int
leapyear(long int year)12086d7f5d3SJohn Marino leapyear (long int year)
12186d7f5d3SJohn Marino {
12286d7f5d3SJohn Marino   /* Don't add YEAR to TM_YEAR_BASE, as that might overflow.
12386d7f5d3SJohn Marino      Also, work even if YEAR is negative.  */
12486d7f5d3SJohn Marino   return
12586d7f5d3SJohn Marino     ((year & 3) == 0
12686d7f5d3SJohn Marino      && (year % 100 != 0
12786d7f5d3SJohn Marino 	 || ((year / 100) & 3) == (- (TM_YEAR_BASE / 100) & 3)));
12886d7f5d3SJohn Marino }
12986d7f5d3SJohn Marino 
13086d7f5d3SJohn Marino /* How many days come before each month (0-12).  */
13186d7f5d3SJohn Marino #ifndef _LIBC
13286d7f5d3SJohn Marino static
13386d7f5d3SJohn Marino #endif
13486d7f5d3SJohn Marino const unsigned short int __mon_yday[2][13] =
13586d7f5d3SJohn Marino   {
13686d7f5d3SJohn Marino     /* Normal years.  */
13786d7f5d3SJohn Marino     { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
13886d7f5d3SJohn Marino     /* Leap years.  */
13986d7f5d3SJohn Marino     { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
14086d7f5d3SJohn Marino   };
14186d7f5d3SJohn Marino 
14286d7f5d3SJohn Marino 
14386d7f5d3SJohn Marino #ifndef _LIBC
14486d7f5d3SJohn Marino /* Portable standalone applications should supply a "time_r.h" that
14586d7f5d3SJohn Marino    declares a POSIX-compliant localtime_r, for the benefit of older
14686d7f5d3SJohn Marino    implementations that lack localtime_r or have a nonstandard one.
14786d7f5d3SJohn Marino    See the gnulib time_r module for one way to implement this.  */
14886d7f5d3SJohn Marino # include "time_r.h"
14986d7f5d3SJohn Marino # undef __localtime_r
15086d7f5d3SJohn Marino # define __localtime_r localtime_r
15186d7f5d3SJohn Marino # define __mktime_internal mktime_internal
15286d7f5d3SJohn Marino #endif
15386d7f5d3SJohn Marino 
15486d7f5d3SJohn Marino /* Return an integer value measuring (YEAR1-YDAY1 HOUR1:MIN1:SEC1) -
15586d7f5d3SJohn Marino    (YEAR0-YDAY0 HOUR0:MIN0:SEC0) in seconds, assuming that the clocks
15686d7f5d3SJohn Marino    were not adjusted between the time stamps.
15786d7f5d3SJohn Marino 
15886d7f5d3SJohn Marino    The YEAR values uses the same numbering as TP->tm_year.  Values
15986d7f5d3SJohn Marino    need not be in the usual range.  However, YEAR1 must not be less
16086d7f5d3SJohn Marino    than 2 * INT_MIN or greater than 2 * INT_MAX.
16186d7f5d3SJohn Marino 
16286d7f5d3SJohn Marino    The result may overflow.  It is the caller's responsibility to
16386d7f5d3SJohn Marino    detect overflow.  */
16486d7f5d3SJohn Marino 
16586d7f5d3SJohn Marino static inline time_t
ydhms_diff(long int year1,long int yday1,int hour1,int min1,int sec1,int year0,int yday0,int hour0,int min0,int sec0)16686d7f5d3SJohn Marino ydhms_diff (long int year1, long int yday1, int hour1, int min1, int sec1,
16786d7f5d3SJohn Marino 	    int year0, int yday0, int hour0, int min0, int sec0)
16886d7f5d3SJohn Marino {
16986d7f5d3SJohn Marino   verify (C99_integer_division, -1 / 2 == 0);
17086d7f5d3SJohn Marino   verify (long_int_year_and_yday_are_wide_enough,
17186d7f5d3SJohn Marino 	  INT_MAX <= LONG_MAX / 2 || TIME_T_MAX <= UINT_MAX);
17286d7f5d3SJohn Marino 
17386d7f5d3SJohn Marino   /* Compute intervening leap days correctly even if year is negative.
17486d7f5d3SJohn Marino      Take care to avoid integer overflow here.  */
17586d7f5d3SJohn Marino   int a4 = SHR (year1, 2) + SHR (TM_YEAR_BASE, 2) - ! (year1 & 3);
17686d7f5d3SJohn Marino   int b4 = SHR (year0, 2) + SHR (TM_YEAR_BASE, 2) - ! (year0 & 3);
17786d7f5d3SJohn Marino   int a100 = a4 / 25 - (a4 % 25 < 0);
17886d7f5d3SJohn Marino   int b100 = b4 / 25 - (b4 % 25 < 0);
17986d7f5d3SJohn Marino   int a400 = SHR (a100, 2);
18086d7f5d3SJohn Marino   int b400 = SHR (b100, 2);
18186d7f5d3SJohn Marino   int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
18286d7f5d3SJohn Marino 
18386d7f5d3SJohn Marino   /* Compute the desired time in time_t precision.  Overflow might
18486d7f5d3SJohn Marino      occur here.  */
18586d7f5d3SJohn Marino   time_t tyear1 = year1;
18686d7f5d3SJohn Marino   time_t years = tyear1 - year0;
18786d7f5d3SJohn Marino   time_t days = 365 * years + yday1 - yday0 + intervening_leap_days;
18886d7f5d3SJohn Marino   time_t hours = 24 * days + hour1 - hour0;
18986d7f5d3SJohn Marino   time_t minutes = 60 * hours + min1 - min0;
19086d7f5d3SJohn Marino   time_t seconds = 60 * minutes + sec1 - sec0;
19186d7f5d3SJohn Marino   return seconds;
19286d7f5d3SJohn Marino }
19386d7f5d3SJohn Marino 
19486d7f5d3SJohn Marino 
19586d7f5d3SJohn Marino /* Return a time_t value corresponding to (YEAR-YDAY HOUR:MIN:SEC),
19686d7f5d3SJohn Marino    assuming that *T corresponds to *TP and that no clock adjustments
19786d7f5d3SJohn Marino    occurred between *TP and the desired time.
19886d7f5d3SJohn Marino    If TP is null, return a value not equal to *T; this avoids false matches.
19986d7f5d3SJohn Marino    If overflow occurs, yield the minimal or maximal value, except do not
20086d7f5d3SJohn Marino    yield a value equal to *T.  */
20186d7f5d3SJohn Marino static time_t
guess_time_tm(long int year,long int yday,int hour,int min,int sec,const time_t * t,const struct tm * tp)20286d7f5d3SJohn Marino guess_time_tm (long int year, long int yday, int hour, int min, int sec,
20386d7f5d3SJohn Marino 	       const time_t *t, const struct tm *tp)
20486d7f5d3SJohn Marino {
20586d7f5d3SJohn Marino   if (tp)
20686d7f5d3SJohn Marino     {
20786d7f5d3SJohn Marino       time_t d = ydhms_diff (year, yday, hour, min, sec,
20886d7f5d3SJohn Marino 			     tp->tm_year, tp->tm_yday,
20986d7f5d3SJohn Marino 			     tp->tm_hour, tp->tm_min, tp->tm_sec);
21086d7f5d3SJohn Marino       time_t t1 = *t + d;
21186d7f5d3SJohn Marino       if ((t1 < *t) == (TYPE_SIGNED (time_t) ? d < 0 : TIME_T_MAX / 2 < d))
21286d7f5d3SJohn Marino 	return t1;
21386d7f5d3SJohn Marino     }
21486d7f5d3SJohn Marino 
21586d7f5d3SJohn Marino   /* Overflow occurred one way or another.  Return the nearest result
21686d7f5d3SJohn Marino      that is actually in range, except don't report a zero difference
21786d7f5d3SJohn Marino      if the actual difference is nonzero, as that would cause a false
21886d7f5d3SJohn Marino      match.  */
21986d7f5d3SJohn Marino   return (*t < TIME_T_MIDPOINT
22086d7f5d3SJohn Marino 	  ? TIME_T_MIN + (*t == TIME_T_MIN)
22186d7f5d3SJohn Marino 	  : TIME_T_MAX - (*t == TIME_T_MAX));
22286d7f5d3SJohn Marino }
22386d7f5d3SJohn Marino 
22486d7f5d3SJohn Marino /* Use CONVERT to convert *T to a broken down time in *TP.
22586d7f5d3SJohn Marino    If *T is out of range for conversion, adjust it so that
22686d7f5d3SJohn Marino    it is the nearest in-range value and then convert that.  */
22786d7f5d3SJohn Marino static struct tm *
ranged_convert(struct tm * (* convert)(const time_t *,struct tm *),time_t * t,struct tm * tp)22886d7f5d3SJohn Marino ranged_convert (struct tm *(*convert) (const time_t *, struct tm *),
22986d7f5d3SJohn Marino 		time_t *t, struct tm *tp)
23086d7f5d3SJohn Marino {
23186d7f5d3SJohn Marino   struct tm *r = convert (t, tp);
23286d7f5d3SJohn Marino 
23386d7f5d3SJohn Marino   if (!r && *t)
23486d7f5d3SJohn Marino     {
23586d7f5d3SJohn Marino       time_t bad = *t;
23686d7f5d3SJohn Marino       time_t ok = 0;
23786d7f5d3SJohn Marino 
23886d7f5d3SJohn Marino       /* BAD is a known unconvertible time_t, and OK is a known good one.
23986d7f5d3SJohn Marino 	 Use binary search to narrow the range between BAD and OK until
24086d7f5d3SJohn Marino 	 they differ by 1.  */
24186d7f5d3SJohn Marino       while (bad != ok + (bad < 0 ? -1 : 1))
24286d7f5d3SJohn Marino 	{
24386d7f5d3SJohn Marino 	  time_t mid = *t = (bad < 0
24486d7f5d3SJohn Marino 			     ? bad + ((ok - bad) >> 1)
24586d7f5d3SJohn Marino 			     : ok + ((bad - ok) >> 1));
24686d7f5d3SJohn Marino 	  r = convert (t, tp);
24786d7f5d3SJohn Marino 	  if (r)
24886d7f5d3SJohn Marino 	    ok = mid;
24986d7f5d3SJohn Marino 	  else
25086d7f5d3SJohn Marino 	    bad = mid;
25186d7f5d3SJohn Marino 	}
25286d7f5d3SJohn Marino 
25386d7f5d3SJohn Marino       if (!r && ok)
25486d7f5d3SJohn Marino 	{
25586d7f5d3SJohn Marino 	  /* The last conversion attempt failed;
25686d7f5d3SJohn Marino 	     revert to the most recent successful attempt.  */
25786d7f5d3SJohn Marino 	  *t = ok;
25886d7f5d3SJohn Marino 	  r = convert (t, tp);
25986d7f5d3SJohn Marino 	}
26086d7f5d3SJohn Marino     }
26186d7f5d3SJohn Marino 
26286d7f5d3SJohn Marino   return r;
26386d7f5d3SJohn Marino }
26486d7f5d3SJohn Marino 
26586d7f5d3SJohn Marino 
26686d7f5d3SJohn Marino /* Convert *TP to a time_t value, inverting
26786d7f5d3SJohn Marino    the monotonic and mostly-unit-linear conversion function CONVERT.
26886d7f5d3SJohn Marino    Use *OFFSET to keep track of a guess at the offset of the result,
26986d7f5d3SJohn Marino    compared to what the result would be for UTC without leap seconds.
27086d7f5d3SJohn Marino    If *OFFSET's guess is correct, only one CONVERT call is needed.
27186d7f5d3SJohn Marino    This function is external because it is used also by timegm.c.  */
27286d7f5d3SJohn Marino time_t
__mktime_internal(struct tm * tp,struct tm * (* convert)(const time_t *,struct tm *),time_t * offset)27386d7f5d3SJohn Marino __mktime_internal (struct tm *tp,
27486d7f5d3SJohn Marino 		   struct tm *(*convert) (const time_t *, struct tm *),
27586d7f5d3SJohn Marino 		   time_t *offset)
27686d7f5d3SJohn Marino {
27786d7f5d3SJohn Marino   time_t t, gt, t0, t1, t2;
27886d7f5d3SJohn Marino   struct tm tm;
27986d7f5d3SJohn Marino 
28086d7f5d3SJohn Marino   /* The maximum number of probes (calls to CONVERT) should be enough
28186d7f5d3SJohn Marino      to handle any combinations of time zone rule changes, solar time,
28286d7f5d3SJohn Marino      leap seconds, and oscillations around a spring-forward gap.
28386d7f5d3SJohn Marino      POSIX.1 prohibits leap seconds, but some hosts have them anyway.  */
28486d7f5d3SJohn Marino   int remaining_probes = 6;
28586d7f5d3SJohn Marino 
28686d7f5d3SJohn Marino   /* Time requested.  Copy it in case CONVERT modifies *TP; this can
28786d7f5d3SJohn Marino      occur if TP is localtime's returned value and CONVERT is localtime.  */
28886d7f5d3SJohn Marino   int sec = tp->tm_sec;
28986d7f5d3SJohn Marino   int min = tp->tm_min;
29086d7f5d3SJohn Marino   int hour = tp->tm_hour;
29186d7f5d3SJohn Marino   int mday = tp->tm_mday;
29286d7f5d3SJohn Marino   int mon = tp->tm_mon;
29386d7f5d3SJohn Marino   int year_requested = tp->tm_year;
29486d7f5d3SJohn Marino   int isdst = tp->tm_isdst;
29586d7f5d3SJohn Marino 
29686d7f5d3SJohn Marino   /* 1 if the previous probe was DST.  */
29786d7f5d3SJohn Marino   int dst2;
29886d7f5d3SJohn Marino 
29986d7f5d3SJohn Marino   /* Ensure that mon is in range, and set year accordingly.  */
30086d7f5d3SJohn Marino   int mon_remainder = mon % 12;
30186d7f5d3SJohn Marino   int negative_mon_remainder = mon_remainder < 0;
30286d7f5d3SJohn Marino   int mon_years = mon / 12 - negative_mon_remainder;
30386d7f5d3SJohn Marino   long int lyear_requested = year_requested;
30486d7f5d3SJohn Marino   long int year = lyear_requested + mon_years;
30586d7f5d3SJohn Marino 
30686d7f5d3SJohn Marino   /* The other values need not be in range:
30786d7f5d3SJohn Marino      the remaining code handles minor overflows correctly,
30886d7f5d3SJohn Marino      assuming int and time_t arithmetic wraps around.
30986d7f5d3SJohn Marino      Major overflows are caught at the end.  */
31086d7f5d3SJohn Marino 
31186d7f5d3SJohn Marino   /* Calculate day of year from year, month, and day of month.
31286d7f5d3SJohn Marino      The result need not be in range.  */
31386d7f5d3SJohn Marino   int mon_yday = ((__mon_yday[leapyear (year)]
31486d7f5d3SJohn Marino 		   [mon_remainder + 12 * negative_mon_remainder])
31586d7f5d3SJohn Marino 		  - 1);
31686d7f5d3SJohn Marino   long int lmday = mday;
31786d7f5d3SJohn Marino   long int yday = mon_yday + lmday;
31886d7f5d3SJohn Marino 
31986d7f5d3SJohn Marino   time_t guessed_offset = *offset;
32086d7f5d3SJohn Marino 
32186d7f5d3SJohn Marino   int sec_requested = sec;
32286d7f5d3SJohn Marino 
32386d7f5d3SJohn Marino   if (LEAP_SECONDS_POSSIBLE)
32486d7f5d3SJohn Marino     {
32586d7f5d3SJohn Marino       /* Handle out-of-range seconds specially,
32686d7f5d3SJohn Marino 	 since ydhms_tm_diff assumes every minute has 60 seconds.  */
32786d7f5d3SJohn Marino       if (sec < 0)
32886d7f5d3SJohn Marino 	sec = 0;
32986d7f5d3SJohn Marino       if (59 < sec)
33086d7f5d3SJohn Marino 	sec = 59;
33186d7f5d3SJohn Marino     }
33286d7f5d3SJohn Marino 
33386d7f5d3SJohn Marino   /* Invert CONVERT by probing.  First assume the same offset as last
33486d7f5d3SJohn Marino      time.  */
33586d7f5d3SJohn Marino 
33686d7f5d3SJohn Marino   t0 = ydhms_diff (year, yday, hour, min, sec,
33786d7f5d3SJohn Marino 		   EPOCH_YEAR - TM_YEAR_BASE, 0, 0, 0, - guessed_offset);
33886d7f5d3SJohn Marino 
33986d7f5d3SJohn Marino   if (TIME_T_MAX / INT_MAX / 366 / 24 / 60 / 60 < 3)
34086d7f5d3SJohn Marino     {
34186d7f5d3SJohn Marino       /* time_t isn't large enough to rule out overflows, so check
34286d7f5d3SJohn Marino 	 for major overflows.  A gross check suffices, since if t0
34386d7f5d3SJohn Marino 	 has overflowed, it is off by a multiple of TIME_T_MAX -
34486d7f5d3SJohn Marino 	 TIME_T_MIN + 1.  So ignore any component of the difference
34586d7f5d3SJohn Marino 	 that is bounded by a small value.  */
34686d7f5d3SJohn Marino 
34786d7f5d3SJohn Marino       /* Approximate log base 2 of the number of time units per
34886d7f5d3SJohn Marino 	 biennium.  A biennium is 2 years; use this unit instead of
34986d7f5d3SJohn Marino 	 years to avoid integer overflow.  For example, 2 average
35086d7f5d3SJohn Marino 	 Gregorian years are 2 * 365.2425 * 24 * 60 * 60 seconds,
35186d7f5d3SJohn Marino 	 which is 63113904 seconds, and rint (log2 (63113904)) is
35286d7f5d3SJohn Marino 	 26.  */
35386d7f5d3SJohn Marino       int ALOG2_SECONDS_PER_BIENNIUM = 26;
35486d7f5d3SJohn Marino       int ALOG2_MINUTES_PER_BIENNIUM = 20;
35586d7f5d3SJohn Marino       int ALOG2_HOURS_PER_BIENNIUM = 14;
35686d7f5d3SJohn Marino       int ALOG2_DAYS_PER_BIENNIUM = 10;
35786d7f5d3SJohn Marino       int LOG2_YEARS_PER_BIENNIUM = 1;
35886d7f5d3SJohn Marino 
35986d7f5d3SJohn Marino       int approx_requested_biennia =
36086d7f5d3SJohn Marino 	(SHR (year_requested, LOG2_YEARS_PER_BIENNIUM)
36186d7f5d3SJohn Marino 	 - SHR (EPOCH_YEAR - TM_YEAR_BASE, LOG2_YEARS_PER_BIENNIUM)
36286d7f5d3SJohn Marino 	 + SHR (mday, ALOG2_DAYS_PER_BIENNIUM)
36386d7f5d3SJohn Marino 	 + SHR (hour, ALOG2_HOURS_PER_BIENNIUM)
36486d7f5d3SJohn Marino 	 + SHR (min, ALOG2_MINUTES_PER_BIENNIUM)
36586d7f5d3SJohn Marino 	 + (LEAP_SECONDS_POSSIBLE
36686d7f5d3SJohn Marino 	    ? 0
36786d7f5d3SJohn Marino 	    : SHR (sec, ALOG2_SECONDS_PER_BIENNIUM)));
36886d7f5d3SJohn Marino 
36986d7f5d3SJohn Marino       int approx_biennia = SHR (t0, ALOG2_SECONDS_PER_BIENNIUM);
37086d7f5d3SJohn Marino       int diff = approx_biennia - approx_requested_biennia;
37186d7f5d3SJohn Marino       int abs_diff = diff < 0 ? - diff : diff;
37286d7f5d3SJohn Marino 
37386d7f5d3SJohn Marino       /* IRIX 4.0.5 cc miscaculates TIME_T_MIN / 3: it erroneously
37486d7f5d3SJohn Marino 	 gives a positive value of 715827882.  Setting a variable
37586d7f5d3SJohn Marino 	 first then doing math on it seems to work.
37686d7f5d3SJohn Marino 	 (ghazi@caip.rutgers.edu) */
37786d7f5d3SJohn Marino       time_t time_t_max = TIME_T_MAX;
37886d7f5d3SJohn Marino       time_t time_t_min = TIME_T_MIN;
37986d7f5d3SJohn Marino       time_t overflow_threshold =
38086d7f5d3SJohn Marino 	(time_t_max / 3 - time_t_min / 3) >> ALOG2_SECONDS_PER_BIENNIUM;
38186d7f5d3SJohn Marino 
38286d7f5d3SJohn Marino       if (overflow_threshold < abs_diff)
38386d7f5d3SJohn Marino 	{
38486d7f5d3SJohn Marino 	  /* Overflow occurred.  Try repairing it; this might work if
38586d7f5d3SJohn Marino 	     the time zone offset is enough to undo the overflow.  */
38686d7f5d3SJohn Marino 	  time_t repaired_t0 = -1 - t0;
38786d7f5d3SJohn Marino 	  approx_biennia = SHR (repaired_t0, ALOG2_SECONDS_PER_BIENNIUM);
38886d7f5d3SJohn Marino 	  diff = approx_biennia - approx_requested_biennia;
38986d7f5d3SJohn Marino 	  abs_diff = diff < 0 ? - diff : diff;
39086d7f5d3SJohn Marino 	  if (overflow_threshold < abs_diff)
39186d7f5d3SJohn Marino 	    return -1;
39286d7f5d3SJohn Marino 	  guessed_offset += repaired_t0 - t0;
39386d7f5d3SJohn Marino 	  t0 = repaired_t0;
39486d7f5d3SJohn Marino 	}
39586d7f5d3SJohn Marino     }
39686d7f5d3SJohn Marino 
39786d7f5d3SJohn Marino   /* Repeatedly use the error to improve the guess.  */
39886d7f5d3SJohn Marino 
39986d7f5d3SJohn Marino   for (t = t1 = t2 = t0, dst2 = 0;
40086d7f5d3SJohn Marino        (gt = guess_time_tm (year, yday, hour, min, sec, &t,
40186d7f5d3SJohn Marino 			    ranged_convert (convert, &t, &tm)),
40286d7f5d3SJohn Marino 	t != gt);
40386d7f5d3SJohn Marino        t1 = t2, t2 = t, t = gt, dst2 = tm.tm_isdst != 0)
40486d7f5d3SJohn Marino     if (t == t1 && t != t2
40586d7f5d3SJohn Marino 	&& (tm.tm_isdst < 0
40686d7f5d3SJohn Marino 	    || (isdst < 0
40786d7f5d3SJohn Marino 		? dst2 <= (tm.tm_isdst != 0)
40886d7f5d3SJohn Marino 		: (isdst != 0) != (tm.tm_isdst != 0))))
40986d7f5d3SJohn Marino       /* We can't possibly find a match, as we are oscillating
41086d7f5d3SJohn Marino 	 between two values.  The requested time probably falls
41186d7f5d3SJohn Marino 	 within a spring-forward gap of size GT - T.  Follow the common
41286d7f5d3SJohn Marino 	 practice in this case, which is to return a time that is GT - T
41386d7f5d3SJohn Marino 	 away from the requested time, preferring a time whose
41486d7f5d3SJohn Marino 	 tm_isdst differs from the requested value.  (If no tm_isdst
41586d7f5d3SJohn Marino 	 was requested and only one of the two values has a nonzero
41686d7f5d3SJohn Marino 	 tm_isdst, prefer that value.)  In practice, this is more
41786d7f5d3SJohn Marino 	 useful than returning -1.  */
41886d7f5d3SJohn Marino       goto offset_found;
41986d7f5d3SJohn Marino     else if (--remaining_probes == 0)
42086d7f5d3SJohn Marino       return -1;
42186d7f5d3SJohn Marino 
42286d7f5d3SJohn Marino   /* We have a match.  Check whether tm.tm_isdst has the requested
42386d7f5d3SJohn Marino      value, if any.  */
42486d7f5d3SJohn Marino   if (isdst != tm.tm_isdst && 0 <= isdst && 0 <= tm.tm_isdst)
42586d7f5d3SJohn Marino     {
42686d7f5d3SJohn Marino       /* tm.tm_isdst has the wrong value.  Look for a neighboring
42786d7f5d3SJohn Marino 	 time with the right value, and use its UTC offset.
42886d7f5d3SJohn Marino 
42986d7f5d3SJohn Marino 	 Heuristic: probe the adjacent timestamps in both directions,
43086d7f5d3SJohn Marino 	 looking for the desired isdst.  This should work for all real
43186d7f5d3SJohn Marino 	 time zone histories in the tz database.  */
43286d7f5d3SJohn Marino 
43386d7f5d3SJohn Marino       /* Distance between probes when looking for a DST boundary.  In
43486d7f5d3SJohn Marino 	 tzdata2003a, the shortest period of DST is 601200 seconds
43586d7f5d3SJohn Marino 	 (e.g., America/Recife starting 2000-10-08 01:00), and the
43686d7f5d3SJohn Marino 	 shortest period of non-DST surrounded by DST is 694800
43786d7f5d3SJohn Marino 	 seconds (Africa/Tunis starting 1943-04-17 01:00).  Use the
43886d7f5d3SJohn Marino 	 minimum of these two values, so we don't miss these short
43986d7f5d3SJohn Marino 	 periods when probing.  */
44086d7f5d3SJohn Marino       int stride = 601200;
44186d7f5d3SJohn Marino 
44286d7f5d3SJohn Marino       /* The longest period of DST in tzdata2003a is 536454000 seconds
44386d7f5d3SJohn Marino 	 (e.g., America/Jujuy starting 1946-10-01 01:00).  The longest
44486d7f5d3SJohn Marino 	 period of non-DST is much longer, but it makes no real sense
44586d7f5d3SJohn Marino 	 to search for more than a year of non-DST, so use the DST
44686d7f5d3SJohn Marino 	 max.  */
44786d7f5d3SJohn Marino       int duration_max = 536454000;
44886d7f5d3SJohn Marino 
44986d7f5d3SJohn Marino       /* Search in both directions, so the maximum distance is half
45086d7f5d3SJohn Marino 	 the duration; add the stride to avoid off-by-1 problems.  */
45186d7f5d3SJohn Marino       int delta_bound = duration_max / 2 + stride;
45286d7f5d3SJohn Marino 
45386d7f5d3SJohn Marino       int delta, direction;
45486d7f5d3SJohn Marino 
45586d7f5d3SJohn Marino       for (delta = stride; delta < delta_bound; delta += stride)
45686d7f5d3SJohn Marino 	for (direction = -1; direction <= 1; direction += 2)
45786d7f5d3SJohn Marino 	  {
45886d7f5d3SJohn Marino 	    time_t ot = t + delta * direction;
45986d7f5d3SJohn Marino 	    if ((ot < t) == (direction < 0))
46086d7f5d3SJohn Marino 	      {
46186d7f5d3SJohn Marino 		struct tm otm;
46286d7f5d3SJohn Marino 		ranged_convert (convert, &ot, &otm);
46386d7f5d3SJohn Marino 		if (otm.tm_isdst == isdst)
46486d7f5d3SJohn Marino 		  {
46586d7f5d3SJohn Marino 		    /* We found the desired tm_isdst.
46686d7f5d3SJohn Marino 		       Extrapolate back to the desired time.  */
46786d7f5d3SJohn Marino 		    t = guess_time_tm (year, yday, hour, min, sec, &ot, &otm);
46886d7f5d3SJohn Marino 		    ranged_convert (convert, &t, &tm);
46986d7f5d3SJohn Marino 		    goto offset_found;
47086d7f5d3SJohn Marino 		  }
47186d7f5d3SJohn Marino 	      }
47286d7f5d3SJohn Marino 	  }
47386d7f5d3SJohn Marino     }
47486d7f5d3SJohn Marino 
47586d7f5d3SJohn Marino  offset_found:
47686d7f5d3SJohn Marino   *offset = guessed_offset + t - t0;
47786d7f5d3SJohn Marino 
47886d7f5d3SJohn Marino   if (LEAP_SECONDS_POSSIBLE && sec_requested != tm.tm_sec)
47986d7f5d3SJohn Marino     {
48086d7f5d3SJohn Marino       /* Adjust time to reflect the tm_sec requested, not the normalized value.
48186d7f5d3SJohn Marino 	 Also, repair any damage from a false match due to a leap second.  */
48286d7f5d3SJohn Marino       int sec_adjustment = (sec == 0 && tm.tm_sec == 60) - sec;
48386d7f5d3SJohn Marino       t1 = t + sec_requested;
48486d7f5d3SJohn Marino       t2 = t1 + sec_adjustment;
48586d7f5d3SJohn Marino       if (((t1 < t) != (sec_requested < 0))
48686d7f5d3SJohn Marino 	  | ((t2 < t1) != (sec_adjustment < 0))
48786d7f5d3SJohn Marino 	  | ! convert (&t2, &tm))
48886d7f5d3SJohn Marino 	return -1;
48986d7f5d3SJohn Marino       t = t2;
49086d7f5d3SJohn Marino     }
49186d7f5d3SJohn Marino 
49286d7f5d3SJohn Marino   *tp = tm;
49386d7f5d3SJohn Marino   return t;
49486d7f5d3SJohn Marino }
49586d7f5d3SJohn Marino 
49686d7f5d3SJohn Marino 
49786d7f5d3SJohn Marino /* FIXME: This should use a signed type wide enough to hold any UTC
49886d7f5d3SJohn Marino    offset in seconds.  'int' should be good enough for GNU code.  We
49986d7f5d3SJohn Marino    can't fix this unilaterally though, as other modules invoke
50086d7f5d3SJohn Marino    __mktime_internal.  */
50186d7f5d3SJohn Marino static time_t localtime_offset;
50286d7f5d3SJohn Marino 
50386d7f5d3SJohn Marino /* Convert *TP to a time_t value.  */
50486d7f5d3SJohn Marino time_t
mktime(struct tm * tp)50586d7f5d3SJohn Marino mktime (struct tm *tp)
50686d7f5d3SJohn Marino {
50786d7f5d3SJohn Marino #ifdef _LIBC
50886d7f5d3SJohn Marino   /* POSIX.1 8.1.1 requires that whenever mktime() is called, the
50986d7f5d3SJohn Marino      time zone names contained in the external variable `tzname' shall
51086d7f5d3SJohn Marino      be set as if the tzset() function had been called.  */
51186d7f5d3SJohn Marino   __tzset ();
51286d7f5d3SJohn Marino #endif
51386d7f5d3SJohn Marino 
51486d7f5d3SJohn Marino   return __mktime_internal (tp, __localtime_r, &localtime_offset);
51586d7f5d3SJohn Marino }
51686d7f5d3SJohn Marino 
51786d7f5d3SJohn Marino #ifdef weak_alias
weak_alias(mktime,timelocal)51886d7f5d3SJohn Marino weak_alias (mktime, timelocal)
51986d7f5d3SJohn Marino #endif
52086d7f5d3SJohn Marino 
52186d7f5d3SJohn Marino #ifdef _LIBC
52286d7f5d3SJohn Marino libc_hidden_def (mktime)
52386d7f5d3SJohn Marino libc_hidden_weak (timelocal)
52486d7f5d3SJohn Marino #endif
52586d7f5d3SJohn Marino 
52686d7f5d3SJohn Marino #if DEBUG
52786d7f5d3SJohn Marino 
52886d7f5d3SJohn Marino static int
52986d7f5d3SJohn Marino not_equal_tm (const struct tm *a, const struct tm *b)
53086d7f5d3SJohn Marino {
53186d7f5d3SJohn Marino   return ((a->tm_sec ^ b->tm_sec)
53286d7f5d3SJohn Marino 	  | (a->tm_min ^ b->tm_min)
53386d7f5d3SJohn Marino 	  | (a->tm_hour ^ b->tm_hour)
53486d7f5d3SJohn Marino 	  | (a->tm_mday ^ b->tm_mday)
53586d7f5d3SJohn Marino 	  | (a->tm_mon ^ b->tm_mon)
53686d7f5d3SJohn Marino 	  | (a->tm_year ^ b->tm_year)
53786d7f5d3SJohn Marino 	  | (a->tm_yday ^ b->tm_yday)
53886d7f5d3SJohn Marino 	  | (a->tm_isdst ^ b->tm_isdst));
53986d7f5d3SJohn Marino }
54086d7f5d3SJohn Marino 
54186d7f5d3SJohn Marino static void
print_tm(const struct tm * tp)54286d7f5d3SJohn Marino print_tm (const struct tm *tp)
54386d7f5d3SJohn Marino {
54486d7f5d3SJohn Marino   if (tp)
54586d7f5d3SJohn Marino     printf ("%04d-%02d-%02d %02d:%02d:%02d yday %03d wday %d isdst %d",
54686d7f5d3SJohn Marino 	    tp->tm_year + TM_YEAR_BASE, tp->tm_mon + 1, tp->tm_mday,
54786d7f5d3SJohn Marino 	    tp->tm_hour, tp->tm_min, tp->tm_sec,
54886d7f5d3SJohn Marino 	    tp->tm_yday, tp->tm_wday, tp->tm_isdst);
54986d7f5d3SJohn Marino   else
55086d7f5d3SJohn Marino     printf ("0");
55186d7f5d3SJohn Marino }
55286d7f5d3SJohn Marino 
55386d7f5d3SJohn Marino static int
check_result(time_t tk,struct tm tmk,time_t tl,const struct tm * lt)55486d7f5d3SJohn Marino check_result (time_t tk, struct tm tmk, time_t tl, const struct tm *lt)
55586d7f5d3SJohn Marino {
55686d7f5d3SJohn Marino   if (tk != tl || !lt || not_equal_tm (&tmk, lt))
55786d7f5d3SJohn Marino     {
55886d7f5d3SJohn Marino       printf ("mktime (");
55986d7f5d3SJohn Marino       print_tm (lt);
56086d7f5d3SJohn Marino       printf (")\nyields (");
56186d7f5d3SJohn Marino       print_tm (&tmk);
56286d7f5d3SJohn Marino       printf (") == %ld, should be %ld\n", (long int) tk, (long int) tl);
56386d7f5d3SJohn Marino       return 1;
56486d7f5d3SJohn Marino     }
56586d7f5d3SJohn Marino 
56686d7f5d3SJohn Marino   return 0;
56786d7f5d3SJohn Marino }
56886d7f5d3SJohn Marino 
56986d7f5d3SJohn Marino int
main(int argc,char ** argv)57086d7f5d3SJohn Marino main (int argc, char **argv)
57186d7f5d3SJohn Marino {
57286d7f5d3SJohn Marino   int status = 0;
57386d7f5d3SJohn Marino   struct tm tm, tmk, tml;
57486d7f5d3SJohn Marino   struct tm *lt;
57586d7f5d3SJohn Marino   time_t tk, tl, tl1;
57686d7f5d3SJohn Marino   char trailer;
57786d7f5d3SJohn Marino 
57886d7f5d3SJohn Marino   if ((argc == 3 || argc == 4)
57986d7f5d3SJohn Marino       && (sscanf (argv[1], "%d-%d-%d%c",
58086d7f5d3SJohn Marino 		  &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &trailer)
58186d7f5d3SJohn Marino 	  == 3)
58286d7f5d3SJohn Marino       && (sscanf (argv[2], "%d:%d:%d%c",
58386d7f5d3SJohn Marino 		  &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &trailer)
58486d7f5d3SJohn Marino 	  == 3))
58586d7f5d3SJohn Marino     {
58686d7f5d3SJohn Marino       tm.tm_year -= TM_YEAR_BASE;
58786d7f5d3SJohn Marino       tm.tm_mon--;
58886d7f5d3SJohn Marino       tm.tm_isdst = argc == 3 ? -1 : atoi (argv[3]);
58986d7f5d3SJohn Marino       tmk = tm;
59086d7f5d3SJohn Marino       tl = mktime (&tmk);
59186d7f5d3SJohn Marino       lt = localtime (&tl);
59286d7f5d3SJohn Marino       if (lt)
59386d7f5d3SJohn Marino 	{
59486d7f5d3SJohn Marino 	  tml = *lt;
59586d7f5d3SJohn Marino 	  lt = &tml;
59686d7f5d3SJohn Marino 	}
59786d7f5d3SJohn Marino       printf ("mktime returns %ld == ", (long int) tl);
59886d7f5d3SJohn Marino       print_tm (&tmk);
59986d7f5d3SJohn Marino       printf ("\n");
60086d7f5d3SJohn Marino       status = check_result (tl, tmk, tl, lt);
60186d7f5d3SJohn Marino     }
60286d7f5d3SJohn Marino   else if (argc == 4 || (argc == 5 && strcmp (argv[4], "-") == 0))
60386d7f5d3SJohn Marino     {
60486d7f5d3SJohn Marino       time_t from = atol (argv[1]);
60586d7f5d3SJohn Marino       time_t by = atol (argv[2]);
60686d7f5d3SJohn Marino       time_t to = atol (argv[3]);
60786d7f5d3SJohn Marino 
60886d7f5d3SJohn Marino       if (argc == 4)
60986d7f5d3SJohn Marino 	for (tl = from; by < 0 ? to <= tl : tl <= to; tl = tl1)
61086d7f5d3SJohn Marino 	  {
61186d7f5d3SJohn Marino 	    lt = localtime (&tl);
61286d7f5d3SJohn Marino 	    if (lt)
61386d7f5d3SJohn Marino 	      {
61486d7f5d3SJohn Marino 		tmk = tml = *lt;
61586d7f5d3SJohn Marino 		tk = mktime (&tmk);
61686d7f5d3SJohn Marino 		status |= check_result (tk, tmk, tl, &tml);
61786d7f5d3SJohn Marino 	      }
61886d7f5d3SJohn Marino 	    else
61986d7f5d3SJohn Marino 	      {
62086d7f5d3SJohn Marino 		printf ("localtime (%ld) yields 0\n", (long int) tl);
62186d7f5d3SJohn Marino 		status = 1;
62286d7f5d3SJohn Marino 	      }
62386d7f5d3SJohn Marino 	    tl1 = tl + by;
62486d7f5d3SJohn Marino 	    if ((tl1 < tl) != (by < 0))
62586d7f5d3SJohn Marino 	      break;
62686d7f5d3SJohn Marino 	  }
62786d7f5d3SJohn Marino       else
62886d7f5d3SJohn Marino 	for (tl = from; by < 0 ? to <= tl : tl <= to; tl = tl1)
62986d7f5d3SJohn Marino 	  {
63086d7f5d3SJohn Marino 	    /* Null benchmark.  */
63186d7f5d3SJohn Marino 	    lt = localtime (&tl);
63286d7f5d3SJohn Marino 	    if (lt)
63386d7f5d3SJohn Marino 	      {
63486d7f5d3SJohn Marino 		tmk = tml = *lt;
63586d7f5d3SJohn Marino 		tk = tl;
63686d7f5d3SJohn Marino 		status |= check_result (tk, tmk, tl, &tml);
63786d7f5d3SJohn Marino 	      }
63886d7f5d3SJohn Marino 	    else
63986d7f5d3SJohn Marino 	      {
64086d7f5d3SJohn Marino 		printf ("localtime (%ld) yields 0\n", (long int) tl);
64186d7f5d3SJohn Marino 		status = 1;
64286d7f5d3SJohn Marino 	      }
64386d7f5d3SJohn Marino 	    tl1 = tl + by;
64486d7f5d3SJohn Marino 	    if ((tl1 < tl) != (by < 0))
64586d7f5d3SJohn Marino 	      break;
64686d7f5d3SJohn Marino 	  }
64786d7f5d3SJohn Marino     }
64886d7f5d3SJohn Marino   else
64986d7f5d3SJohn Marino     printf ("Usage:\
65086d7f5d3SJohn Marino \t%s YYYY-MM-DD HH:MM:SS [ISDST] # Test given time.\n\
65186d7f5d3SJohn Marino \t%s FROM BY TO # Test values FROM, FROM+BY, ..., TO.\n\
65286d7f5d3SJohn Marino \t%s FROM BY TO - # Do not test those values (for benchmark).\n",
65386d7f5d3SJohn Marino 	    argv[0], argv[0], argv[0]);
65486d7f5d3SJohn Marino 
65586d7f5d3SJohn Marino   return status;
65686d7f5d3SJohn Marino }
65786d7f5d3SJohn Marino 
65886d7f5d3SJohn Marino #endif /* DEBUG */
65986d7f5d3SJohn Marino 
66086d7f5d3SJohn Marino /*
66186d7f5d3SJohn Marino Local Variables:
66286d7f5d3SJohn Marino compile-command: "gcc -DDEBUG -Wall -W -O -g mktime.c -o mktime"
66386d7f5d3SJohn Marino End:
66486d7f5d3SJohn Marino */
665