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

Commitdc39937

Browse files
committed
Rewrite identify_system_timezone() to give it better-than-chance odds
of correctly identifying the system's daylight-savings transition rules.This still begs the question of how to look through the zic database tofind a matching zone definition, but at least now we'll have some chanceof recognizing the match when we find it.
1 parent82695df commitdc39937

File tree

1 file changed

+114
-78
lines changed

1 file changed

+114
-78
lines changed

‎src/timezone/pgtz.c

Lines changed: 114 additions & 78 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.13 2004/05/23 23:26:53 tgl Exp $
9+
* $PostgreSQL: pgsql/src/timezone/pgtz.c,v 1.14 2004/05/24 02:30:29 tgl Exp $
1010
*
1111
*-------------------------------------------------------------------------
1212
*/
@@ -44,24 +44,21 @@ pg_TZDIR(void)
4444
* Try to determine the system timezone (as opposed to the timezone
4545
* set in our own library).
4646
*/
47-
#defineT_YEAR(60*60*24*365)
48-
#defineT_MONTH (60*60*24*30)
47+
#defineT_DAY((time_t) (60*60*24))
48+
#defineT_MONTH ((time_t) (60*60*24*31))
4949

5050
structtztry
5151
{
52-
time_tstd_t,
53-
dst_t;
54-
charstd_time[TZ_STRLEN_MAX+1],
55-
dst_time[TZ_STRLEN_MAX+1];
56-
intstd_ofs,
57-
dst_ofs;
58-
structtmstd_tm,
59-
dst_tm;
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];
6057
};
6158

6259

