|
|
|
@ -1,4 +1,4 @@ |
|
|
|
|
/* $PostgreSQL: pgsql/src/interfaces/ecpg/pgtypeslib/dt_common.c,v 1.39 2007/05/21 07:04:00 meskes Exp $ */ |
|
|
|
|
/* $PostgreSQL: pgsql/src/interfaces/ecpg/pgtypeslib/dt_common.c,v 1.40 2007/05/21 07:07:48 meskes Exp $ */ |
|
|
|
|
|
|
|
|
|
#include "postgres_fe.h" |
|
|
|
|
|
|
|
|
@ -1090,159 +1090,6 @@ GetCurrentDateTime(struct tm * tm) |
|
|
|
|
abstime2tm(time(NULL), &tz, tm, NULL); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* 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 to centralize uses of mktime() and defend against |
|
|
|
|
* mktime() bugs/restrictions on various platforms. This should be |
|
|
|
|
* the *only* call of mktime() in the backend. |
|
|
|
|
*/ |
|
|
|
|
static 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; |
|
|
|
|
|
|
|
|
|
if (mktime(tmp) != (time_t) -1 && tmp->tm_isdst >= 0) |
|
|
|
|
{ |
|
|
|
|
/* mktime() succeeded, trust its result */ |
|
|
|
|
tm->tm_isdst = tmp->tm_isdst; |
|
|
|
|
|
|
|
|
|
#if defined(HAVE_TM_ZONE) |
|
|
|
|
/* tm_gmtoff is Sun/DEC-ism */ |
|
|
|
|
tz = -tmp->tm_gmtoff; |
|
|
|
|
#elif defined(HAVE_INT_TIMEZONE) |
|
|
|
|
tz = (tmp->tm_isdst > 0) ? TIMEZONE_GLOBAL - SECS_PER_HOUR : TIMEZONE_GLOBAL; |
|
|
|
|
#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 * HOURS_PER_DAY + tm->tm_hour) * MINS_PER_HOUR) * SECS_PER_MINUTE; |
|
|
|
|
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); |
|
|
|
|
if (!tmp) |
|
|
|
|
{ |
|
|
|
|
tm->tm_isdst = 0; |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
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 * HOURS_PER_DAY + tmp->tm_hour) * MINS_PER_HOUR) * SECS_PER_MINUTE; |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 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); |
|
|
|
|
if (!tmp) |
|
|
|
|
{ |
|
|
|
|
tm->tm_isdst = 0; |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
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 * HOURS_PER_DAY + tmp->tm_hour) * MINS_PER_HOUR) * SECS_PER_MINUTE; |
|
|
|
|
delta2 = mysec - locsec; |
|
|
|
|
if (delta2 != delta1) |
|
|
|
|
{ |
|
|
|
|
mysec += (delta2 - delta1); |
|
|
|
|
mytime = (time_t) mysec; |
|
|
|
|
tmp = localtime(&mytime); |
|
|
|
|
if (!tmp) |
|
|
|
|
{ |
|
|
|
|
tm->tm_isdst = 0; |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
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 * HOURS_PER_DAY + tmp->tm_hour) * MINS_PER_HOUR) * SECS_PER_MINUTE; |
|
|
|
|
delta2 = mysec - locsec; |
|
|
|
|
} |
|
|
|
|
tm->tm_isdst = tmp->tm_isdst; |
|
|
|
|
tz = (int) delta2; |
|
|
|
|
} |
|
|
|
|
#else /* not (HAVE_TM_ZONE || HAVE_INT_TIMEZONE) */ |
|
|
|
|
/* Assume UTC if no system timezone info available */ |
|
|
|
|
tm->tm_isdst = 0; |
|
|
|
|
tz = 0; |
|
|
|
|
#endif |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
/* Given date is out of range, so assume UTC */ |
|
|
|
|
tm->tm_isdst = 0; |
|
|
|
|
tz = 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return tz; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void |
|
|
|
|
dt2time(double jd, int *hour, int *min, int *sec, fsec_t *fsec) |
|
|
|
|
{ |
|
|
|
|