Blame lib/mktime.c

Packit 33f14e
/* Convert a 'struct tm' to a time_t value.
Packit 33f14e
   Copyright (C) 1993-2017 Free Software Foundation, Inc.
Packit 33f14e
   This file is part of the GNU C Library.
Packit 33f14e
   Contributed by Paul Eggert <eggert@twinsun.com>.
Packit 33f14e
Packit 33f14e
   The GNU C Library is free software; you can redistribute it and/or
Packit 33f14e
   modify it under the terms of the GNU General Public
Packit 33f14e
   License as published by the Free Software Foundation; either
Packit 33f14e
   version 3 of the License, or (at your option) any later version.
Packit 33f14e
Packit 33f14e
   The GNU C Library is distributed in the hope that it will be useful,
Packit 33f14e
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 33f14e
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 33f14e
   General Public License for more details.
Packit 33f14e
Packit 33f14e
   You should have received a copy of the GNU General Public
Packit 33f14e
   License along with the GNU C Library; if not, see
Packit 33f14e
   <http://www.gnu.org/licenses/>.  */
Packit 33f14e
Packit 33f14e
/* Define this to 1 to have a standalone program to test this implementation of
Packit 33f14e
   mktime.  */
Packit 33f14e
#ifndef DEBUG_MKTIME
Packit 33f14e
# define DEBUG_MKTIME 0
Packit 33f14e
#endif
Packit 33f14e
Packit 33f14e
/* The following macros influence what gets defined when this file is compiled:
Packit 33f14e
Packit 33f14e
   Macro/expression            Which gnulib module    This compilation unit
Packit 33f14e
                                                      should define
Packit 33f14e
Packit 33f14e
   NEED_MKTIME_WORKING         mktime                 rpl_mktime
Packit 33f14e
   || NEED_MKTIME_WINDOWS
Packit 33f14e
Packit 33f14e
   NEED_MKTIME_INTERNAL        mktime-internal        mktime_internal
Packit 33f14e
Packit 33f14e
   DEBUG_MKTIME                (defined manually)     my_mktime, main
Packit 33f14e
 */
Packit 33f14e
Packit 33f14e
#if !defined _LIBC && !DEBUG_MKTIME
Packit 33f14e
# include <config.h>
Packit 33f14e
#endif
Packit 33f14e
Packit 33f14e
/* Assume that leap seconds are possible, unless told otherwise.
Packit 33f14e
   If the host has a 'zic' command with a '-L leapsecondfilename' option,
Packit 33f14e
   then it supports leap seconds; otherwise it probably doesn't.  */
Packit 33f14e
#ifndef LEAP_SECONDS_POSSIBLE
Packit 33f14e
# define LEAP_SECONDS_POSSIBLE 1
Packit 33f14e
#endif
Packit 33f14e
Packit 33f14e
#include <time.h>
Packit 33f14e
Packit 33f14e
#include <limits.h>
Packit 33f14e
#include <stdbool.h>
Packit 33f14e
Packit 33f14e
#include <intprops.h>
Packit 33f14e
#include <verify.h>
Packit 33f14e
Packit 33f14e
#if DEBUG_MKTIME
Packit 33f14e
# include <stdio.h>
Packit 33f14e
# include <stdlib.h>
Packit 33f14e
# include <string.h>
Packit 33f14e
/* Make it work even if the system's libc has its own mktime routine.  */
Packit 33f14e
# undef mktime
Packit 33f14e
# define mktime my_mktime
Packit 33f14e
#endif
Packit 33f14e
Packit 33f14e
#if NEED_MKTIME_WINDOWS /* on native Windows */
Packit 33f14e
# include <stdlib.h>
Packit 33f14e
# include <string.h>
Packit 33f14e
#endif
Packit 33f14e
Packit 33f14e
#if NEED_MKTIME_WORKING || NEED_MKTIME_INTERNAL || DEBUG_MKTIME
Packit 33f14e
Packit 33f14e
/* A signed type that can represent an integer number of years
Packit 33f14e
   multiplied by three times the number of seconds in a year.  It is
Packit 33f14e
   needed when converting a tm_year value times the number of seconds
Packit 33f14e
   in a year.  The factor of three comes because these products need
Packit 33f14e
   to be subtracted from each other, and sometimes with an offset
Packit 33f14e
   added to them, without worrying about overflow.
Packit 33f14e
Packit 33f14e
   Much of the code uses long_int to represent time_t values, to
Packit 33f14e
   lessen the hassle of dealing with platforms where time_t is
Packit 33f14e
   unsigned, and because long_int should suffice to represent all
Packit 33f14e
   time_t values that mktime can generate even on platforms where
Packit 33f14e
   time_t is excessively wide.  */
Packit 33f14e
Packit 33f14e
#if INT_MAX <= LONG_MAX / 3 / 366 / 24 / 60 / 60
Packit 33f14e
typedef long int long_int;
Packit 33f14e
#else
Packit 33f14e
typedef long long int long_int;
Packit 33f14e
#endif
Packit 33f14e
verify (INT_MAX <= TYPE_MAXIMUM (long_int) / 3 / 366 / 24 / 60 / 60);
Packit 33f14e
Packit 33f14e
/* Shift A right by B bits portably, by dividing A by 2**B and
Packit 33f14e
   truncating towards minus infinity.  B should be in the range 0 <= B
Packit 33f14e
   <= LONG_INT_BITS - 2, where LONG_INT_BITS is the number of useful
Packit 33f14e
   bits in a long_int.  LONG_INT_BITS is at least 32.
Packit 33f14e
Packit 33f14e
   ISO C99 says that A >> B is implementation-defined if A < 0.  Some
Packit 33f14e
   implementations (e.g., UNICOS 9.0 on a Cray Y-MP EL) don't shift
Packit 33f14e
   right in the usual way when A < 0, so SHR falls back on division if
Packit 33f14e
   ordinary A >> B doesn't seem to be the usual signed shift.  */
Packit 33f14e
Packit 33f14e
static long_int
Packit 33f14e
shr (long_int a, int b)
Packit 33f14e
{
Packit 33f14e
  long_int one = 1;
Packit 33f14e
  return (-one >> 1 == -1
Packit 33f14e
	  ? a >> b
Packit 33f14e
	  : a / (one << b) - (a % (one << b) < 0));
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Bounds for the intersection of time_t and long_int.  */
Packit 33f14e
Packit 33f14e
static long_int const mktime_min
Packit 33f14e
  = ((TYPE_SIGNED (time_t) && TYPE_MINIMUM (time_t) < TYPE_MINIMUM (long_int))
Packit 33f14e
     ? TYPE_MINIMUM (long_int) : TYPE_MINIMUM (time_t));
Packit 33f14e
static long_int const mktime_max
Packit 33f14e
  = (TYPE_MAXIMUM (long_int) < TYPE_MAXIMUM (time_t)
Packit 33f14e
     ? TYPE_MAXIMUM (long_int) : TYPE_MAXIMUM (time_t));
Packit 33f14e
Packit 33f14e
verify (TYPE_IS_INTEGER (time_t));
Packit 33f14e
Packit 33f14e
#define EPOCH_YEAR 1970
Packit 33f14e
#define TM_YEAR_BASE 1900
Packit 33f14e
verify (TM_YEAR_BASE % 100 == 0);
Packit 33f14e
Packit 33f14e
/* Is YEAR + TM_YEAR_BASE a leap year?  */
Packit 33f14e
static bool
Packit 33f14e
leapyear (long_int year)
Packit 33f14e
{
Packit 33f14e
  /* Don't add YEAR to TM_YEAR_BASE, as that might overflow.
Packit 33f14e
     Also, work even if YEAR is negative.  */
Packit 33f14e
  return
Packit 33f14e
    ((year & 3) == 0
Packit 33f14e
     && (year % 100 != 0
Packit 33f14e
	 || ((year / 100) & 3) == (- (TM_YEAR_BASE / 100) & 3)));
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* How many days come before each month (0-12).  */
Packit 33f14e
#ifndef _LIBC
Packit 33f14e
static
Packit 33f14e
#endif
Packit 33f14e
const unsigned short int __mon_yday[2][13] =
Packit 33f14e
  {
Packit 33f14e
    /* Normal years.  */
Packit 33f14e
    { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
Packit 33f14e
    /* Leap years.  */
Packit 33f14e
    { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
Packit 33f14e
  };
Packit 33f14e
Packit 33f14e
Packit 33f14e
#ifdef _LIBC
Packit 33f14e
typedef time_t mktime_offset_t;
Packit 33f14e
#else
Packit 33f14e
/* Portable standalone applications should supply a <time.h> that
Packit 33f14e
   declares a POSIX-compliant localtime_r, for the benefit of older
Packit 33f14e
   implementations that lack localtime_r or have a nonstandard one.
Packit 33f14e
   See the gnulib time_r module for one way to implement this.  */
Packit 33f14e
# undef __localtime_r
Packit 33f14e
# define __localtime_r localtime_r
Packit 33f14e
# define __mktime_internal mktime_internal
Packit 33f14e
# include "mktime-internal.h"
Packit 33f14e
#endif
Packit 33f14e
Packit 33f14e
/* Do the values A and B differ according to the rules for tm_isdst?
Packit 33f14e
   A and B differ if one is zero and the other positive.  */
Packit 33f14e
static bool
Packit 33f14e
isdst_differ (int a, int b)
Packit 33f14e
{
Packit 33f14e
  return (!a != !b) && (0 <= a) && (0 <= b);
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Return an integer value measuring (YEAR1-YDAY1 HOUR1:MIN1:SEC1) -
Packit 33f14e
   (YEAR0-YDAY0 HOUR0:MIN0:SEC0) in seconds, assuming that the clocks
Packit 33f14e
   were not adjusted between the timestamps.
Packit 33f14e
Packit 33f14e
   The YEAR values uses the same numbering as TP->tm_year.  Values
Packit 33f14e
   need not be in the usual range.  However, YEAR1 must not overflow
Packit 33f14e
   when multiplied by three times the number of seconds in a year, and
Packit 33f14e
   likewise for YDAY1 and three times the number of seconds in a day.  */
Packit 33f14e
Packit 33f14e
static long_int
Packit 33f14e
ydhms_diff (long_int year1, long_int yday1, int hour1, int min1, int sec1,
Packit 33f14e
	    int year0, int yday0, int hour0, int min0, int sec0)
Packit 33f14e
{
Packit 33f14e
  verify (-1 / 2 == 0);
Packit 33f14e
Packit 33f14e
  /* Compute intervening leap days correctly even if year is negative.
Packit 33f14e
     Take care to avoid integer overflow here.  */
Packit 33f14e
  int a4 = shr (year1, 2) + shr (TM_YEAR_BASE, 2) - ! (year1 & 3);
Packit 33f14e
  int b4 = shr (year0, 2) + shr (TM_YEAR_BASE, 2) - ! (year0 & 3);
Packit 33f14e
  int a100 = a4 / 25 - (a4 % 25 < 0);
Packit 33f14e
  int b100 = b4 / 25 - (b4 % 25 < 0);
Packit 33f14e
  int a400 = shr (a100, 2);
Packit 33f14e
  int b400 = shr (b100, 2);
Packit 33f14e
  int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
Packit 33f14e
Packit 33f14e
  /* Compute the desired time without overflowing.  */
Packit 33f14e
  long_int years = year1 - year0;
Packit 33f14e
  long_int days = 365 * years + yday1 - yday0 + intervening_leap_days;
Packit 33f14e
  long_int hours = 24 * days + hour1 - hour0;
Packit 33f14e
  long_int minutes = 60 * hours + min1 - min0;
Packit 33f14e
  long_int seconds = 60 * minutes + sec1 - sec0;
Packit 33f14e
  return seconds;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Return the average of A and B, even if A + B would overflow.
Packit 33f14e
   Round toward positive infinity.  */
Packit 33f14e
static long_int
Packit 33f14e
long_int_avg (long_int a, long_int b)
Packit 33f14e
{
Packit 33f14e
  return shr (a, 1) + shr (b, 1) + ((a | b) & 1);
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Return a time_t value corresponding to (YEAR-YDAY HOUR:MIN:SEC),
Packit 33f14e
   assuming that T corresponds to *TP and that no clock adjustments
Packit 33f14e
   occurred between *TP and the desired time.
Packit 33f14e
   Although T and the returned value are of type long_int,
Packit 33f14e
   they represent time_t values and must be in time_t range.
Packit 33f14e
   If TP is null, return a value not equal to T; this avoids false matches.
Packit 33f14e
   YEAR and YDAY must not be so large that multiplying them by three times the
Packit 33f14e
   number of seconds in a year (or day, respectively) would overflow long_int.
Packit 33f14e
   If the returned value would be out of range, yield the minimal or
Packit 33f14e
   maximal in-range value, except do not yield a value equal to T.  */
Packit 33f14e
static long_int
Packit 33f14e
guess_time_tm (long_int year, long_int yday, int hour, int min, int sec,
Packit 33f14e
	       long_int t, const struct tm *tp)
Packit 33f14e
{
Packit 33f14e
  if (tp)
Packit 33f14e
    {
Packit 33f14e
      long_int result;
Packit 33f14e
      long_int d = ydhms_diff (year, yday, hour, min, sec,
Packit 33f14e
			       tp->tm_year, tp->tm_yday,
Packit 33f14e
			       tp->tm_hour, tp->tm_min, tp->tm_sec);
Packit 33f14e
      if (! INT_ADD_WRAPV (t, d, &result))
Packit 33f14e
	return result;
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  /* Overflow occurred one way or another.  Return the nearest result
Packit 33f14e
     that is actually in range, except don't report a zero difference
Packit 33f14e
     if the actual difference is nonzero, as that would cause a false
Packit 33f14e
     match; and don't oscillate between two values, as that would
Packit 33f14e
     confuse the spring-forward gap detector.  */
Packit 33f14e
  return (t < long_int_avg (mktime_min, mktime_max)
Packit 33f14e
	  ? (t <= mktime_min + 1 ? t + 1 : mktime_min)
Packit 33f14e
	  : (mktime_max - 1 <= t ? t - 1 : mktime_max));
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Use CONVERT to convert T to a struct tm value in *TM.  T must be in
Packit 33f14e
   range for time_t.  Return TM if successful, NULL if T is out of
Packit 33f14e
   range for CONVERT.  */
Packit 33f14e
static struct tm *
Packit 33f14e
convert_time (struct tm *(*convert) (const time_t *, struct tm *),
Packit 33f14e
	      long_int t, struct tm *tm)
Packit 33f14e
{
Packit 33f14e
  time_t x = t;
Packit 33f14e
  return convert (&x, tm);
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Use CONVERT to convert *T to a broken down time in *TP.
Packit 33f14e
   If *T is out of range for conversion, adjust it so that
Packit 33f14e
   it is the nearest in-range value and then convert that.
Packit 33f14e
   A value is in range if it fits in both time_t and long_int.  */
Packit 33f14e
static struct tm *
Packit 33f14e
ranged_convert (struct tm *(*convert) (const time_t *, struct tm *),
Packit 33f14e
		long_int *t, struct tm *tp)
Packit 33f14e
{
Packit 33f14e
  struct tm *r;
Packit 33f14e
  if (*t < mktime_min)
Packit 33f14e
    *t = mktime_min;
Packit 33f14e
  else if (mktime_max < *t)
Packit 33f14e
    *t = mktime_max;
Packit 33f14e
  r = convert_time (convert, *t, tp);
Packit 33f14e
Packit 33f14e
  if (!r && *t)
Packit 33f14e
    {
Packit 33f14e
      long_int bad = *t;
Packit 33f14e
      long_int ok = 0;
Packit 33f14e
Packit 33f14e
      /* BAD is a known unconvertible value, and OK is a known good one.
Packit 33f14e
	 Use binary search to narrow the range between BAD and OK until
Packit 33f14e
	 they differ by 1.  */
Packit 33f14e
      while (true)
Packit 33f14e
	{
Packit 33f14e
	  long_int mid = long_int_avg (ok, bad);
Packit 33f14e
	  if (mid != ok && mid != bad)
Packit 33f14e
	    break;
Packit 33f14e
	  r = convert_time (convert, mid, tp);
Packit 33f14e
	  if (r)
Packit 33f14e
	    ok = mid;
Packit 33f14e
	  else
Packit 33f14e
	    bad = mid;
Packit 33f14e
	}
Packit 33f14e
Packit 33f14e
      if (!r && ok)
Packit 33f14e
	{
Packit 33f14e
	  /* The last conversion attempt failed;
Packit 33f14e
	     revert to the most recent successful attempt.  */
Packit 33f14e
	  r = convert_time (convert, ok, tp);
Packit 33f14e
	}
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  return r;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Convert *TP to a time_t value, inverting
Packit 33f14e
   the monotonic and mostly-unit-linear conversion function CONVERT.
Packit 33f14e
   Use *OFFSET to keep track of a guess at the offset of the result,
Packit 33f14e
   compared to what the result would be for UTC without leap seconds.
Packit 33f14e
   If *OFFSET's guess is correct, only one CONVERT call is needed.
Packit 33f14e
   This function is external because it is used also by timegm.c.  */
Packit 33f14e
time_t
Packit 33f14e
__mktime_internal (struct tm *tp,
Packit 33f14e
		   struct tm *(*convert) (const time_t *, struct tm *),
Packit 33f14e
		   mktime_offset_t *offset)
Packit 33f14e
{
Packit 33f14e
  long_int t, gt, t0, t1, t2, dt;
Packit 33f14e
  struct tm tm;
Packit 33f14e
Packit 33f14e
  /* The maximum number of probes (calls to CONVERT) should be enough
Packit 33f14e
     to handle any combinations of time zone rule changes, solar time,
Packit 33f14e
     leap seconds, and oscillations around a spring-forward gap.
Packit 33f14e
     POSIX.1 prohibits leap seconds, but some hosts have them anyway.  */
Packit 33f14e
  int remaining_probes = 6;
Packit 33f14e
Packit 33f14e
  /* Time requested.  Copy it in case CONVERT modifies *TP; this can
Packit 33f14e
     occur if TP is localtime's returned value and CONVERT is localtime.  */
Packit 33f14e
  int sec = tp->tm_sec;
Packit 33f14e
  int min = tp->tm_min;
Packit 33f14e
  int hour = tp->tm_hour;
Packit 33f14e
  int mday = tp->tm_mday;
Packit 33f14e
  int mon = tp->tm_mon;
Packit 33f14e
  int year_requested = tp->tm_year;
Packit 33f14e
  int isdst = tp->tm_isdst;
Packit 33f14e
Packit 33f14e
  /* 1 if the previous probe was DST.  */
Packit 33f14e
  int dst2;
Packit 33f14e
Packit 33f14e
  /* Ensure that mon is in range, and set year accordingly.  */
Packit 33f14e
  int mon_remainder = mon % 12;
Packit 33f14e
  int negative_mon_remainder = mon_remainder < 0;
Packit 33f14e
  int mon_years = mon / 12 - negative_mon_remainder;
Packit 33f14e
  long_int lyear_requested = year_requested;
Packit 33f14e
  long_int year = lyear_requested + mon_years;
Packit 33f14e
Packit 33f14e
  /* The other values need not be in range:
Packit 33f14e
     the remaining code handles overflows correctly.  */
Packit 33f14e
Packit 33f14e
  /* Calculate day of year from year, month, and day of month.
Packit 33f14e
     The result need not be in range.  */
Packit 33f14e
  int mon_yday = ((__mon_yday[leapyear (year)]
Packit 33f14e
		   [mon_remainder + 12 * negative_mon_remainder])
Packit 33f14e
		  - 1);
Packit 33f14e
  long_int lmday = mday;
Packit 33f14e
  long_int yday = mon_yday + lmday;
Packit 33f14e
Packit 33f14e
  int negative_offset_guess;
Packit 33f14e
Packit 33f14e
  int sec_requested = sec;
Packit 33f14e
Packit 33f14e
  if (LEAP_SECONDS_POSSIBLE)
Packit 33f14e
    {
Packit 33f14e
      /* Handle out-of-range seconds specially,
Packit 33f14e
	 since ydhms_tm_diff assumes every minute has 60 seconds.  */
Packit 33f14e
      if (sec < 0)
Packit 33f14e
	sec = 0;
Packit 33f14e
      if (59 < sec)
Packit 33f14e
	sec = 59;
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  /* Invert CONVERT by probing.  First assume the same offset as last
Packit 33f14e
     time.  */
Packit 33f14e
Packit 33f14e
  INT_SUBTRACT_WRAPV (0, *offset, &negative_offset_guess);
Packit 33f14e
  t0 = ydhms_diff (year, yday, hour, min, sec,
Packit 33f14e
		   EPOCH_YEAR - TM_YEAR_BASE, 0, 0, 0, negative_offset_guess);
Packit 33f14e
Packit 33f14e
  /* Repeatedly use the error to improve the guess.  */
Packit 33f14e
Packit 33f14e
  for (t = t1 = t2 = t0, dst2 = 0;
Packit 33f14e
       (gt = guess_time_tm (year, yday, hour, min, sec, t,
Packit 33f14e
			    ranged_convert (convert, &t, &tm)),
Packit 33f14e
	t != gt);
Packit 33f14e
       t1 = t2, t2 = t, t = gt, dst2 = tm.tm_isdst != 0)
Packit 33f14e
    if (t == t1 && t != t2
Packit 33f14e
	&& (tm.tm_isdst < 0
Packit 33f14e
	    || (isdst < 0
Packit 33f14e
		? dst2 <= (tm.tm_isdst != 0)
Packit 33f14e
		: (isdst != 0) != (tm.tm_isdst != 0))))
Packit 33f14e
      /* We can't possibly find a match, as we are oscillating
Packit 33f14e
	 between two values.  The requested time probably falls
Packit 33f14e
	 within a spring-forward gap of size GT - T.  Follow the common
Packit 33f14e
	 practice in this case, which is to return a time that is GT - T
Packit 33f14e
	 away from the requested time, preferring a time whose
Packit 33f14e
	 tm_isdst differs from the requested value.  (If no tm_isdst
Packit 33f14e
	 was requested and only one of the two values has a nonzero
Packit 33f14e
	 tm_isdst, prefer that value.)  In practice, this is more
Packit 33f14e
	 useful than returning -1.  */
Packit 33f14e
      goto offset_found;
Packit 33f14e
    else if (--remaining_probes == 0)
Packit 33f14e
      return -1;
Packit 33f14e
Packit 33f14e
  /* We have a match.  Check whether tm.tm_isdst has the requested
Packit 33f14e
     value, if any.  */
Packit 33f14e
  if (isdst_differ (isdst, tm.tm_isdst))
Packit 33f14e
    {
Packit 33f14e
      /* tm.tm_isdst has the wrong value.  Look for a neighboring
Packit 33f14e
	 time with the right value, and use its UTC offset.
Packit 33f14e
Packit 33f14e
	 Heuristic: probe the adjacent timestamps in both directions,
Packit 33f14e
	 looking for the desired isdst.  This should work for all real
Packit 33f14e
	 time zone histories in the tz database.  */
Packit 33f14e
Packit 33f14e
      /* Distance between probes when looking for a DST boundary.  In
Packit 33f14e
	 tzdata2003a, the shortest period of DST is 601200 seconds
Packit 33f14e
	 (e.g., America/Recife starting 2000-10-08 01:00), and the
Packit 33f14e
	 shortest period of non-DST surrounded by DST is 694800
Packit 33f14e
	 seconds (Africa/Tunis starting 1943-04-17 01:00).  Use the
Packit 33f14e
	 minimum of these two values, so we don't miss these short
Packit 33f14e
	 periods when probing.  */
Packit 33f14e
      int stride = 601200;
Packit 33f14e
Packit 33f14e
      /* The longest period of DST in tzdata2003a is 536454000 seconds
Packit 33f14e
	 (e.g., America/Jujuy starting 1946-10-01 01:00).  The longest
Packit 33f14e
	 period of non-DST is much longer, but it makes no real sense
Packit 33f14e
	 to search for more than a year of non-DST, so use the DST
Packit 33f14e
	 max.  */
Packit 33f14e
      int duration_max = 536454000;
Packit 33f14e
Packit 33f14e
      /* Search in both directions, so the maximum distance is half
Packit 33f14e
	 the duration; add the stride to avoid off-by-1 problems.  */
Packit 33f14e
      int delta_bound = duration_max / 2 + stride;
Packit 33f14e
Packit 33f14e
      int delta, direction;
Packit 33f14e
Packit 33f14e
      for (delta = stride; delta < delta_bound; delta += stride)
Packit 33f14e
	for (direction = -1; direction <= 1; direction += 2)
Packit 33f14e
	  {
Packit 33f14e
	    long_int ot;
Packit 33f14e
	    if (! INT_ADD_WRAPV (t, delta * direction, &ot))
Packit 33f14e
	      {
Packit 33f14e
		struct tm otm;
Packit 33f14e
		ranged_convert (convert, &ot, &otm;;
Packit 33f14e
		if (! isdst_differ (isdst, otm.tm_isdst))
Packit 33f14e
		  {
Packit 33f14e
		    /* We found the desired tm_isdst.
Packit 33f14e
		       Extrapolate back to the desired time.  */
Packit 33f14e
		    t = guess_time_tm (year, yday, hour, min, sec, ot, &otm;;
Packit 33f14e
		    ranged_convert (convert, &t, &tm;;
Packit 33f14e
		    goto offset_found;
Packit 33f14e
		  }
Packit 33f14e
	      }
Packit 33f14e
	  }
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
 offset_found:
Packit 33f14e
  /* Set *OFFSET to the low-order bits of T - T0 - NEGATIVE_OFFSET_GUESS.
Packit 33f14e
     This is just a heuristic to speed up the next mktime call, and
Packit 33f14e
     correctness is unaffected if integer overflow occurs here.  */
Packit 33f14e
  INT_SUBTRACT_WRAPV (t, t0, &dt);
Packit 33f14e
  INT_SUBTRACT_WRAPV (dt, negative_offset_guess, offset);
Packit 33f14e
Packit 33f14e
  if (LEAP_SECONDS_POSSIBLE && sec_requested != tm.tm_sec)
Packit 33f14e
    {
Packit 33f14e
      /* Adjust time to reflect the tm_sec requested, not the normalized value.
Packit 33f14e
	 Also, repair any damage from a false match due to a leap second.  */
Packit 33f14e
      long_int sec_adjustment = sec == 0 && tm.tm_sec == 60;
Packit 33f14e
      sec_adjustment -= sec;
Packit 33f14e
      sec_adjustment += sec_requested;
Packit 33f14e
      if (INT_ADD_WRAPV (t, sec_adjustment, &t)
Packit 33f14e
	  || ! (mktime_min <= t && t <= mktime_max)
Packit 33f14e
	  || ! convert_time (convert, t, &tm))
Packit 33f14e
	return -1;
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  *tp = tm;
Packit 33f14e
  return t;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
#endif /* NEED_MKTIME_WORKING || NEED_MKTIME_INTERNAL || DEBUG_MKTIME */
Packit 33f14e
Packit 33f14e
#if NEED_MKTIME_WORKING || NEED_MKTIME_WINDOWS || DEBUG_MKTIME
Packit 33f14e
Packit 33f14e
# if NEED_MKTIME_WORKING || DEBUG_MKTIME
Packit 33f14e
static mktime_offset_t localtime_offset;
Packit 33f14e
# endif
Packit 33f14e
Packit 33f14e
/* Convert *TP to a time_t value.  */
Packit 33f14e
time_t
Packit 33f14e
mktime (struct tm *tp)
Packit 33f14e
{
Packit 33f14e
# if NEED_MKTIME_WINDOWS
Packit 33f14e
  /* Rectify the value of the environment variable TZ.
Packit 33f14e
     There are four possible kinds of such values:
Packit 33f14e
       - Traditional US time zone names, e.g. "PST8PDT".  Syntax: see
Packit 33f14e
         <https://msdn.microsoft.com/en-us/library/90s5c885.aspx>
Packit 33f14e
       - Time zone names based on geography, that contain one or more
Packit 33f14e
         slashes, e.g. "Europe/Moscow".
Packit 33f14e
       - Time zone names based on geography, without slashes, e.g.
Packit 33f14e
         "Singapore".
Packit 33f14e
       - Time zone names that contain explicit DST rules.  Syntax: see
Packit 33f14e
         <http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html#tag_08_03>
Packit 33f14e
     The Microsoft CRT understands only the first kind.  It produces incorrect
Packit 33f14e
     results if the value of TZ is of the other kinds.
Packit 33f14e
     But in a Cygwin environment, /etc/profile.d/tzset.sh sets TZ to a value
Packit 33f14e
     of the second kind for most geographies, or of the first kind in a few
Packit 33f14e
     other geographies.  If it is of the second kind, neutralize it.  For the
Packit 33f14e
     Microsoft CRT, an absent or empty TZ means the time zone that the user
Packit 33f14e
     has set in the Windows Control Panel.
Packit 33f14e
     If the value of TZ is of the third or fourth kind -- Cygwin programs
Packit 33f14e
     understand these syntaxes as well --, it does not matter whether we
Packit 33f14e
     neutralize it or not, since these values occur only when a Cygwin user
Packit 33f14e
     has set TZ explicitly; this case is 1. rare and 2. under the user's
Packit 33f14e
     responsibility.  */
Packit 33f14e
  const char *tz = getenv ("TZ");
Packit 33f14e
  if (tz != NULL && strchr (tz, '/') != NULL)
Packit 33f14e
    _putenv ("TZ=");
Packit 33f14e
# endif
Packit 33f14e
Packit 33f14e
# if NEED_MKTIME_WORKING || DEBUG_MKTIME
Packit 33f14e
#  ifdef _LIBC
Packit 33f14e
  /* POSIX.1 8.1.1 requires that whenever mktime() is called, the
Packit 33f14e
     time zone names contained in the external variable 'tzname' shall
Packit 33f14e
     be set as if the tzset() function had been called.  */
Packit 33f14e
  __tzset ();
Packit 33f14e
#  elif HAVE_TZSET
Packit 33f14e
  tzset ();
Packit 33f14e
#  endif
Packit 33f14e
Packit 33f14e
  return __mktime_internal (tp, __localtime_r, &localtime_offset);
Packit 33f14e
# else
Packit 33f14e
#  undef mktime
Packit 33f14e
  return mktime (tp);
Packit 33f14e
# endif
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
#endif /* NEED_MKTIME_WORKING || NEED_MKTIME_WINDOWS || DEBUG_MKTIME */
Packit 33f14e
Packit 33f14e
#ifdef weak_alias
Packit 33f14e
weak_alias (mktime, timelocal)
Packit 33f14e
#endif
Packit 33f14e
Packit 33f14e
#ifdef _LIBC
Packit 33f14e
libc_hidden_def (mktime)
Packit 33f14e
libc_hidden_weak (timelocal)
Packit 33f14e
#endif
Packit 33f14e

Packit 33f14e
#if DEBUG_MKTIME
Packit 33f14e
Packit 33f14e
static int
Packit 33f14e
not_equal_tm (const struct tm *a, const struct tm *b)
Packit 33f14e
{
Packit 33f14e
  return ((a->tm_sec ^ b->tm_sec)
Packit 33f14e
	  | (a->tm_min ^ b->tm_min)
Packit 33f14e
	  | (a->tm_hour ^ b->tm_hour)
Packit 33f14e
	  | (a->tm_mday ^ b->tm_mday)
Packit 33f14e
	  | (a->tm_mon ^ b->tm_mon)
Packit 33f14e
	  | (a->tm_year ^ b->tm_year)
Packit 33f14e
	  | (a->tm_yday ^ b->tm_yday)
Packit 33f14e
	  | isdst_differ (a->tm_isdst, b->tm_isdst));
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
static void
Packit 33f14e
print_tm (const struct tm *tp)
Packit 33f14e
{
Packit 33f14e
  if (tp)
Packit 33f14e
    printf ("%04d-%02d-%02d %02d:%02d:%02d yday %03d wday %d isdst %d",
Packit 33f14e
	    tp->tm_year + TM_YEAR_BASE, tp->tm_mon + 1, tp->tm_mday,
Packit 33f14e
	    tp->tm_hour, tp->tm_min, tp->tm_sec,
Packit 33f14e
	    tp->tm_yday, tp->tm_wday, tp->tm_isdst);
Packit 33f14e
  else
Packit 33f14e
    printf ("0");
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
static int
Packit 33f14e
check_result (time_t tk, struct tm tmk, time_t tl, const struct tm *lt)
Packit 33f14e
{
Packit 33f14e
  if (tk != tl || !lt || not_equal_tm (&tmk, lt))
Packit 33f14e
    {
Packit 33f14e
      printf ("mktime (");
Packit 33f14e
      print_tm (lt);
Packit 33f14e
      printf (")\nyields (");
Packit 33f14e
      print_tm (&tmk);
Packit 33f14e
      printf (") == %ld, should be %ld\n", (long int) tk, (long int) tl);
Packit 33f14e
      return 1;
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  return 0;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
int
Packit 33f14e
main (int argc, char **argv)
Packit 33f14e
{
Packit 33f14e
  int status = 0;
Packit 33f14e
  struct tm tm, tmk, tml;
Packit 33f14e
  struct tm *lt;
Packit 33f14e
  time_t tk, tl, tl1;
Packit 33f14e
  char trailer;
Packit 33f14e
Packit 33f14e
  /* Sanity check, plus call tzset.  */
Packit 33f14e
  tl = 0;
Packit 33f14e
  if (! localtime (&tl))
Packit 33f14e
    {
Packit 33f14e
      printf ("localtime (0) fails\n");
Packit 33f14e
      status = 1;
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  if ((argc == 3 || argc == 4)
Packit 33f14e
      && (sscanf (argv[1], "%d-%d-%d%c",
Packit 33f14e
		  &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &trailer)
Packit 33f14e
	  == 3)
Packit 33f14e
      && (sscanf (argv[2], "%d:%d:%d%c",
Packit 33f14e
		  &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &trailer)
Packit 33f14e
	  == 3))
Packit 33f14e
    {
Packit 33f14e
      tm.tm_year -= TM_YEAR_BASE;
Packit 33f14e
      tm.tm_mon--;
Packit 33f14e
      tm.tm_isdst = argc == 3 ? -1 : atoi (argv[3]);
Packit 33f14e
      tmk = tm;
Packit 33f14e
      tl = mktime (&tmk);
Packit 33f14e
      lt = localtime_r (&tl, &tml);
Packit 33f14e
      printf ("mktime returns %ld == ", (long int) tl);
Packit 33f14e
      print_tm (&tmk);
Packit 33f14e
      printf ("\n");
Packit 33f14e
      status = check_result (tl, tmk, tl, lt);
Packit 33f14e
    }
Packit 33f14e
  else if (argc == 4 || (argc == 5 && strcmp (argv[4], "-") == 0))
Packit 33f14e
    {
Packit 33f14e
      time_t from = atol (argv[1]);
Packit 33f14e
      time_t by = atol (argv[2]);
Packit 33f14e
      time_t to = atol (argv[3]);
Packit 33f14e
Packit 33f14e
      if (argc == 4)
Packit 33f14e
	for (tl = from; by < 0 ? to <= tl : tl <= to; tl = tl1)
Packit 33f14e
	  {
Packit 33f14e
	    lt = localtime_r (&tl, &tml);
Packit 33f14e
	    if (lt)
Packit 33f14e
	      {
Packit 33f14e
		tmk = tml;
Packit 33f14e
		tk = mktime (&tmk);
Packit 33f14e
		status |= check_result (tk, tmk, tl, &tml);
Packit 33f14e
	      }
Packit 33f14e
	    else
Packit 33f14e
	      {
Packit 33f14e
		printf ("localtime_r (%ld) yields 0\n", (long int) tl);
Packit 33f14e
		status = 1;
Packit 33f14e
	      }
Packit 33f14e
	    tl1 = tl + by;
Packit 33f14e
	    if ((tl1 < tl) != (by < 0))
Packit 33f14e
	      break;
Packit 33f14e
	  }
Packit 33f14e
      else
Packit 33f14e
	for (tl = from; by < 0 ? to <= tl : tl <= to; tl = tl1)
Packit 33f14e
	  {
Packit 33f14e
	    /* Null benchmark.  */
Packit 33f14e
	    lt = localtime_r (&tl, &tml);
Packit 33f14e
	    if (lt)
Packit 33f14e
	      {
Packit 33f14e
		tmk = tml;
Packit 33f14e
		tk = tl;
Packit 33f14e
		status |= check_result (tk, tmk, tl, &tml);
Packit 33f14e
	      }
Packit 33f14e
	    else
Packit 33f14e
	      {
Packit 33f14e
		printf ("localtime_r (%ld) yields 0\n", (long int) tl);
Packit 33f14e
		status = 1;
Packit 33f14e
	      }
Packit 33f14e
	    tl1 = tl + by;
Packit 33f14e
	    if ((tl1 < tl) != (by < 0))
Packit 33f14e
	      break;
Packit 33f14e
	  }
Packit 33f14e
    }
Packit 33f14e
  else
Packit 33f14e
    printf ("Usage:\
Packit 33f14e
\t%s YYYY-MM-DD HH:MM:SS [ISDST] # Test given time.\n\
Packit 33f14e
\t%s FROM BY TO # Test values FROM, FROM+BY, ..., TO.\n\
Packit 33f14e
\t%s FROM BY TO - # Do not test those values (for benchmark).\n",
Packit 33f14e
	    argv[0], argv[0], argv[0]);
Packit 33f14e
Packit 33f14e
  return status;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
#endif /* DEBUG_MKTIME */
Packit 33f14e

Packit 33f14e
/*
Packit 33f14e
Local Variables:
Packit 33f14e
compile-command: "gcc -DDEBUG_MKTIME -I. -Wall -W -O2 -g mktime.c -o mktime"
Packit 33f14e
End:
Packit 33f14e
*/