On Fri, Feb 21, 2003 at 08:39:12PM -0600, Ross J. Reedstrom wrote: > > Every other validly formatted TZ variable that returns GMT should be > caught be the datetktbl check. > > I'll play with it this weekend, see how hard it is to make it work.
O.K., the weekend's over, And I've created two different version of this. Both work, ipass all the regression test, and solve the 'CST is just a funny way to say GMT' problem. I was able to make use of DecodePosixTimezone (DPT) from Thomas's datetime parsing code in assign_timezone. However, the order of application of this vis. tzset is unclear. I had proposed doing the DPT first, then tzset, then a NOTICE if it looked like tzset didn't. Got that working, but discovered a change of behavior: for some of those who have a timezone in the zoneinfo database that is a three letter abbreviation, the current code (tzset only) will provide daylight savings time transitions, so that a timestamp in July returns a different timezone than one in February. This is not true for our internal values of set time zone: there, we convert to a numerical offset, which is constant no matter when the timestamp occurs. This is still a win for those who's timezone abbreviation is _not_ in the zoneinfo DB, (such as CST), which currently is silently interpreted as an odd spelling of GMT. Second solution - try tzset() first, and apply the following heuristic to see if it took: tzname[0]==$TZ and tzname[1]=="" and timezone=0 and daylight=0 In other words, _all_ the timezone related information remains the default. I tested this against the 1607 zoneinfo files on my system: every one was filtered out, even things that _are_ GMT with no DST (they all had a non-null tzname[1] == tzname[0]) If this succeeds (i.e. tzset didn't recognize the TZ), go ahead and look it up in our big table'o date/time strings. This also works, fixing the bogus GMT spellings, without changing current behavior for any string that is not bogus. Note that the sysadmin can always tell if tzset or the table was used, by looking at the format of the 'show time zone' result. If tzset was called, this is the string that was passed to 'set time zone'. If the table was used, it will be an hours west of GMT offset. The problem with this approach is that it does nothing to reduce our dependency on the OS timezone functionality. Comments? I've attached the second patch for discussion. Ross
Index: src//backend/commands/variable.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/commands/variable.c,v retrieving revision 1.73 diff -c -r1.73 variable.c *** src//backend/commands/variable.c 2003/02/01 18:31:28 1.73 --- src//backend/commands/variable.c 2003/02/24 21:29:44 *************** *** 243,252 **** const char * assign_timezone(const char *value, bool doit, bool interactive) { ! char *result; ! char *endptr; double hours; /* * Check for INTERVAL 'foo' */ --- 243,257 ---- const char * assign_timezone(const char *value, bool doit, bool interactive) { ! char *result; ! char *endptr; ! char tztmp[sizeof(tzbuf)]; ! char *lp; ! const char *cp; double hours; + int tzval,i; + /* * Check for INTERVAL 'foo' */ *************** *** 337,348 **** else { /* ! * Otherwise assume it is a timezone name. * ! * XXX unfortunately we have no reasonable way to check whether a ! * timezone name is good, so we have to just assume that it ! * is. */ if (doit) { strcpy(tzbuf, "TZ="); --- 342,360 ---- else { /* ! * Otherwise assume it is a timezone name. ! * Try tzset() first. If that fails, see if our internal ! * table of timezone names, can handle it. * ! * XXX unfortunately we have only an approximate way to check ! * whether a timezone name is good: if the value of TZ is returned ! * as the canonical tzname, there is no daylight savings time ! * (flag or canonical second name) _and_ the offset is GMT, ! * tzset() punted, i.e., returned all default values. ! * If that happens, try the internal table - if _that_ fails, ! * throw a notice. rjr 2003/02/23 */ + if (doit) { strcpy(tzbuf, "TZ="); *************** *** 351,356 **** --- 363,392 ---- elog(LOG, "assign_timezone: putenv failed"); tzset(); HasCTZSet = false; + if (timezone == 0.0 && strcmp(value,tzname[0]) == 0 && + daylight == 0 && strcmp("",tzname[1]) == 0) + { + cp=value; + lp=tztmp; + *lp++ = tolower((unsigned char) *cp++); + for (i = 0; (i < sizeof(tztmp)) && *cp; i++) + *lp++ = tolower((unsigned char) *cp++); + /* XXX DecodePosixTimezone seems to not handle + * a three character string - there's a fencepost somewhere */ + *lp++ = ' '; + *lp = '\0'; + tzval=0; + if (DecodePosixTimezone(tztmp, &tzval) == 0) + { + CTimeZone = tzval; + HasCTZSet = true; + strncpy(tzbuf,value, sizeof(tzbuf) - 1); + } + else + { + elog(NOTICE, "assign_timezone: unusual spelling of GMT: %s", value); + } + } } } } Index: src//backend/utils/adt/datetime.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/utils/adt/datetime.c,v retrieving revision 1.102 diff -c -r1.102 datetime.c *** src//backend/utils/adt/datetime.c 2003/02/22 05:57:44 1.102 --- src//backend/utils/adt/datetime.c 2003/02/24 21:29:45 *************** *** 33,42 **** struct tm * tm, fsec_t *fsec, int *is2digits); static int DecodeTime(char *str, int fmask, int *tmask, struct tm * tm, fsec_t *fsec); ! static int DecodeTimezone(char *str, int *tzp); static datetkn *datebsearch(char *key, datetkn *base, unsigned int nel); static int DecodeDate(char *str, int fmask, int *tmask, struct tm * tm); - static int DecodePosixTimezone(char *str, int *val); static void TrimTrailingZeros(char *str); --- 33,41 ---- struct tm * tm, fsec_t *fsec, int *is2digits); static int DecodeTime(char *str, int fmask, int *tmask, struct tm * tm, fsec_t *fsec); ! static int DecodeTimezone(char *str, int *tzp); static datetkn *datebsearch(char *key, datetkn *base, unsigned int nel); static int DecodeDate(char *str, int fmask, int *tmask, struct tm * tm); static void TrimTrailingZeros(char *str); *************** *** 2595,2601 **** * PST+h * - thomas 2000-03-15 */ ! static int DecodePosixTimezone(char *str, int *tzp) { int val, --- 2594,2600 ---- * PST+h * - thomas 2000-03-15 */ ! int DecodePosixTimezone(char *str, int *tzp) { int val, Index: src//include/utils/datetime.h =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/include/utils/datetime.h,v retrieving revision 1.36 diff -c -r1.36 datetime.h *** src//include/utils/datetime.h 2003/02/20 05:24:55 1.36 --- src//include/utils/datetime.h 2003/02/24 21:29:45 *************** *** 280,285 **** --- 280,287 ---- int nf, int *dtype, struct tm * tm, fsec_t *fsec); + extern int DecodePosixTimezone(char *str, int *tzp); + extern int DetermineLocalTimeZone(struct tm * tm); extern int EncodeDateOnly(struct tm * tm, int style, char *str);
---------------------------(end of broadcast)--------------------------- TIP 3: if posting/reading through Usenet, please send an appropriate subscribe-nomail command to [EMAIL PROTECTED] so that your message can get through to the mailing list cleanly