6360
staticbool
64-
compare_tm(structtm*s,structpg_tm*p)
61+
compare_tm(structtm*s,structpg_tm*p)
6562
{
6663
if (s->tm_sec!=p->tm_sec||
6764
s->tm_min!=p->tm_min||
@@ -77,36 +74,31 @@ compare_tm(struct tm * s, struct pg_tm * p)
7774
}
7875

7976
staticbool
80-
try_timezone(char*tzname,structtztry*tt,boolcheckdst)
77+
try_timezone(char*tzname,structtztry*tt)
8178
{
82-
structpg_tm*pgtm;
79+
inti;
80+
structtm*systm;
81+
structpg_tm*pgtm;
8382

8483
if (!pg_tzset(tzname))
85-
return false;/* If this timezone couldn't be picked at
86-
* all */
84+
return false;/* can't handle the TZ name at all */
8785

88-
/* Verify standard time */
89-
pgtm=pg_localtime(&(tt->std_t));
90-
if (!pgtm)
91-
return false;
92-
if (!compare_tm(&(tt->std_tm),pgtm))
93-
return false;
94-
95-
if (!checkdst)
96-
return true;
97-
98-
/* Now check daylight time */
99-
pgtm=pg_localtime(&(tt->dst_t));
100-
if (!pgtm)
101-
return false;
102-
if (!compare_tm(&(tt->dst_tm),pgtm))
103-
return false;
86+
/* Check for match at all the test times */
87+
for (i=0;i<tt->n_test_times;i++)
88+
{
89+
pgtm=pg_localtime(&(tt->test_times[i]));
90+
if (!pgtm)
91+
return false;/* probably shouldn't happen */
92+
systm=localtime(&(tt->test_times[i]));
93+
if (!compare_tm(systm,pgtm))
94+
return false;
95+
}
10496

10597
return true;
10698
}
10799

108100
staticint
109-
get_timezone_offset(structtm*tm)
101+
get_timezone_offset(structtm*tm)
110102
{
111103
#if defined(HAVE_STRUCT_TM_TM_ZONE)
112104
returntm->tm_gmtoff;
@@ -150,88 +142,132 @@ win32_get_timezone_abbrev(char *tz)
150142
* Try to identify a timezone name (in our terminology) that matches the
151143
* observed behavior of the system timezone library. We cannot assume that
152144
* the system TZ environment setting (if indeed there is one) matches our
153-
* terminology, so ignore it and just look at what localtime() returns.
145+
* terminology, soweignore it and just look at what localtime() returns.
154146
*/
155147
staticchar*
156148
identify_system_timezone(void)
157149
{
158-
staticchar__tzbuf[TZ_STRLEN_MAX+1];
159-
boolstd_found= false,
160-
dst_found= false;
161-
time_ttnow=time(NULL);
150+
staticcharresultbuf[TZ_STRLEN_MAX+1];
151+
time_ttnow;
162152
time_tt;
153+
intnowisdst,
154+
curisdst;
155+
intstd_ofs=0;
163156
structtztrytt;
157+
structtm*tm;
164158
charcbuf[TZ_STRLEN_MAX+1];
165159

166160
/* Initialize OS timezone library */
167161
tzset();
168162

163+
/* No info yet */
169164
memset(&tt,0,sizeof(tt));
170165

171-
for (t=tnow;t<tnow+T_YEAR;t+=T_MONTH)
166+
/*
167+
* The idea here is to scan forward from today and try to locate the
168+
* next two daylight-savings transition boundaries. We will test for
169+
* correct results on the day before and after each boundary; this
170+
* gives at least some confidence that we've selected the right DST
171+
* rule set.
172+
*/
173+
tnow=time(NULL);
174+
175+
/*
176+
* Round back to a GMT midnight so results don't depend on local time
177+
* of day
178+
*/
179+
tnow-= (tnow %T_DAY);
180+
181+
/* Always test today, so we have at least one test point */
182+
tt.test_times[tt.n_test_times++]=tnow;
183+
184+
tm=localtime(&tnow);
185+
nowisdst=tm->tm_isdst;
186+
curisdst=nowisdst;
187+
188+
if (curisdst==0)
172189
{
173-
structtm*tm=localtime(&t);
190+
/* Set up STD zone name, in case we are in a non-DST zone */
191+
memset(cbuf,0,sizeof(cbuf));
192+
strftime(cbuf,sizeof(cbuf)-1,"%Z",tm);/* zone abbr */
193+
strcpy(tt.std_zone_name,TZABBREV(cbuf));
194+
/* Also preset std_ofs */
195+
std_ofs=get_timezone_offset(tm);
196+
}
174197

175-
if (tm->tm_isdst==0&& !std_found)
176-
{
177-
/* Standard time */
178-
memcpy(&tt.std_tm,tm,sizeof(structtm));
179-
memset(cbuf,0,sizeof(cbuf));
180-
strftime(cbuf,sizeof(cbuf)-1,"%Z",tm);/* zone abbr */
181-
strcpy(tt.std_time,TZABBREV(cbuf));
182-
tt.std_ofs=get_timezone_offset(tm);
183-
tt.std_t=t;
184-
std_found= true;
185-
}
186-
elseif (tm->tm_isdst==1&& !dst_found)
198+
/*
199+
* We have to look a little further ahead than one year, in case today
200+
* is just past a DST boundary that falls earlier in the year than the
201+
* next similar boundary. Arbitrarily scan up to 14 months.
202+
*/
203+
for (t=tnow+T_DAY;t<tnow+T_MONTH*14;t+=T_DAY)
204+
{
205+
tm=localtime(&t);
206+
if (tm->tm_isdst >=0&&tm->tm_isdst!=curisdst)
187207
{
188-
/* Daylight time */
189-
memcpy(&tt.dst_tm,tm,sizeof(structtm));
208+
/* Found a boundary */
209+
tt.test_times[tt.n_test_times++]=t-T_DAY;
210+
tt.test_times[tt.n_test_times++]=t;
211+
curisdst=tm->tm_isdst;
212+
/* Save STD or DST zone name, also std_ofs */
190213
memset(cbuf,0,sizeof(cbuf));
191214
strftime(cbuf,sizeof(cbuf)-1,"%Z",tm);/* zone abbr */
192-
strcpy(tt.dst_time,TZABBREV(cbuf));
193-
tt.dst_ofs=get_timezone_offset(tm);
194-
tt.dst_t=t;
195-
dst_found= true;
215+
if (curisdst==0)
216+
{
217+
strcpy(tt.std_zone_name,TZABBREV(cbuf));
218+
std_ofs=get_timezone_offset(tm);
219+
}
220+
else
221+
strcpy(tt.dst_zone_name,TZABBREV(cbuf));
222+
/* Have we found two boundaries? */
223+
if (tt.n_test_times >=5)
224+
break;
196225
}
197-
if (std_found&&dst_found)
198-
break;/* Got both standard and daylight */
199226
}
200227

201-
if (!std_found)
228+
/* We should have found a STD zone name by now... */
229+
if (tt.std_zone_name[0]=='\0')
202230
{
203-
/* Failed to determine TZ! */
204231
ereport(LOG,
205232
(errmsg("unable to determine system timezone, defaulting to \"%s\"","GMT"),
206233
errhint("You can specify the correct timezone in postgresql.conf.")));
207234
returnNULL;/* go to GMT */
208235
}
209236

210-
if (dst_found)
237+
/* If we found DST too then try STD<ofs>DST */
238+
if (tt.dst_zone_name[0]!='\0')
211239
{
212-
/* Try STD<ofs>DST */
213-
sprintf(__tzbuf,"%s%d%s",tt.std_time,-tt.std_ofs /3600,tt.dst_time);
214-
if (try_timezone(__tzbuf,&tt,dst_found))
215-
return__tzbuf;
240+
snprintf(resultbuf,sizeof(resultbuf),"%s%d%s",
241+
tt.std_zone_name,-std_ofs /3600,tt.dst_zone_name);
242+
if (try_timezone(resultbuf,&tt))
243+
returnresultbuf;
216244
}
217-
/* Try just the STD timezone */
218-
strcpy(__tzbuf,tt.std_time);
219-
if (try_timezone(__tzbuf,&tt,dst_found))
220-
return__tzbuf;
245+
246+
/* Try just the STD timezone (works for GMT at least) */
247+
strcpy(resultbuf,tt.std_zone_name);
248+
if (try_timezone(resultbuf,&tt))
249+
returnresultbuf;
250+
251+
/* Try STD<ofs> */
252+
snprintf(resultbuf,sizeof(resultbuf),"%s%d",
253+
tt.std_zone_name,-std_ofs /3600);
254+
if (try_timezone(resultbuf,&tt))
255+
returnresultbuf;
221256

222257
/*
223-
* Did not find the timezone. Fallback totry a GMT zone. Note that the
258+
* Did not find the timezone. Fallback touse a GMT zone. Note that the
224259
* zic timezone database names the GMT-offset zones in POSIX style: plus
225260
* is west of Greenwich. It's unfortunate that this is opposite of SQL
226261
* conventions. Should we therefore change the names? Probably not...
227262
*/
228-
sprintf(__tzbuf,"Etc/GMT%s%d",
229-
(-tt.std_ofs>0) ?"+" :"",-tt.std_ofs /3600);
263+
snprintf(resultbuf,sizeof(resultbuf),"Etc/GMT%s%d",
264+
(-std_ofs>0) ?"+" :"",-std_ofs /3600);
265+
230266
ereport(LOG,
231-
(errmsg("could not recognize system timezone, defaulting to \"%s\"",
232-
__tzbuf),
233-
errhint("You can specify the correct timezone in postgresql.conf.")));
234-
return__tzbuf;
267+
(errmsg("could not recognize system timezone, defaulting to \"%s\"",
268+
resultbuf),
269+
errhint("You can specify the correct timezone in postgresql.conf.")));
270+
returnresultbuf;
235271
}
236272

237273
/*

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp