mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-09-30 15:51:24 +02:00
Consolidate several near-identical uses of mktime() into a single
routine DetermineLocalTimeZone(). In that routine, be more wary of broken mktime() implementations than the original code was: don't allow mktime to change the already-set y/m/d/h/m/s information, and don't use tm_gmtoff if mktime failed. Possibly this will resolve some of the complaints we've been hearing from users of Middle Eastern timezones on RedHat.
This commit is contained in:
parent
0cec2bb0cd
commit
f5ba72ea04
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.63 2001/04/03 18:05:53 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.64 2001/05/03 22:53:07 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -869,32 +869,7 @@ DecodeDateTime(char **field, int *ftype, int nf,
|
||||
if (fmask & DTK_M(DTZMOD))
|
||||
return -1;
|
||||
|
||||
if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday))
|
||||
{
|
||||
#if defined(HAVE_TM_ZONE) || defined(HAVE_INT_TIMEZONE)
|
||||
tm->tm_year -= 1900;
|
||||
tm->tm_mon -= 1;
|
||||
tm->tm_isdst = -1;
|
||||
mktime(tm);
|
||||
tm->tm_year += 1900;
|
||||
tm->tm_mon += 1;
|
||||
|
||||
#if defined(HAVE_TM_ZONE)
|
||||
*tzp = -(tm->tm_gmtoff); /* tm_gmtoff is
|
||||
* Sun/DEC-ism */
|
||||
#elif defined(HAVE_INT_TIMEZONE)
|
||||
*tzp = ((tm->tm_isdst > 0) ? (TIMEZONE_GLOBAL - 3600) : TIMEZONE_GLOBAL);
|
||||
#endif /* HAVE_INT_TIMEZONE */
|
||||
|
||||
#else /* not (HAVE_TM_ZONE || HAVE_INT_TIMEZONE) */
|
||||
*tzp = CTimeZone;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
tm->tm_isdst = 0;
|
||||
*tzp = 0;
|
||||
}
|
||||
*tzp = DetermineLocalTimeZone(tm);
|
||||
}
|
||||
}
|
||||
|
||||
@ -902,6 +877,69 @@ DecodeDateTime(char **field, int *ftype, int nf,
|
||||
} /* DecodeDateTime() */
|
||||
|
||||
|
||||
/* DetermineLocalTimeZone()
|
||||
* 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
|
||||
* (ie, regular or daylight-savings time) at that time. Set the struct tm's
|
||||
* tm_isdst field accordingly, and return the actual timezone offset.
|
||||
*
|
||||
* This subroutine exists mainly to centralize uses of mktime() and defend
|
||||
* against mktime() bugs on various platforms...
|
||||
*/
|
||||
int
|
||||
DetermineLocalTimeZone(struct tm * tm)
|
||||
{
|
||||
int tz;
|
||||
|
||||
if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday))
|
||||
{
|
||||
#if defined(HAVE_TM_ZONE) || defined(HAVE_INT_TIMEZONE)
|
||||
/*
|
||||
* Some buggy mktime() implementations may change the year/month/day
|
||||
* when given a time right at a DST boundary. To prevent corruption
|
||||
* of the caller's data, give mktime() a copy...
|
||||
*/
|
||||
struct tm tt,
|
||||
*tmp = &tt;
|
||||
|
||||
*tmp = *tm;
|
||||
/* change to Unix conventions for year/month */
|
||||
tmp->tm_year -= 1900;
|
||||
tmp->tm_mon -= 1;
|
||||
|
||||
/* indicate timezone unknown */
|
||||
tmp->tm_isdst = -1;
|
||||
|
||||
mktime(tmp);
|
||||
|
||||
tm->tm_isdst = tmp->tm_isdst;
|
||||
|
||||
#if defined(HAVE_TM_ZONE)
|
||||
/* tm_gmtoff is Sun/DEC-ism */
|
||||
if (tmp->tm_isdst >= 0)
|
||||
tz = -(tmp->tm_gmtoff);
|
||||
else
|
||||
tz = 0; /* assume GMT if mktime failed */
|
||||
#elif defined(HAVE_INT_TIMEZONE)
|
||||
tz = ((tmp->tm_isdst > 0) ? (TIMEZONE_GLOBAL - 3600) : TIMEZONE_GLOBAL);
|
||||
#endif /* HAVE_INT_TIMEZONE */
|
||||
|
||||
#else /* not (HAVE_TM_ZONE || HAVE_INT_TIMEZONE) */
|
||||
tm->tm_isdst = 0;
|
||||
tz = CTimeZone;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Given date is out of range, so assume GMT */
|
||||
tm->tm_isdst = 0;
|
||||
tz = 0;
|
||||
}
|
||||
|
||||
return tz;
|
||||
}
|
||||
|
||||
|
||||
/* DecodeTimeOnly()
|
||||
* Interpret parsed string as time fields only.
|
||||
* Note that support for time zone is here for
|
||||
@ -1119,22 +1157,8 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
|
||||
tmp->tm_min = tm->tm_min;
|
||||
tmp->tm_sec = tm->tm_sec;
|
||||
|
||||
#if defined(HAVE_TM_ZONE) || defined(HAVE_INT_TIMEZONE)
|
||||
tmp->tm_year -= 1900;
|
||||
tmp->tm_mon -= 1;
|
||||
tmp->tm_isdst = -1;
|
||||
mktime(tmp);
|
||||
*tzp = DetermineLocalTimeZone(tmp);
|
||||
tm->tm_isdst = tmp->tm_isdst;
|
||||
|
||||
#if defined(HAVE_TM_ZONE)
|
||||
*tzp = -(tmp->tm_gmtoff); /* tm_gmtoff is Sun/DEC-ism */
|
||||
#elif defined(HAVE_INT_TIMEZONE)
|
||||
*tzp = ((tmp->tm_isdst > 0) ? (TIMEZONE_GLOBAL - 3600) : TIMEZONE_GLOBAL);
|
||||
#endif
|
||||
|
||||
#else /* not (HAVE_TM_ZONE || HAVE_INT_TIMEZONE) */
|
||||
*tzp = CTimeZone;
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
* formatting.c
|
||||
*
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/formatting.c,v 1.36 2001/03/23 04:49:54 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/formatting.c,v 1.37 2001/05/03 22:53:07 tgl Exp $
|
||||
*
|
||||
*
|
||||
* Portions Copyright (c) 1999-2000, PostgreSQL Global Development Group
|
||||
@ -2936,37 +2936,7 @@ to_timestamp(PG_FUNCTION_ARGS)
|
||||
#ifdef DEBUG_TO_FROM_CHAR
|
||||
NOTICE_TM;
|
||||
#endif
|
||||
if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday))
|
||||
{
|
||||
|
||||
#if defined(HAVE_TM_ZONE) || defined(HAVE_INT_TIMEZONE)
|
||||
tm->tm_isdst = -1;
|
||||
tm->tm_year -= 1900;
|
||||
tm->tm_mon -= 1;
|
||||
|
||||
#ifdef DEBUG_TO_FROM_CHAR
|
||||
elog(DEBUG_elog_output, "TO-FROM_CHAR: Call mktime()");
|
||||
NOTICE_TM;
|
||||
#endif
|
||||
mktime(tm);
|
||||
tm->tm_year += 1900;
|
||||
tm->tm_mon += 1;
|
||||
|
||||
#if defined(HAVE_TM_ZONE)
|
||||
tz = -(tm->tm_gmtoff); /* tm_gmtoff is Sun/DEC-ism */
|
||||
#elif defined(HAVE_INT_TIMEZONE)
|
||||
tz = ((tm->tm_isdst > 0) ? (TIMEZONE_GLOBAL - 3600) : TIMEZONE_GLOBAL);
|
||||
#endif
|
||||
|
||||
#else /* not (HAVE_TM_ZONE || HAVE_INT_TIMEZONE) */
|
||||
tz = CTimeZone;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
tm->tm_isdst = 0;
|
||||
tz = 0;
|
||||
}
|
||||
tz = DetermineLocalTimeZone(tm);
|
||||
#ifdef DEBUG_TO_FROM_CHAR
|
||||
NOTICE_TM;
|
||||
#endif
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/timestamp.c,v 1.48 2001/05/03 19:00:36 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/timestamp.c,v 1.49 2001/05/03 22:53:07 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -990,32 +990,7 @@ timestamp_pl_span(PG_FUNCTION_ARGS)
|
||||
if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
|
||||
tm->tm_mday = (day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]);
|
||||
|
||||
if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday))
|
||||
{
|
||||
#if defined(HAVE_TM_ZONE) || defined(HAVE_INT_TIMEZONE)
|
||||
tm->tm_year -= 1900;
|
||||
tm->tm_mon -= 1;
|
||||
tm->tm_isdst = -1;
|
||||
mktime(tm);
|
||||
tm->tm_year += 1900;
|
||||
tm->tm_mon += 1;
|
||||
|
||||
#if defined(HAVE_TM_ZONE)
|
||||
tz = -(tm->tm_gmtoff); /* tm_gmtoff is
|
||||
* Sun/DEC-ism */
|
||||
#elif defined(HAVE_INT_TIMEZONE)
|
||||
tz = ((tm->tm_isdst > 0) ? (TIMEZONE_GLOBAL - 3600) : TIMEZONE_GLOBAL);
|
||||
#endif
|
||||
|
||||
#else /* not (HAVE_TM_ZONE || HAVE_INT_TIMEZONE) */
|
||||
tz = CTimeZone;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
tm->tm_isdst = 0;
|
||||
tz = 0;
|
||||
}
|
||||
tz = DetermineLocalTimeZone(tm);
|
||||
|
||||
if (tm2timestamp(tm, fsec, &tz, &dt) != 0)
|
||||
elog(ERROR, "Unable to add timestamp and interval");
|
||||
@ -1631,31 +1606,7 @@ timestamp_trunc(PG_FUNCTION_ARGS)
|
||||
result = 0;
|
||||
}
|
||||
|
||||
if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday))
|
||||
{
|
||||
#if defined(HAVE_TM_ZONE) || defined(HAVE_INT_TIMEZONE)
|
||||
tm->tm_year -= 1900;
|
||||
tm->tm_mon -= 1;
|
||||
tm->tm_isdst = -1;
|
||||
mktime(tm);
|
||||
tm->tm_year += 1900;
|
||||
tm->tm_mon += 1;
|
||||
|
||||
#if defined(HAVE_TM_ZONE)
|
||||
tz = -(tm->tm_gmtoff); /* tm_gmtoff is Sun/DEC-ism */
|
||||
#elif defined(HAVE_INT_TIMEZONE)
|
||||
tz = ((tm->tm_isdst > 0) ? (TIMEZONE_GLOBAL - 3600) : TIMEZONE_GLOBAL);
|
||||
#endif
|
||||
|
||||
#else /* not (HAVE_TM_ZONE || HAVE_INT_TIMEZONE) */
|
||||
tz = CTimeZone;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
tm->tm_isdst = 0;
|
||||
tz = 0;
|
||||
}
|
||||
tz = DetermineLocalTimeZone(tm);
|
||||
|
||||
if (tm2timestamp(tm, fsec, &tz, &result) != 0)
|
||||
elog(ERROR, "Unable to truncate timestamp to '%s'", lowunits);
|
||||
|
@ -9,7 +9,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: datetime.h,v 1.17 2001/01/24 19:43:28 momjian Exp $
|
||||
* $Id: datetime.h,v 1.18 2001/05/03 22:53:07 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -255,6 +255,8 @@ extern int DecodeDateDelta(char **field, int *ftype,
|
||||
int nf, int *dtype,
|
||||
struct tm * tm, double *fsec);
|
||||
|
||||
extern int DetermineLocalTimeZone(struct tm * tm);
|
||||
|
||||
extern int EncodeDateOnly(struct tm * tm, int style, char *str);
|
||||
extern int EncodeTimeOnly(struct tm * tm, double fsec, int *tzp, int style, char *str);
|
||||
extern int EncodeDateTime(struct tm * tm, double fsec, int *tzp, char **tzn, int style, char *str);
|
||||
|
Loading…
Reference in New Issue
Block a user