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

Commit99b225c

Browse files
committed
Check more test points (in fact, every week in 1970..2004) to get a more
accurate matching of our time zone to the system's zone. This method isable to distinguish Antarctica/Casey from Australia/Perth, as in ChrisK-L's recent example; and it is not materially slower than before, becausethe extra checks generally don't get done against very many time zones.It seems possible that with this test we'd be able to correctly identifyWindows timezones without looking at the timezone name, but I do nothave the ability to try it.
1 parentb9f698e commit99b225c

File tree

1 file changed

+70
-77
lines changed

1 file changed

+70
-77
lines changed

‎src/timezone/pgtz.c

Lines changed: 70 additions & 77 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.17 2004/06/03 02:08:07 tgl Exp $
9+
* $PostgreSQL: pgsql/src/timezone/pgtz.c,v 1.18 2004/07/10 23:06:50 tgl Exp $
1010
*
1111
*-------------------------------------------------------------------------
1212
*/
@@ -29,13 +29,13 @@
2929

3030

3131
#defineT_DAY((time_t) (60*60*24))
32+
#defineT_WEEK ((time_t) (60*60*24*7))
3233
#defineT_MONTH ((time_t) (60*60*24*31))
3334

35+
#defineMAX_TEST_TIMES (52*35)/* 35 years, or 1970..2004 */
36+
3437
structtztry
3538
{
36-
charstd_zone_name[TZ_STRLEN_MAX+1],
37-
dst_zone_name[TZ_STRLEN_MAX+1];
38-
#defineMAX_TEST_TIMES 10
3939
intn_test_times;
4040
time_ttest_times[MAX_TEST_TIMES];
4141
};
@@ -219,27 +219,61 @@ identify_system_timezone(void)
219219
staticcharresultbuf[TZ_STRLEN_MAX+1];
220220
time_ttnow;
221221
time_tt;
222-
intnowisdst,
223-
curisdst;
224-
intstd_ofs=0;
225222
structtztrytt;
226223
structtm*tm;
227224
chartmptzdir[MAXPGPATH];
225+
intstd_ofs;
226+
charstd_zone_name[TZ_STRLEN_MAX+1],
227+
dst_zone_name[TZ_STRLEN_MAX+1];
228228
charcbuf[TZ_STRLEN_MAX+1];
229229

230230
/* Initialize OS timezone library */
231231
tzset();
232232

233-
/* No info yet */
234-
memset(&tt,0,sizeof(tt));
233+
/*
234+
* Set up the list of dates to be probed to verify that our timezone
235+
* matches the system zone. We first probe January and July of 1970;
236+
* 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.
245+
*/
246+
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);
249+
while (tt.n_test_times<MAX_TEST_TIMES)
250+
{
251+
t+=T_WEEK;
252+
tt.test_times[tt.n_test_times++]=t;
253+
}
254+
255+
/* Search for a matching timezone file */
256+
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));
262+
returnresultbuf;
263+
}
235264

236265
/*
237-
* The idea here is to scan forward from today and try to locate the
238-
* next two daylight-savings transition boundaries. We will test for
239-
* correct results on the day before and after each boundary; this
240-
* gives at least some confidence that we've selected the right DST
241-
* rule set.
266+
* Couldn't find a match in the database, so next we try constructed zone
267+
* names (like "PST8PDT").
268+
*
269+
* First we need to determine the names of the local standard and daylight
270+
* zones. The idea here is to scan forward from today until we have
271+
* seen both zones, if both are in use.
242272
*/
273+
memset(std_zone_name,0,sizeof(std_zone_name));
274+
memset(dst_zone_name,0,sizeof(dst_zone_name));
275+
std_ofs=0;
276+
243277
tnow=time(NULL);
244278

245279
/*
@@ -248,103 +282,62 @@ identify_system_timezone(void)
248282
*/
249283
tnow-= (tnow %T_DAY);
250284

251-
/* Always test today, so we have at least one test point */
252-
tt.test_times[tt.n_test_times++]=tnow;
253-
254-
tm=localtime(&tnow);
255-
nowisdst=tm->tm_isdst;
256-
curisdst=nowisdst;
257-
258-
if (curisdst==0)
259-
{
260-
/* Set up STD zone name, in case we are in a non-DST zone */
261-
memset(cbuf,0,sizeof(cbuf));
262-
strftime(cbuf,sizeof(cbuf)-1,"%Z",tm);/* zone abbr */
263-
strcpy(tt.std_zone_name,TZABBREV(cbuf));
264-
/* Also preset std_ofs */
265-
std_ofs=get_timezone_offset(tm);
266-
}
267-
268285
/*
269286
* We have to look a little further ahead than one year, in case today
270287
* is just past a DST boundary that falls earlier in the year than the
271288
* next similar boundary. Arbitrarily scan up to 14 months.
272289
*/
273-
for (t=tnow+T_DAY;t<tnow+T_MONTH*14;t+=T_DAY)
290+
for (t=tnow;t <=tnow+T_MONTH*14;t+=T_MONTH)
274291
{
275292
tm=localtime(&t);
276-
if (tm->tm_isdst >=0&&tm->tm_isdst!=curisdst)
293+
if (tm->tm_isdst<0)
294+
continue;
295+
if (tm->tm_isdst==0&&std_zone_name[0]=='\0')
277296
{
278-
/* Found a boundary */
279-
tt.test_times[tt.n_test_times++]=t-T_DAY;
280-
tt.test_times[tt.n_test_times++]=t;
281-
curisdst=tm->tm_isdst;
282-
/* Save STD or DST zone name, also std_ofs */
297+
/* found STD zone */
283298
memset(cbuf,0,sizeof(cbuf));
284299
strftime(cbuf,sizeof(cbuf)-1,"%Z",tm);/* zone abbr */
285-
if (curisdst==0)
286-
{
287-
strcpy(tt.std_zone_name,TZABBREV(cbuf));
288-
std_ofs=get_timezone_offset(tm);
289-
}
290-
else
291-
strcpy(tt.dst_zone_name,TZABBREV(cbuf));
292-
/* Have we found two boundaries? */
293-
if (tt.n_test_times >=5)
294-
break;
300+
strcpy(std_zone_name,TZABBREV(cbuf));
301+
std_ofs=get_timezone_offset(tm);
295302
}
303+
if (tm->tm_isdst>0&&dst_zone_name[0]=='\0')
304+
{
305+
/* found DST zone */
306+
memset(cbuf,0,sizeof(cbuf));
307+
strftime(cbuf,sizeof(cbuf)-1,"%Z",tm);/* zone abbr */
308+
strcpy(dst_zone_name,TZABBREV(cbuf));
309+
}
310+
/* Done if found both */
311+
if (std_zone_name[0]&&dst_zone_name[0])
312+
break;
296313
}
297314

298-
/*
299-
* Add a couple of historical dates as well; without this we are likely
300-
* to choose an accidental match, such as Antartica/Palmer when we
301-
* really want America/Santiago. Ideally we'd probe some dates before
302-
* 1970 too, but that is guaranteed to fail if the system TZ library
303-
* doesn't cope with DST before 1970.
304-
*/
305-
tt.test_times[tt.n_test_times++]=build_time_t(1970,1,15);
306-
tt.test_times[tt.n_test_times++]=build_time_t(1970,7,15);
307-
tt.test_times[tt.n_test_times++]=build_time_t(1990,4,1);
308-
tt.test_times[tt.n_test_times++]=build_time_t(1990,10,1);
309-
310-
Assert(tt.n_test_times <=MAX_TEST_TIMES);
311-
312315
/* We should have found a STD zone name by now... */
313-
if (tt.std_zone_name[0]=='\0')
316+
if (std_zone_name[0]=='\0')
314317
{
315318
ereport(LOG,
316319
(errmsg("unable to determine system timezone, defaulting to \"%s\"","GMT"),
317320
errhint("You can specify the correct timezone in postgresql.conf.")));
318321
returnNULL;/* go to GMT */
319322
}
320323

321-
/* Search for a matching timezone file */
322-
strcpy(tmptzdir,pg_TZDIR());
323-
if (scan_available_timezones(tmptzdir,
324-
tmptzdir+strlen(tmptzdir)+1,
325-
&tt))
326-
{
327-
StrNCpy(resultbuf,pg_get_current_timezone(),sizeof(resultbuf));
328-
returnresultbuf;
329-
}
330-
331324
/* If we found DST then try STD<ofs>DST */
332-
if (tt.dst_zone_name[0]!='\0')
325+
if (dst_zone_name[0]!='\0')
333326
{
334327
snprintf(resultbuf,sizeof(resultbuf),"%s%d%s",
335-
tt.std_zone_name,-std_ofs /3600,tt.dst_zone_name);
328+
std_zone_name,-std_ofs /3600,dst_zone_name);
336329
if (try_timezone(resultbuf,&tt))
337330
returnresultbuf;
338331
}
339332

340333
/* Try just the STD timezone (works for GMT at least) */
341-
strcpy(resultbuf,tt.std_zone_name);
334+
strcpy(resultbuf,std_zone_name);
342335
if (try_timezone(resultbuf,&tt))
343336
returnresultbuf;
344337

345338
/* Try STD<ofs> */
346339
snprintf(resultbuf,sizeof(resultbuf),"%s%d",
347-
tt.std_zone_name,-std_ofs /3600);
340+
std_zone_name,-std_ofs /3600);
348341
if (try_timezone(resultbuf,&tt))
349342
returnresultbuf;
350343

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp