diff --git a/src/timezone/README b/src/timezone/README
index 2e41d7ac9779434520f90355f6d3df19b00793d4..c33c26143f244a9c4d08e24dbd9d287371e93790 100644
--- a/src/timezone/README
+++ b/src/timezone/README
@@ -84,8 +84,10 @@ other exposed names.
 slightly modified the API of the former, in part because it now relies
 on our own pg_open_tzfile() rather than opening files for itself.
 
-* tzparse() is adjusted to cache the result of loading the TZDEFRULES
-zone, so that that's not repeated more than once per process.
+* tzparse() is adjusted to avoid loading the TZDEFRULES zone unless
+really necessary, and to ignore any leap-second data it may supply.
+We also cache the result of loading the TZDEFRULES zone, so that
+that's not repeated more than once per process.
 
 * There's a fair amount of code we don't need and have removed,
 including all the nonstandard optional APIs.  We have also added
diff --git a/src/timezone/localtime.c b/src/timezone/localtime.c
index a2260e590ddd9075b8428faeba191f39b1af37ca..e3029d841d7b1727aabb2b2f67af3d4902395748 100644
--- a/src/timezone/localtime.c
+++ b/src/timezone/localtime.c
@@ -54,7 +54,7 @@ static const char gmt[] = "GMT";
  * PG: We cache the result of trying to load the TZDEFRULES zone here.
  * tzdefrules_loaded is 0 if not tried yet, +1 if good, -1 if failed.
  */
-static struct state tzdefrules_s;
+static struct state *tzdefrules_s = NULL;
 static int	tzdefrules_loaded = 0;
 
 /*
@@ -908,20 +908,10 @@ tzparse(const char *name, struct state *sp, bool lastditch)
 	stdname = name;
 	if (lastditch)
 	{
-		/*
-		 * This is intentionally somewhat different from the IANA code.  We do
-		 * not want to invoke tzload() in the lastditch case: we can't assume
-		 * pg_open_tzfile() is sane yet, and we don't care about leap seconds
-		 * anyway.
-		 */
+		/* Unlike IANA, don't assume name is exactly "GMT" */
 		stdlen = strlen(name);	/* length of standard zone name */
 		name += stdlen;
-		if (stdlen >= sizeof sp->chars)
-			stdlen = (sizeof sp->chars) - 1;
-		charcnt = stdlen + 1;
 		stdoffset = 0;
-		sp->goback = sp->goahead = false;	/* simulate failed tzload() */
-		load_ok = false;
 	}
 	else
 	{
@@ -945,27 +935,23 @@ tzparse(const char *name, struct state *sp, bool lastditch)
 		name = getoffset(name, &stdoffset);
 		if (name == NULL)
 			return false;
-		charcnt = stdlen + 1;
-		if (sizeof sp->chars < charcnt)
-			return false;
-
-		/*
-		 * This bit also differs from the IANA code, which doesn't make any
-		 * attempt to avoid repetitive loadings of the TZDEFRULES zone.
-		 */
-		if (tzdefrules_loaded == 0)
-		{
-			if (tzload(TZDEFRULES, NULL, &tzdefrules_s, false) == 0)
-				tzdefrules_loaded = 1;
-			else
-				tzdefrules_loaded = -1;
-		}
-		load_ok = (tzdefrules_loaded > 0);
-		if (load_ok)
-			memcpy(sp, &tzdefrules_s, sizeof(struct state));
 	}
-	if (!load_ok)
-		sp->leapcnt = 0;		/* so, we're off a little */
+	charcnt = stdlen + 1;
+	if (sizeof sp->chars < charcnt)
+		return false;
+
+	/*
+	 * The IANA code always tries tzload(TZDEFRULES) here.  We do not want to
+	 * do that; it would be bad news in the lastditch case, where we can't
+	 * assume pg_open_tzfile() is sane yet.  Moreover, the only reason to do
+	 * it unconditionally is to absorb the TZDEFRULES zone's leap second info,
+	 * which we don't want to do anyway.  Without that, we only need to load
+	 * TZDEFRULES if the zone name specifies DST but doesn't incorporate a
+	 * POSIX-style transition date rule, which is not a common case.
+	 */
+	sp->goback = sp->goahead = false;	/* simulate failed tzload() */
+	sp->leapcnt = 0;			/* intentionally assume no leap seconds */
+
 	if (*name != '\0')
 	{
 		if (*name == '<')
@@ -996,8 +982,38 @@ tzparse(const char *name, struct state *sp, bool lastditch)
 		}
 		else
 			dstoffset = stdoffset - SECSPERHOUR;
-		if (*name == '\0' && !load_ok)
-			name = TZDEFRULESTRING;
+		if (*name == '\0')
+		{
+			/*
+			 * The POSIX zone name does not provide a transition-date rule.
+			 * Here we must load the TZDEFRULES zone, if possible, to serve as
+			 * source data for the transition dates.  Unlike the IANA code, we
+			 * try to cache the data so it's only loaded once.
+			 */
+			if (tzdefrules_loaded == 0)
+			{
+				/* Allocate on first use */
+				if (tzdefrules_s == NULL)
+					tzdefrules_s = (struct state *) malloc(sizeof(struct state));
+				if (tzdefrules_s != NULL)
+				{
+					if (tzload(TZDEFRULES, NULL, tzdefrules_s, false) == 0)
+						tzdefrules_loaded = 1;
+					else
+						tzdefrules_loaded = -1;
+					/* In any case, we ignore leap-second data from the file */
+					tzdefrules_s->leapcnt = 0;
+				}
+			}
+			load_ok = (tzdefrules_loaded > 0);
+			if (load_ok)
+				memcpy(sp, tzdefrules_s, sizeof(struct state));
+			else
+			{
+				/* If we can't load TZDEFRULES, fall back to hard-wired rule */
+				name = TZDEFRULESTRING;
+			}
+		}
 		if (*name == ',' || *name == ';')
 		{
 			struct rule start;