mirror of
https://github.com/postgres/postgres.git
synced 2025-08-09 17:03:00 +03:00
Back-patch fixes to work around broken mktime() in recent glibc releases.
This commit is contained in:
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/date.c,v 1.64.2.2 2002/08/22 05:27:41 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/adt/date.c,v 1.64.2.3 2002/09/30 20:57:10 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -274,28 +274,20 @@ date_timestamptz(PG_FUNCTION_ARGS)
|
|||||||
TimestampTz result;
|
TimestampTz result;
|
||||||
struct tm tt,
|
struct tm tt,
|
||||||
*tm = &tt;
|
*tm = &tt;
|
||||||
time_t utime;
|
|
||||||
|
|
||||||
j2date((dateVal + date2j(2000, 1, 1)), &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
|
j2date((dateVal + date2j(2000, 1, 1)),
|
||||||
|
&(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
|
||||||
|
|
||||||
if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday))
|
if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday))
|
||||||
{
|
{
|
||||||
#if defined(HAVE_TM_ZONE) || defined(HAVE_INT_TIMEZONE)
|
int tz;
|
||||||
|
|
||||||
tm->tm_hour = 0;
|
tm->tm_hour = 0;
|
||||||
tm->tm_min = 0;
|
tm->tm_min = 0;
|
||||||
tm->tm_sec = 0;
|
tm->tm_sec = 0;
|
||||||
tm->tm_isdst = -1;
|
tz = DetermineLocalTimeZone(tm);
|
||||||
|
|
||||||
tm->tm_year -= 1900;
|
result = dateVal * 86400.0 + tz;
|
||||||
tm->tm_mon -= 1;
|
|
||||||
utime = mktime(tm);
|
|
||||||
if (utime == -1)
|
|
||||||
elog(ERROR, "Unable to convert date to tm");
|
|
||||||
|
|
||||||
result = utime + ((date2j(1970, 1, 1) - date2j(2000, 1, 1)) * 86400.0);
|
|
||||||
#else
|
|
||||||
result = dateVal * 86400.0 + CTimeZone;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.87.2.1 2002/02/25 16:22:48 thomas Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.87.2.2 2002/09/30 20:57:11 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -1427,13 +1427,15 @@ DecodeDateTime(char **field, int *ftype, int nf,
|
|||||||
|
|
||||||
|
|
||||||
/* DetermineLocalTimeZone()
|
/* DetermineLocalTimeZone()
|
||||||
|
*
|
||||||
* Given a struct tm in which tm_year, tm_mon, tm_mday, tm_hour, tm_min, and
|
* Given a struct tm in which tm_year, tm_mon, tm_mday, tm_hour, tm_min, and
|
||||||
* tm_sec fields are set, attempt to determine the applicable local zone
|
* tm_sec fields are set, attempt to determine the applicable local zone
|
||||||
* (ie, regular or daylight-savings time) at that time. Set the struct tm's
|
* (ie, regular or daylight-savings time) at that time. Set the struct tm's
|
||||||
* tm_isdst field accordingly, and return the actual timezone offset.
|
* tm_isdst field accordingly, and return the actual timezone offset.
|
||||||
*
|
*
|
||||||
* This subroutine exists mainly to centralize uses of mktime() and defend
|
* This subroutine exists to centralize uses of mktime() and defend against
|
||||||
* against mktime() bugs on various platforms...
|
* mktime() bugs/restrictions on various platforms. This should be
|
||||||
|
* the *only* call of mktime() in the backend.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
DetermineLocalTimeZone(struct tm * tm)
|
DetermineLocalTimeZone(struct tm * tm)
|
||||||
@@ -1441,7 +1443,10 @@ DetermineLocalTimeZone(struct tm * tm)
|
|||||||
int tz;
|
int tz;
|
||||||
|
|
||||||
if (HasCTZSet)
|
if (HasCTZSet)
|
||||||
|
{
|
||||||
|
tm->tm_isdst = 0; /* for lack of a better idea */
|
||||||
tz = CTimeZone;
|
tz = CTimeZone;
|
||||||
|
}
|
||||||
else if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday))
|
else if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday))
|
||||||
{
|
{
|
||||||
#if defined(HAVE_TM_ZONE) || defined(HAVE_INT_TIMEZONE)
|
#if defined(HAVE_TM_ZONE) || defined(HAVE_INT_TIMEZONE)
|
||||||
@@ -1463,20 +1468,90 @@ DetermineLocalTimeZone(struct tm * tm)
|
|||||||
/* indicate timezone unknown */
|
/* indicate timezone unknown */
|
||||||
tmp->tm_isdst = -1;
|
tmp->tm_isdst = -1;
|
||||||
|
|
||||||
mktime(tmp);
|
if (mktime(tmp) != ((time_t) -1) &&
|
||||||
|
tmp->tm_isdst >= 0)
|
||||||
tm->tm_isdst = tmp->tm_isdst;
|
{
|
||||||
|
/* mktime() succeeded, trust its result */
|
||||||
|
tm->tm_isdst = tmp->tm_isdst;
|
||||||
|
|
||||||
#if defined(HAVE_TM_ZONE)
|
#if defined(HAVE_TM_ZONE)
|
||||||
/* tm_gmtoff is Sun/DEC-ism */
|
/* tm_gmtoff is Sun/DEC-ism */
|
||||||
if (tmp->tm_isdst >= 0)
|
|
||||||
tz = -(tmp->tm_gmtoff);
|
tz = -(tmp->tm_gmtoff);
|
||||||
else
|
|
||||||
tz = 0; /* assume UTC if mktime failed */
|
|
||||||
#elif defined(HAVE_INT_TIMEZONE)
|
#elif defined(HAVE_INT_TIMEZONE)
|
||||||
tz = ((tmp->tm_isdst > 0) ? (TIMEZONE_GLOBAL - 3600) : TIMEZONE_GLOBAL);
|
tz = ((tmp->tm_isdst > 0) ? (TIMEZONE_GLOBAL - 3600) : TIMEZONE_GLOBAL);
|
||||||
#endif /* HAVE_INT_TIMEZONE */
|
#endif /* HAVE_INT_TIMEZONE */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* We have a buggy (not to say deliberately brain damaged)
|
||||||
|
* mktime(). Work around it by using localtime() instead.
|
||||||
|
*
|
||||||
|
* First, generate the time_t value corresponding to the given
|
||||||
|
* y/m/d/h/m/s taken as GMT time. This will not overflow (at
|
||||||
|
* least not for time_t taken as signed) because of the range
|
||||||
|
* check we did above.
|
||||||
|
*/
|
||||||
|
long day,
|
||||||
|
mysec,
|
||||||
|
locsec,
|
||||||
|
delta1,
|
||||||
|
delta2;
|
||||||
|
time_t mytime;
|
||||||
|
|
||||||
|
day = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) -
|
||||||
|
date2j(1970, 1, 1));
|
||||||
|
mysec = tm->tm_sec + (tm->tm_min + (day * 24 + tm->tm_hour) * 60) * 60;
|
||||||
|
mytime = (time_t) mysec;
|
||||||
|
/*
|
||||||
|
* Use localtime to convert that time_t to broken-down time, and
|
||||||
|
* reassemble to get a representation of local time.
|
||||||
|
*/
|
||||||
|
tmp = localtime(&mytime);
|
||||||
|
day = (date2j(tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday) -
|
||||||
|
date2j(1970, 1, 1));
|
||||||
|
locsec = tmp->tm_sec + (tmp->tm_min + (day * 24 + tmp->tm_hour) * 60) * 60;
|
||||||
|
/*
|
||||||
|
* The local time offset corresponding to that GMT time is
|
||||||
|
* now computable as mysec - locsec.
|
||||||
|
*/
|
||||||
|
delta1 = mysec - locsec;
|
||||||
|
/*
|
||||||
|
* However, if that GMT time and the local time we are actually
|
||||||
|
* interested in are on opposite sides of a daylight-savings-time
|
||||||
|
* transition, then this is not the time offset we want. So,
|
||||||
|
* adjust the time_t to be what we think the GMT time corresponding
|
||||||
|
* to our target local time is, and repeat the localtime() call
|
||||||
|
* and delta calculation. We may have to do it twice before we
|
||||||
|
* have a trustworthy delta.
|
||||||
|
*
|
||||||
|
* Note: think not to put a loop here, since if we've been given
|
||||||
|
* an "impossible" local time (in the gap during a spring-forward
|
||||||
|
* transition) we'd never get out of the loop. Twice is enough
|
||||||
|
* to give the behavior we want, which is that "impossible" times
|
||||||
|
* are taken as standard time, while at a fall-back boundary
|
||||||
|
* ambiguous times are also taken as standard.
|
||||||
|
*/
|
||||||
|
mysec += delta1;
|
||||||
|
mytime = (time_t) mysec;
|
||||||
|
tmp = localtime(&mytime);
|
||||||
|
day = (date2j(tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday) -
|
||||||
|
date2j(1970, 1, 1));
|
||||||
|
locsec = tmp->tm_sec + (tmp->tm_min + (day * 24 + tmp->tm_hour) * 60) * 60;
|
||||||
|
delta2 = mysec - locsec;
|
||||||
|
if (delta2 != delta1)
|
||||||
|
{
|
||||||
|
mysec += (delta2 - delta1);
|
||||||
|
mytime = (time_t) mysec;
|
||||||
|
tmp = localtime(&mytime);
|
||||||
|
day = (date2j(tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday) -
|
||||||
|
date2j(1970, 1, 1));
|
||||||
|
locsec = tmp->tm_sec + (tmp->tm_min + (day * 24 + tmp->tm_hour) * 60) * 60;
|
||||||
|
delta2 = mysec - locsec;
|
||||||
|
}
|
||||||
|
tm->tm_isdst = tmp->tm_isdst;
|
||||||
|
tz = (int) delta2;
|
||||||
|
}
|
||||||
#else /* not (HAVE_TM_ZONE || HAVE_INT_TIMEZONE) */
|
#else /* not (HAVE_TM_ZONE || HAVE_INT_TIMEZONE) */
|
||||||
tm->tm_isdst = 0;
|
tm->tm_isdst = 0;
|
||||||
tz = CTimeZone;
|
tz = CTimeZone;
|
||||||
|
Reference in New Issue
Block a user