Skip to content

Commit 8c3340f

Browse files
committed
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.
1 parent 5b965bf commit 8c3340f

File tree

1 file changed

+38
-9
lines changed

1 file changed

+38
-9
lines changed

src/timezone/pgtz.c

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
77
*
88
* IDENTIFICATION
9-
* $PostgreSQL: pgsql/src/timezone/pgtz.c,v 1.59 2008/02/16 21:16:04 tgl Exp $
9+
* $PostgreSQL: pgsql/src/timezone/pgtz.c,v 1.60 2008/07/01 03:40:55 tgl Exp $
1010
*
1111
*-------------------------------------------------------------------------
1212
*/
@@ -198,7 +198,7 @@ scan_directory_ci(const char *dirname, const char *fname, int fnamelen,
198198
#define T_WEEK ((time_t) (60*60*24*7))
199199
#define T_MONTH ((time_t) (60*60*24*31))
200200

201-
#define MAX_TEST_TIMES (52*100) /* 100 years, or 1904..2004 */
201+
#define MAX_TEST_TIMES (52*100) /* 100 years */
202202

203203
struct tztry
204204
{
@@ -367,6 +367,7 @@ identify_system_timezone(void)
367367
time_t t;
368368
struct tztry tt;
369369
struct tm *tm;
370+
int thisyear;
370371
int bestscore;
371372
char tmptzdir[MAXPGPATH];
372373
int std_ofs;
@@ -379,11 +380,14 @@ identify_system_timezone(void)
379380

380381
/*
381382
* Set up the list of dates to be probed to see how well our timezone
382-
* matches the system zone. We first probe January and July of 2004; this
383-
* serves to quickly eliminate the vast majority of the TZ database
384-
* entries. If those dates match, we probe every week from 2004 backwards
385-
* to late 1904. (Weekly resolution is good enough to identify DST
386-
* transition rules, since everybody switches on Sundays.) The further
383+
* matches the system zone. We first probe January and July of the
384+
* current year; this serves to quickly eliminate the vast majority of the
385+
* TZ database entries. If those dates match, we probe every week for 100
386+
* years backwards from the current July. (Weekly resolution is good
387+
* enough to identify DST transition rules, since everybody switches on
388+
* Sundays.) This is sufficient to cover most of the Unix time_t range,
389+
* and we don't want to look further than that since many systems won't
390+
* have sane TZ behavior further back anyway. The further
387391
* back the zone matches, the better we score it. This may seem like a
388392
* rather random way of doing things, but experience has shown that
389393
* system-supplied timezone definitions are likely to have DST behavior
@@ -393,9 +397,29 @@ identify_system_timezone(void)
393397
* (Note: we probe Thursdays, not Sundays, to avoid triggering
394398
* DST-transition bugs in localtime itself.)
395399
*/
400+
tnow = time(NULL);
401+
tm = localtime(&tnow);
402+
if (!tm)
403+
return NULL; /* give up if localtime is broken... */
404+
thisyear = tm->tm_year + 1900;
405+
406+
t = build_time_t(thisyear, 1, 15);
407+
/*
408+
* Round back to GMT midnight Thursday. This depends on the knowledge
409+
* that the time_t origin is Thu Jan 01 1970. (With a different origin
410+
* we'd be probing some other day of the week, but it wouldn't matter
411+
* anyway unless localtime() had DST-transition bugs.)
412+
*/
413+
t -= (t % T_WEEK);
414+
396415
tt.n_test_times = 0;
397-
tt.test_times[tt.n_test_times++] = build_time_t(2004, 1, 15);
398-
tt.test_times[tt.n_test_times++] = t = build_time_t(2004, 7, 15);
416+
tt.test_times[tt.n_test_times++] = t;
417+
418+
t = build_time_t(thisyear, 7, 15);
419+
t -= (t % T_WEEK);
420+
421+
tt.test_times[tt.n_test_times++] = t;
422+
399423
while (tt.n_test_times < MAX_TEST_TIMES)
400424
{
401425
t -= T_WEEK;
@@ -410,7 +434,12 @@ identify_system_timezone(void)
410434
&tt,
411435
&bestscore, resultbuf);
412436
if (bestscore > 0)
437+
{
438+
/* Ignore zic's rather silly "Factory" time zone; use GMT instead */
439+
if (strcmp(resultbuf, "Factory") == 0)
440+
return NULL;
413441
return resultbuf;
442+
}
414443

415444
/*
416445
* Couldn't find a match in the database, so next we try constructed zone

0 commit comments

Comments
 (0)