Blame src/gl/mktime.c

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