From: Tom Lane Date: Tue, 1 Jul 2008 03:40:55 +0000 (+0000) Subject: Fix identify_system_timezone() so that it tests the behavior of the system X-Git-Tag: REL8_4_BETA1~1220 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8c3340fe166fba79aeb5a51dffa951bbf63d9af4;p=postgresql Fix identify_system_timezone() so that it tests the behavior of the system timezone setting in the current year and for 100 years back, rather than always examining years 1904-2004. The original coding would have problems distinguishing zones whose behavior diverged only after 2004; which is a situation we will surely face sometime, if it's not out there already. In passing, also prevent selection of the dummy "Factory" timezone, even if that's exactly what the system is using. Reporting time as GMT seems better than that. --- diff --git a/src/timezone/pgtz.c b/src/timezone/pgtz.c index b951830b02..bdd2250667 100644 --- a/src/timezone/pgtz.c +++ b/src/timezone/pgtz.c @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * * IDENTIFICATION - * $PostgreSQL: pgsql/src/timezone/pgtz.c,v 1.59 2008/02/16 21:16:04 tgl Exp $ + * $PostgreSQL: pgsql/src/timezone/pgtz.c,v 1.60 2008/07/01 03:40:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -198,7 +198,7 @@ scan_directory_ci(const char *dirname, const char *fname, int fnamelen, #define T_WEEK ((time_t) (60*60*24*7)) #define T_MONTH ((time_t) (60*60*24*31)) -#define MAX_TEST_TIMES (52*100) /* 100 years, or 1904..2004 */ +#define MAX_TEST_TIMES (52*100) /* 100 years */ struct tztry { @@ -367,6 +367,7 @@ identify_system_timezone(void) time_t t; struct tztry tt; struct tm *tm; + int thisyear; int bestscore; char tmptzdir[MAXPGPATH]; int std_ofs; @@ -379,11 +380,14 @@ identify_system_timezone(void) /* * Set up the list of dates to be probed to see how well our timezone - * matches the system zone. We first probe January and July of 2004; this - * serves to quickly eliminate the vast majority of the TZ database - * entries. If those dates match, we probe every week from 2004 backwards - * to late 1904. (Weekly resolution is good enough to identify DST - * transition rules, since everybody switches on Sundays.) The further + * matches the system zone. We first probe January and July of the + * current year; this serves to quickly eliminate the vast majority of the + * TZ database entries. If those dates match, we probe every week for 100 + * years backwards from the current July. (Weekly resolution is good + * enough to identify DST transition rules, since everybody switches on + * Sundays.) This is sufficient to cover most of the Unix time_t range, + * and we don't want to look further than that since many systems won't + * have sane TZ behavior further back anyway. The further * back the zone matches, the better we score it. This may seem like a * rather random way of doing things, but experience has shown that * system-supplied timezone definitions are likely to have DST behavior @@ -393,9 +397,29 @@ identify_system_timezone(void) * (Note: we probe Thursdays, not Sundays, to avoid triggering * DST-transition bugs in localtime itself.) */ + tnow = time(NULL); + tm = localtime(&tnow); + if (!tm) + return NULL; /* give up if localtime is broken... */ + thisyear = tm->tm_year + 1900; + + t = build_time_t(thisyear, 1, 15); + /* + * Round back to GMT midnight Thursday. This depends on the knowledge + * that the time_t origin is Thu Jan 01 1970. (With a different origin + * we'd be probing some other day of the week, but it wouldn't matter + * anyway unless localtime() had DST-transition bugs.) + */ + t -= (t % T_WEEK); + tt.n_test_times = 0; - tt.test_times[tt.n_test_times++] = build_time_t(2004, 1, 15); - tt.test_times[tt.n_test_times++] = t = build_time_t(2004, 7, 15); + tt.test_times[tt.n_test_times++] = t; + + t = build_time_t(thisyear, 7, 15); + t -= (t % T_WEEK); + + tt.test_times[tt.n_test_times++] = t; + while (tt.n_test_times < MAX_TEST_TIMES) { t -= T_WEEK; @@ -410,7 +434,12 @@ identify_system_timezone(void) &tt, &bestscore, resultbuf); if (bestscore > 0) + { + /* Ignore zic's rather silly "Factory" time zone; use GMT instead */ + if (strcmp(resultbuf, "Factory") == 0) + return NULL; return resultbuf; + } /* * Couldn't find a match in the database, so next we try constructed zone