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

Commit76c50c0

Browse files
committed
Add code to identify_system_timezone() to try all zones in the zic
database, not just ones that we cons up POSIX names for. This looksgrim but it seems to take less than a second even on a relatively slowmachine, and since it only happens once during postmaster startup, thatseems acceptable.
1 parent17ff181 commit76c50c0

File tree

1 file changed

+216
-55
lines changed

1 file changed

+216
-55
lines changed

‎src/timezone/pgtz.c

Lines changed: 216 additions & 55 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.14 2004/05/24 02:30:29 tgl Exp $
9+
* $PostgreSQL: pgsql/src/timezone/pgtz.c,v 1.15 2004/05/25 18:08:59 tgl Exp $
1010
*
1111
*-------------------------------------------------------------------------
1212
*/
@@ -15,18 +15,39 @@
1515
#include"postgres.h"
1616

1717
#include<ctype.h>
18+
#include<sys/stat.h>
1819

1920
#include"miscadmin.h"
2021
#include"pgtime.h"
2122
#include"pgtz.h"
23+
#include"storage/fd.h"
2224
#include"tzfile.h"
2325
#include"utils/elog.h"
2426
#include"utils/guc.h"
2527

2628

29+
#defineT_DAY((time_t) (60*60*24))
30+
#defineT_MONTH ((time_t) (60*60*24*31))
31+
32+
structtztry
33+
{
34+
charstd_zone_name[TZ_STRLEN_MAX+1],
35+
dst_zone_name[TZ_STRLEN_MAX+1];
36+
#defineMAX_TEST_TIMES 10
37+
intn_test_times;
38+
time_ttest_times[MAX_TEST_TIMES];
39+
};
40+
2741
staticchartzdir[MAXPGPATH];
2842
staticintdone_tzdir=0;
2943

44+
staticboolscan_available_timezones(char*tzdir,char*tzdirsub,
45+
structtztry*tt);
46+
47+
48+
/*
49+
* Return full pathname of timezone data directory
50+
*/
3051
char*
3152
pg_TZDIR(void)
3253
{
@@ -41,22 +62,69 @@ pg_TZDIR(void)
4162
}
4263

4364
/*
44-
* Try to determine the system timezone (as opposed to the timezone
45-
* set in our own library).
65+
* Get GMT offset from a system struct tm
4666
*/
47-
#defineT_DAY((time_t) (60*60*24))
48-
#defineT_MONTH ((time_t) (60*60*24*31))
67+
staticint
68+
get_timezone_offset(structtm*tm)
69+
{
70+
#if defined(HAVE_STRUCT_TM_TM_ZONE)
71+
returntm->tm_gmtoff;
72+
#elif defined(HAVE_INT_TIMEZONE)
73+
#ifdefHAVE_UNDERSCORE_TIMEZONE
74+
return-_timezone;
75+
#else
76+
return-timezone;
77+
#endif
78+
#else
79+
#error No way to determine TZ? Can this happen?
80+
#endif
81+
}
4982

50-
structtztry
83+
/*
84+
* Grotty kluge for win32 ... do we really need this?
85+
*/
86+
#ifdefWIN32
87+
#defineTZABBREV(tz) win32_get_timezone_abbrev(tz)
88+
89+
staticchar*
90+
win32_get_timezone_abbrev(constchar*tz)
5191
{
52-
charstd_zone_name[TZ_STRLEN_MAX+1],
53-
dst_zone_name[TZ_STRLEN_MAX+1];
54-
#defineMAX_TEST_TIMES 5
55-
intn_test_times;
56-
time_ttest_times[MAX_TEST_TIMES];
57-
};
92+
staticcharw32tzabbr[TZ_STRLEN_MAX+1];
93+
intl=0;
94+
constchar*c;
95+
96+
for (c=tz;*c;c++)
97+
{
98+
if (isupper((unsignedchar)*c))
99+
w32tzabbr[l++]=*c;
100+
}
101+
w32tzabbr[l]='\0';
102+
returnw32tzabbr;
103+
}
104+
105+
#else
106+
#defineTZABBREV(tz) (tz)
107+
#endif
108+
109+
/*
110+
* Convenience subroutine to convert y/m/d to time_t
111+
*/
112+
statictime_t
113+
build_time_t(intyear,intmonth,intday)
114+
{
115+
structtmtm;
58116

117+
memset(&tm,0,sizeof(tm));
118+
tm.tm_mday=day;
119+
tm.tm_mon=month-1;
120+
tm.tm_year=year-1900;
121+
122+
returnmktime(&tm);
123+
}
59124

125+
/*
126+
* Does a system tm value match one we computed ourselves?
127+
*/
60128
staticbool
61129
compare_tm(structtm*s,structpg_tm*p)
62130
{
@@ -73,12 +141,16 @@ compare_tm(struct tm *s, struct pg_tm *p)
73141
return true;
74142
}
75143

144+
/*
145+
* See if a specific timezone setting matches the system behavior
146+
*/
76147
staticbool
77-
try_timezone(char*tzname,structtztry*tt)
148+
try_timezone(constchar*tzname,structtztry*tt)
78149
{
79150
inti;
80151
structtm*systm;
81152
structpg_tm*pgtm;
153+
charcbuf[TZ_STRLEN_MAX+1];
82154

83155
if (!pg_tzset(tzname))
84156
return false;/* can't handle the TZ name at all */
@@ -92,51 +164,25 @@ try_timezone(char *tzname, struct tztry *tt)
92164
systm=localtime(&(tt->test_times[i]));
93165
if (!compare_tm(systm,pgtm))
94166
return false;
167+
if (systm->tm_isdst >=0)
168+
{
169+
/* Check match of zone names, too */
170+
if (pgtm->tm_zone==NULL)
171+
return false;
172+
memset(cbuf,0,sizeof(cbuf));
173+
strftime(cbuf,sizeof(cbuf)-1,"%Z",systm);/* zone abbr */
174+
if (strcmp(TZABBREV(cbuf),pgtm->tm_zone)!=0)
175+
return false;
176+
}
95177
}
96178

97-
return true;
98-
}
99-
100-
staticint
101-
get_timezone_offset(structtm*tm)
102-
{
103-
#if defined(HAVE_STRUCT_TM_TM_ZONE)
104-
returntm->tm_gmtoff;
105-
#elif defined(HAVE_INT_TIMEZONE)
106-
#ifdefHAVE_UNDERSCORE_TIMEZONE
107-
return-_timezone;
108-
#else
109-
return-timezone;
110-
#endif
111-
#else
112-
#error No way to determine TZ? Can this happen?
113-
#endif
114-
}
115-
116-
117-
#ifdefWIN32
118-
#defineTZABBREV(tz) win32_get_timezone_abbrev(tz)
119-
120-
staticchar*
121-
win32_get_timezone_abbrev(char*tz)
122-
{
123-
staticcharw32tzabbr[TZ_STRLEN_MAX+1];
124-
intl=0;
125-
char*c;
179+
/* Reject if leap seconds involved */
180+
if (!tz_acceptable())
181+
return false;
126182

127-
for (c=tz;*c;c++)
128-
{
129-
if (isupper(*c))
130-
w32tzabbr[l++]=*c;
131-
}
132-
w32tzabbr[l]='\0';
133-
returnw32tzabbr;
183+
return true;
134184
}
135185

136-
#else
137-
#defineTZABBREV(tz) tz
138-
#endif
139-
140186

141187
/*
142188
* Try to identify a timezone name (in our terminology) that matches the
@@ -155,6 +201,7 @@ identify_system_timezone(void)
155201
intstd_ofs=0;
156202
structtztrytt;
157203
structtm*tm;
204+
chartmptzdir[MAXPGPATH];
158205
charcbuf[TZ_STRLEN_MAX+1];
159206

160207
/* Initialize OS timezone library */
@@ -225,6 +272,20 @@ identify_system_timezone(void)
225272
}
226273
}
227274

275+
/*
276+
* Add a couple of historical dates as well; without this we are likely
277+
* to choose an accidental match, such as Antartica/Palmer when we
278+
* really want America/Santiago. Ideally we'd probe some dates before
279+
* 1970 too, but that is guaranteed to fail if the system TZ library
280+
* doesn't cope with DST before 1970.
281+
*/
282+
tt.test_times[tt.n_test_times++]=build_time_t(1970,1,15);
283+
tt.test_times[tt.n_test_times++]=build_time_t(1970,7,15);
284+
tt.test_times[tt.n_test_times++]=build_time_t(1990,4,1);
285+
tt.test_times[tt.n_test_times++]=build_time_t(1990,10,1);
286+
287+
Assert(tt.n_test_times <=MAX_TEST_TIMES);
288+
228289
/* We should have found a STD zone name by now... */
229290
if (tt.std_zone_name[0]=='\0')
230291
{
@@ -234,7 +295,17 @@ identify_system_timezone(void)
234295
returnNULL;/* go to GMT */
235296
}
236297

237-
/* If we found DST too then try STD<ofs>DST */
298+
/* Search for a matching timezone file */
299+
strcpy(tmptzdir,pg_TZDIR());
300+
if (scan_available_timezones(tmptzdir,
301+
tmptzdir+strlen(tmptzdir)+1,
302+
&tt))
303+
{
304+
StrNCpy(resultbuf,pg_get_current_timezone(),sizeof(resultbuf));
305+
returnresultbuf;
306+
}
307+
308+
/* If we found DST then try STD<ofs>DST */
238309
if (tt.dst_zone_name[0]!='\0')
239310
{
240311
snprintf(resultbuf,sizeof(resultbuf),"%s%d%s",
@@ -270,6 +341,96 @@ identify_system_timezone(void)
270341
returnresultbuf;
271342
}
272343

344+
/*
345+
* Recursively scan the timezone database looking for a usable match to
346+
* the system timezone behavior.
347+
*
348+
* tzdir points to a buffer of size MAXPGPATH. On entry, it holds the
349+
* pathname of a directory containing TZ files. We internally modify it
350+
* to hold pathnames of sub-directories and files, but must restore it
351+
* to its original contents before exit.
352+
*
353+
* tzdirsub points to the part of tzdir that represents the subfile name
354+
* (ie, tzdir + the original directory name length, plus one for the
355+
* first added '/').
356+
*
357+
* tt tells about the system timezone behavior we need to match.
358+
*
359+
* On success, returns TRUE leaving the proper timezone selected.
360+
* On failure, returns FALSE with a random timezone selected.
361+
*/
362+
staticbool
363+
scan_available_timezones(char*tzdir,char*tzdirsub,structtztry*tt)
364+
{
365+
inttzdir_orig_len=strlen(tzdir);
366+
boolfound= false;
367+
DIR*dirdesc;
368+
369+
dirdesc=AllocateDir(tzdir);
370+
if (!dirdesc)
371+
{
372+
ereport(LOG,
373+
(errcode_for_file_access(),
374+
errmsg("could not open directory \"%s\": %m",tzdir)));
375+
return false;
376+
}
377+
378+
for (;;)
379+
{
380+
structdirent*direntry;
381+
structstatstatbuf;
382+
383+
errno=0;
384+
direntry=readdir(dirdesc);
385+
if (!direntry)
386+
{
387+
if (errno)
388+
ereport(LOG,
389+
(errcode_for_file_access(),
390+
errmsg("error reading directory: %m")));
391+
break;
392+
}
393+
394+
/* Ignore . and .., plus any other "hidden" files */
395+
if (direntry->d_name[0]=='.')
396+
continue;
397+
398+
snprintf(tzdir+tzdir_orig_len,MAXPGPATH-tzdir_orig_len,
399+
"/%s",direntry->d_name);
400+
401+
if (stat(tzdir,&statbuf)!=0)
402+
{
403+
ereport(LOG,
404+
(errcode_for_file_access(),
405+
errmsg("could not stat \"%s\": %m",tzdir)));
406+
continue;
407+
}
408+
409+
if (S_ISDIR(statbuf.st_mode))
410+
{
411+
/* Recurse into subdirectory */
412+
found=scan_available_timezones(tzdir,tzdirsub,tt);
413+
if (found)
414+
break;
415+
}
416+
else
417+
{
418+
/* Load and test this file */
419+
found=try_timezone(tzdirsub,tt);
420+
if (found)
421+
break;
422+
}
423+
}
424+
425+
FreeDir(dirdesc);
426+
427+
/* Restore tzdir */
428+
tzdir[tzdir_orig_len]='\0';
429+
430+
returnfound;
431+
}
432+
433+
273434
/*
274435
* Check whether timezone is acceptable.
275436
*
@@ -351,6 +512,6 @@ pg_timezone_initialize(void)
351512
/* Select setting */
352513
def_tz=select_default_timezone();
353514
/* Tell GUC about the value. Will redundantly call pg_tzset() */
354-
SetConfigOption("timezone",def_tz,PGC_POSTMASTER,PGC_S_ENV_VAR);
515+
SetConfigOption("timezone",def_tz,PGC_POSTMASTER,PGC_S_ARGV);
355516
}
356517
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp