Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commite31c8cf

Browse files
committed
Still another try at automatically detecting the best match in the zic
timezone database for the system behavior we find ourselves in. Scanbackwards from current time and choose the zone that matches furthestback. As per discussion a week or so back.
1 parent6642911 commite31c8cf

File tree

1 file changed

+78
-64
lines changed

1 file changed

+78
-64
lines changed

‎src/timezone/pgtz.c

Lines changed: 78 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
77
*
88
* IDENTIFICATION
9-
* $PostgreSQL: pgsql/src/timezone/pgtz.c,v 1.18 2004/07/10 23:06:50 tgl Exp $
9+
* $PostgreSQL: pgsql/src/timezone/pgtz.c,v 1.19 2004/07/22 05:28:30 tgl Exp $
1010
*
1111
*-------------------------------------------------------------------------
1212
*/
@@ -32,7 +32,7 @@
3232
#defineT_WEEK ((time_t) (60*60*24*7))
3333
#defineT_MONTH ((time_t) (60*60*24*31))
3434

35-
#defineMAX_TEST_TIMES (52*35)/*35 years, or1970..2004 */
35+
#defineMAX_TEST_TIMES (52*40)/*40 years, or1964..2004 */
3636

3737
structtztry
3838
{
@@ -43,8 +43,9 @@ struct tztry
4343
staticchartzdir[MAXPGPATH];
4444
staticintdone_tzdir=0;
4545

46-
staticboolscan_available_timezones(char*tzdir,char*tzdirsub,
47-
structtztry*tt);
46+
staticvoidscan_available_timezones(char*tzdir,char*tzdirsub,
47+
structtztry*tt,
48+
int*bestscore,char*bestzonename);
4849

4950

5051
/*
@@ -144,10 +145,18 @@ compare_tm(struct tm *s, struct pg_tm *p)
144145
}
145146

146147
/*
147-
* See if a specific timezone setting matches the system behavior
148+
* See how well a specific timezone setting matches the system behavior
149+
*
150+
* We score a timezone setting according to the number of test times it
151+
* matches. (The test times are ordered later-to-earlier, but this routine
152+
* doesn't actually know that; it just scans until the first non-match.)
153+
*
154+
* We return -1 for a completely unusable setting; this is worse than the
155+
* score of zero for a setting that works but matches not even the first
156+
* test time.
148157
*/
149-
staticbool
150-
try_timezone(constchar*tzname,structtztry*tt)
158+
staticint
159+
score_timezone(constchar*tzname,structtztry*tt)
151160
{
152161
inti;
153162
pg_time_tpgtt;
@@ -156,59 +165,59 @@ try_timezone(const char *tzname, struct tztry *tt)
156165
charcbuf[TZ_STRLEN_MAX+1];
157166

158167
if (!pg_tzset(tzname))
159-
return false;/* can't handle the TZ name at all */
168+
return-1;/* can't handle the TZ name at all */
169+
170+
/* Reject if leap seconds involved */
171+
if (!tz_acceptable())
172+
{
173+
elog(DEBUG4,"Reject TZ \"%s\": uses leap seconds",tzname);
174+
return-1;
175+
}
160176

161177
/* Check for match at all the test times */
162178
for (i=0;i<tt->n_test_times;i++)
163179
{
164180
pgtt= (pg_time_t) (tt->test_times[i]);
165181
pgtm=pg_localtime(&pgtt);
166182
if (!pgtm)
167-
returnfalse;/* probably shouldn't happen */
183+
return-1;/* probably shouldn't happen */
168184
systm=localtime(&(tt->test_times[i]));
169185
if (!compare_tm(systm,pgtm))
170186
{
171-
elog(DEBUG4,"RejectTZ \"%s\": at %ld %04d-%02d-%02d %02d:%02d:%02d %s versus %04d-%02d-%02d %02d:%02d:%02d %s",
172-
tzname, (long)pgtt,
187+
elog(DEBUG4,"TZ \"%s\" scores %d: at %ld %04d-%02d-%02d %02d:%02d:%02d %s versus %04d-%02d-%02d %02d:%02d:%02d %s",
188+
tzname,i,(long)pgtt,
173189
pgtm->tm_year+1900,pgtm->tm_mon+1,pgtm->tm_mday,
174190
pgtm->tm_hour,pgtm->tm_min,pgtm->tm_sec,
175191
pgtm->tm_isdst ?"dst" :"std",
176192
systm->tm_year+1900,systm->tm_mon+1,systm->tm_mday,
177193
systm->tm_hour,systm->tm_min,systm->tm_sec,
178194
systm->tm_isdst ?"dst" :"std");
179-
returnfalse;
195+
returni;
180196
}
181197
if (systm->tm_isdst >=0)
182198
{
183199
/* Check match of zone names, too */
184200
if (pgtm->tm_zone==NULL)
185-
returnfalse;
201+
return-1;/* probably shouldn't happen */
186202
memset(cbuf,0,sizeof(cbuf));
187203
strftime(cbuf,sizeof(cbuf)-1,"%Z",systm);/* zone abbr */
188204
if (strcmp(TZABBREV(cbuf),pgtm->tm_zone)!=0)
189205
{
190-
elog(DEBUG4,"RejectTZ \"%s\": at %ld \"%s\" versus \"%s\"",
191-
tzname, (long)pgtt,
206+
elog(DEBUG4,"TZ \"%s\" scores %d: at %ld \"%s\" versus \"%s\"",
207+
tzname,i,(long)pgtt,
192208
pgtm->tm_zone,cbuf);
193-
returnfalse;
209+
returni;
194210
}
195211
}
196212
}
197213

198-
/* Reject if leap seconds involved */
199-
if (!tz_acceptable())
200-
{
201-
elog(DEBUG4,"Reject TZ \"%s\": uses leap seconds",tzname);
202-
return false;
203-
}
204-
205-
elog(DEBUG4,"Accept TZ \"%s\"",tzname);
206-
return true;
214+
elog(DEBUG4,"TZ \"%s\" gets max score %d",tzname,i);
215+
returni;
207216
}
208217

209218

210219
/*
211-
* Try to identify a timezone name (in our terminology) that matches the
220+
* Try to identify a timezone name (in our terminology) thatbestmatches the
212221
* observed behavior of the system timezone library. We cannot assume that
213222
* the system TZ environment setting (if indeed there is one) matches our
214223
* terminology, so we ignore it and just look at what localtime() returns.
@@ -221,6 +230,7 @@ identify_system_timezone(void)
221230
time_tt;
222231
structtztrytt;
223232
structtm*tm;
233+
intbestscore;
224234
chartmptzdir[MAXPGPATH];
225235
intstd_ofs;
226236
charstd_zone_name[TZ_STRLEN_MAX+1],
@@ -231,36 +241,38 @@ identify_system_timezone(void)
231241
tzset();
232242

233243
/*
234-
* Set up the list of dates to be probed toverify that our timezone
235-
* matches the system zone. We first probe January and July of1970;
244+
* Set up the list of dates to be probed tosee how well our timezone
245+
* matches the system zone. We first probe January and July of2004;
236246
* this serves to quickly eliminate the vast majority of the TZ database
237-
* entries. If those dates match, we probe every week from 1970 to
238-
* late 2004. This exhaustive test is intended to ensure that we have
239-
* the same DST transition rules as the system timezone. (Note: we
240-
* probe Thursdays, not Sundays, to avoid triggering DST-transition
241-
* bugs in localtime itself.)
242-
*
243-
* Ideally we'd probe some dates before 1970 too, but that is guaranteed
244-
* to fail if the system TZ library doesn't cope with DST before 1970.
247+
* entries. If those dates match, we probe every week from 2004 backwards
248+
* to late 1964. (Weekly resolution is good enough to identify DST
249+
* transition rules, since everybody switches on Sundays.) The further
250+
* back the zone matches, the better we score it. This may seem like
251+
* a rather random way of doing things, but experience has shown that
252+
* system-supplied timezone definitions are likely to have DST behavior
253+
* that is right for the recent past and not so accurate further back.
254+
* Scoring in this way allows us to recognize zones that have some
255+
* commonality with the zic database, without insisting on exact match.
256+
* (Note: we probe Thursdays, not Sundays, to avoid triggering
257+
* DST-transition bugs in localtime itself.)
245258
*/
246259
tt.n_test_times=0;
247-
tt.test_times[tt.n_test_times++]=t=build_time_t(1970,1,15);
248-
tt.test_times[tt.n_test_times++]=build_time_t(1970,7,15);
260+
tt.test_times[tt.n_test_times++]=build_time_t(2004,1,15);
261+
tt.test_times[tt.n_test_times++]=t=build_time_t(2004,7,15);
249262
while (tt.n_test_times<MAX_TEST_TIMES)
250263
{
251-
t+=T_WEEK;
264+
t-=T_WEEK;
252265
tt.test_times[tt.n_test_times++]=t;
253266
}
254267

255-
/* Search foramatching timezone file */
268+
/* Search forthe best-matching timezone file */
256269
strcpy(tmptzdir,pg_TZDIR());
257-
if (scan_available_timezones(tmptzdir,
258-
tmptzdir+strlen(tmptzdir)+1,
259-
&tt))
260-
{
261-
StrNCpy(resultbuf,pg_get_current_timezone(),sizeof(resultbuf));
270+
bestscore=0;
271+
scan_available_timezones(tmptzdir,tmptzdir+strlen(tmptzdir)+1,
272+
&tt,
273+
&bestscore,resultbuf);
274+
if (bestscore>0)
262275
returnresultbuf;
263-
}
264276

265277
/*
266278
* Couldn't find a match in the database, so next we try constructed zone
@@ -326,19 +338,19 @@ identify_system_timezone(void)
326338
{
327339
snprintf(resultbuf,sizeof(resultbuf),"%s%d%s",
328340
std_zone_name,-std_ofs /3600,dst_zone_name);
329-
if (try_timezone(resultbuf,&tt))
341+
if (score_timezone(resultbuf,&tt)>0)
330342
returnresultbuf;
331343
}
332344

333345
/* Try just the STD timezone (works for GMT at least) */
334346
strcpy(resultbuf,std_zone_name);
335-
if (try_timezone(resultbuf,&tt))
347+
if (score_timezone(resultbuf,&tt)>0)
336348
returnresultbuf;
337349

338350
/* Try STD<ofs> */
339351
snprintf(resultbuf,sizeof(resultbuf),"%s%d",
340352
std_zone_name,-std_ofs /3600);
341-
if (try_timezone(resultbuf,&tt))
353+
if (score_timezone(resultbuf,&tt)>0)
342354
returnresultbuf;
343355

344356
/*
@@ -358,7 +370,7 @@ identify_system_timezone(void)
358370
}
359371

360372
/*
361-
* Recursively scan the timezone database looking fora usable match to
373+
* Recursively scan the timezone database looking forthe best match to
362374
* the system timezone behavior.
363375
*
364376
* tzdir points to a buffer of size MAXPGPATH. On entry, it holds the
@@ -372,14 +384,15 @@ identify_system_timezone(void)
372384
*
373385
* tt tells about the system timezone behavior we need to match.
374386
*
375-
* On success, returns TRUE leaving the proper timezone selected.
376-
* On failure, returns FALSE with a random timezone selected.
387+
* *bestscore and *bestzonename on entry hold the best score found so far
388+
* and the name of the best zone. We overwrite them if we find a better
389+
* score. bestzonename must be a buffer of length TZ_STRLEN_MAX + 1.
377390
*/
378-
staticbool
379-
scan_available_timezones(char*tzdir,char*tzdirsub,structtztry*tt)
391+
staticvoid
392+
scan_available_timezones(char*tzdir,char*tzdirsub,structtztry*tt,
393+
int*bestscore,char*bestzonename)
380394
{
381395
inttzdir_orig_len=strlen(tzdir);
382-
boolfound= false;
383396
DIR*dirdesc;
384397

385398
dirdesc=AllocateDir(tzdir);
@@ -388,7 +401,7 @@ scan_available_timezones(char *tzdir, char *tzdirsub, struct tztry *tt)
388401
ereport(LOG,
389402
(errcode_for_file_access(),
390403
errmsg("could not open directory \"%s\": %m",tzdir)));
391-
return false;
404+
return;
392405
}
393406

394407
for (;;)
@@ -432,25 +445,26 @@ scan_available_timezones(char *tzdir, char *tzdirsub, struct tztry *tt)
432445
if (S_ISDIR(statbuf.st_mode))
433446
{
434447
/* Recurse into subdirectory */
435-
found=scan_available_timezones(tzdir,tzdirsub,tt);
436-
if (found)
437-
break;
448+
scan_available_timezones(tzdir,tzdirsub,tt,
449+
bestscore,bestzonename);
438450
}
439451
else
440452
{
441453
/* Load and test this file */
442-
found=try_timezone(tzdirsub,tt);
443-
if (found)
444-
break;
454+
intscore=score_timezone(tzdirsub,tt);
455+
456+
if (score>*bestscore)
457+
{
458+
*bestscore=score;
459+
StrNCpy(bestzonename,tzdirsub,TZ_STRLEN_MAX+1);
460+
}
445461
}
446462
}
447463

448464
FreeDir(dirdesc);
449465

450466
/* Restore tzdir */
451467
tzdir[tzdir_orig_len]='\0';
452-
453-
returnfound;
454468
}
455469

456470

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp