diff --git a/src/timezone/pgtz.c b/src/timezone/pgtz.c
index 19379d66f1d55b79001a8e90084520fb78161703..c3b8811fda76b6288e16c2b438be67a5c12c9df7 100644
--- a/src/timezone/pgtz.c
+++ b/src/timezone/pgtz.c
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/timezone/pgtz.c,v 1.18 2004/07/10 23:06:50 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/timezone/pgtz.c,v 1.19 2004/07/22 05:28:30 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -32,7 +32,7 @@
 #define T_WEEK  ((time_t) (60*60*24*7))
 #define T_MONTH ((time_t) (60*60*24*31))
 
-#define MAX_TEST_TIMES (52*35)	/* 35 years, or 1970..2004 */
+#define MAX_TEST_TIMES (52*40)	/* 40 years, or 1964..2004 */
 
 struct tztry
 {
@@ -43,8 +43,9 @@ struct tztry
 static char tzdir[MAXPGPATH];
 static int	done_tzdir = 0;
 
-static bool scan_available_timezones(char *tzdir, char *tzdirsub,
-									 struct tztry *tt);
+static void scan_available_timezones(char *tzdir, char *tzdirsub,
+									 struct tztry *tt,
+									 int *bestscore, char *bestzonename);
 
 
 /*
@@ -144,10 +145,18 @@ compare_tm(struct tm *s, struct pg_tm *p)
 }
 
 /*
- * See if a specific timezone setting matches the system behavior
+ * See how well a specific timezone setting matches the system behavior
+ *
+ * We score a timezone setting according to the number of test times it
+ * matches.  (The test times are ordered later-to-earlier, but this routine
+ * doesn't actually know that; it just scans until the first non-match.)
+ *
+ * We return -1 for a completely unusable setting; this is worse than the
+ * score of zero for a setting that works but matches not even the first
+ * test time.
  */
-static bool
-try_timezone(const char *tzname, struct tztry *tt)
+static int
+score_timezone(const char *tzname, struct tztry *tt)
 {
 	int			i;
 	pg_time_t	pgtt;
@@ -156,7 +165,14 @@ try_timezone(const char *tzname, struct tztry *tt)
 	char		cbuf[TZ_STRLEN_MAX + 1];
 
 	if (!pg_tzset(tzname))
-		return false;			/* can't handle the TZ name at all */
+		return -1;				/* can't handle the TZ name at all */
+
+	/* Reject if leap seconds involved */
+	if (!tz_acceptable())
+	{
+		elog(DEBUG4, "Reject TZ \"%s\": uses leap seconds", tzname);
+		return -1;
+	}
 
 	/* Check for match at all the test times */
 	for (i = 0; i < tt->n_test_times; i++)
@@ -164,51 +180,44 @@ try_timezone(const char *tzname, struct tztry *tt)
 		pgtt = (pg_time_t) (tt->test_times[i]);
 		pgtm = pg_localtime(&pgtt);
 		if (!pgtm)
-			return false;		/* probably shouldn't happen */
+			return -1;		/* probably shouldn't happen */
 		systm = localtime(&(tt->test_times[i]));
 		if (!compare_tm(systm, pgtm))
 		{
-			elog(DEBUG4, "Reject TZ \"%s\": at %ld %04d-%02d-%02d %02d:%02d:%02d %s versus %04d-%02d-%02d %02d:%02d:%02d %s",
-				 tzname, (long) pgtt,
+			elog(DEBUG4, "TZ \"%s\" scores %d: at %ld %04d-%02d-%02d %02d:%02d:%02d %s versus %04d-%02d-%02d %02d:%02d:%02d %s",
+				 tzname, i, (long) pgtt,
 				 pgtm->tm_year + 1900, pgtm->tm_mon + 1, pgtm->tm_mday,
 				 pgtm->tm_hour, pgtm->tm_min, pgtm->tm_sec,
 				 pgtm->tm_isdst ? "dst" : "std",
 				 systm->tm_year + 1900, systm->tm_mon + 1, systm->tm_mday,
 				 systm->tm_hour, systm->tm_min, systm->tm_sec,
 				 systm->tm_isdst ? "dst" : "std");
-			return false;
+			return i;
 		}
 		if (systm->tm_isdst >= 0)
 		{
 			/* Check match of zone names, too */
 			if (pgtm->tm_zone == NULL)
-				return false;
+				return -1;		/* probably shouldn't happen */
 			memset(cbuf, 0, sizeof(cbuf));
 			strftime(cbuf, sizeof(cbuf) - 1, "%Z", systm); /* zone abbr */
 			if (strcmp(TZABBREV(cbuf), pgtm->tm_zone) != 0)
 			{
-				elog(DEBUG4, "Reject TZ \"%s\": at %ld \"%s\" versus \"%s\"",
-					 tzname, (long) pgtt,
+				elog(DEBUG4, "TZ \"%s\" scores %d: at %ld \"%s\" versus \"%s\"",
+					 tzname, i, (long) pgtt,
 					 pgtm->tm_zone, cbuf);
-				return false;
+				return i;
 			}
 		}
 	}
 
-	/* Reject if leap seconds involved */
-	if (!tz_acceptable())
-	{
-		elog(DEBUG4, "Reject TZ \"%s\": uses leap seconds", tzname);
-		return false;
-	}
-
-	elog(DEBUG4, "Accept TZ \"%s\"", tzname);
-	return true;
+	elog(DEBUG4, "TZ \"%s\" gets max score %d", tzname, i);
+	return i;
 }
 
 
 /*
- * Try to identify a timezone name (in our terminology) that matches the
+ * Try to identify a timezone name (in our terminology) that best matches the
  * observed behavior of the system timezone library.  We cannot assume that
  * the system TZ environment setting (if indeed there is one) matches our
  * terminology, so we ignore it and just look at what localtime() returns.
@@ -221,6 +230,7 @@ identify_system_timezone(void)
 	time_t		t;
 	struct tztry tt;
 	struct tm  *tm;
+	int			bestscore;
 	char		tmptzdir[MAXPGPATH];
 	int			std_ofs;
 	char		std_zone_name[TZ_STRLEN_MAX + 1],
@@ -231,36 +241,38 @@ identify_system_timezone(void)
 	tzset();
 
 	/*
-	 * Set up the list of dates to be probed to verify that our timezone
-	 * matches the system zone.  We first probe January and July of 1970;
+	 * Set up the list of dates to be probed to see how well our timezone
+	 * matches the system zone.  We first probe January and July of 2004;
 	 * this serves to quickly eliminate the vast majority of the TZ database
-	 * entries.  If those dates match, we probe every week from 1970 to
-	 * late 2004.  This exhaustive test is intended to ensure that we have
-	 * the same DST transition rules as the system timezone.  (Note: we
-	 * probe Thursdays, not Sundays, to avoid triggering DST-transition
-	 * bugs in localtime itself.)
-	 *
-	 * Ideally we'd probe some dates before 1970 too, but that is guaranteed
-	 * to fail if the system TZ library doesn't cope with DST before 1970.
+	 * entries.  If those dates match, we probe every week from 2004 backwards
+	 * to late 1964.  (Weekly resolution is good enough to identify DST
+	 * transition rules, since everybody switches on Sundays.)  The further
+	 * back the zone matches, the better we score it.  This may seem like
+	 * a rather random way of doing things, but experience has shown that
+	 * system-supplied timezone definitions are likely to have DST behavior
+	 * that is right for the recent past and not so accurate further back.
+	 * Scoring in this way allows us to recognize zones that have some
+	 * commonality with the zic database, without insisting on exact match.
+	 * (Note: we probe Thursdays, not Sundays, to avoid triggering
+	 * DST-transition bugs in localtime itself.)
 	 */
 	tt.n_test_times = 0;
-	tt.test_times[tt.n_test_times++] = t = build_time_t(1970, 1, 15);
-	tt.test_times[tt.n_test_times++] = build_time_t(1970, 7, 15);
+	tt.test_times[tt.n_test_times++] = build_time_t(2004, 1, 15);
+	tt.test_times[tt.n_test_times++] = t = build_time_t(2004, 7, 15);
 	while (tt.n_test_times < MAX_TEST_TIMES)
 	{
-		t += T_WEEK;
+		t -= T_WEEK;
 		tt.test_times[tt.n_test_times++] = t;
 	}
 
-	/* Search for a matching timezone file */
+	/* Search for the best-matching timezone file */
 	strcpy(tmptzdir, pg_TZDIR());
-	if (scan_available_timezones(tmptzdir,
-								 tmptzdir + strlen(tmptzdir) + 1,
-								 &tt))
-	{
-		StrNCpy(resultbuf, pg_get_current_timezone(), sizeof(resultbuf));
+	bestscore = 0;
+	scan_available_timezones(tmptzdir, tmptzdir + strlen(tmptzdir) + 1,
+							 &tt,
+							 &bestscore, resultbuf);
+	if (bestscore > 0)
 		return resultbuf;
-	}
 
 	/*
 	 * Couldn't find a match in the database, so next we try constructed zone
@@ -326,19 +338,19 @@ identify_system_timezone(void)
 	{
 		snprintf(resultbuf, sizeof(resultbuf), "%s%d%s",
 				 std_zone_name, -std_ofs / 3600, dst_zone_name);
-		if (try_timezone(resultbuf, &tt))
+		if (score_timezone(resultbuf, &tt) > 0)
 			return resultbuf;
 	}
 
 	/* Try just the STD timezone (works for GMT at least) */
 	strcpy(resultbuf, std_zone_name);
-	if (try_timezone(resultbuf, &tt))
+	if (score_timezone(resultbuf, &tt) > 0)
 		return resultbuf;
 
 	/* Try STD<ofs> */
 	snprintf(resultbuf, sizeof(resultbuf), "%s%d",
 			 std_zone_name, -std_ofs / 3600);
-	if (try_timezone(resultbuf, &tt))
+	if (score_timezone(resultbuf, &tt) > 0)
 		return resultbuf;
 
 	/*
@@ -358,7 +370,7 @@ identify_system_timezone(void)
 }
 
 /*
- * Recursively scan the timezone database looking for a usable match to
+ * Recursively scan the timezone database looking for the best match to
  * the system timezone behavior.
  *
  * tzdir points to a buffer of size MAXPGPATH.  On entry, it holds the
@@ -372,14 +384,15 @@ identify_system_timezone(void)
  *
  * tt tells about the system timezone behavior we need to match.
  *
- * On success, returns TRUE leaving the proper timezone selected.
- * On failure, returns FALSE with a random timezone selected.
+ * *bestscore and *bestzonename on entry hold the best score found so far
+ * and the name of the best zone.  We overwrite them if we find a better
+ * score.  bestzonename must be a buffer of length TZ_STRLEN_MAX + 1.
  */
-static bool
-scan_available_timezones(char *tzdir, char *tzdirsub, struct tztry *tt)
+static void
+scan_available_timezones(char *tzdir, char *tzdirsub, struct tztry *tt,
+						 int *bestscore, char *bestzonename)
 {
 	int			tzdir_orig_len = strlen(tzdir);
-	bool		found = false;
 	DIR		   *dirdesc;
 
 	dirdesc = AllocateDir(tzdir);
@@ -388,7 +401,7 @@ scan_available_timezones(char *tzdir, char *tzdirsub, struct tztry *tt)
 		ereport(LOG,
 				(errcode_for_file_access(),
 				 errmsg("could not open directory \"%s\": %m", tzdir)));
-		return false;
+		return;
 	}
 
 	for (;;)
@@ -432,16 +445,19 @@ scan_available_timezones(char *tzdir, char *tzdirsub, struct tztry *tt)
 		if (S_ISDIR(statbuf.st_mode))
 		{
 			/* Recurse into subdirectory */
-			found = scan_available_timezones(tzdir, tzdirsub, tt);
-			if (found)
-				break;
+			scan_available_timezones(tzdir, tzdirsub, tt,
+									 bestscore, bestzonename);
 		}
 		else
 		{
 			/* Load and test this file */
-			found = try_timezone(tzdirsub, tt);
-			if (found)
-				break;
+			int score = score_timezone(tzdirsub, tt);
+
+			if (score > *bestscore)
+			{
+				*bestscore = score;
+				StrNCpy(bestzonename, tzdirsub, TZ_STRLEN_MAX + 1);
+			}
 		}
 	}
 
@@ -449,8 +465,6 @@ scan_available_timezones(char *tzdir, char *tzdirsub, struct tztry *tt)
 
 	/* Restore tzdir */
 	tzdir[tzdir_orig_len] = '\0';
-
-	return found;
 }