diff --git a/src/bin/initdb/findtimezone.c b/src/bin/initdb/findtimezone.c index 764ead97d3..f39b54cb6c 100644 --- a/src/bin/initdb/findtimezone.c +++ b/src/bin/initdb/findtimezone.c @@ -195,6 +195,7 @@ build_time_t(int year, int month, int day) tm.tm_mday = day; tm.tm_mon = month - 1; tm.tm_year = year - 1900; + tm.tm_isdst = -1; return mktime(&tm); } diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c index 9f3dd81b75..10423dc726 100644 --- a/src/bin/pg_dump/pg_backup_archiver.c +++ b/src/bin/pg_dump/pg_backup_archiver.c @@ -3712,7 +3712,6 @@ ReadHead(ArchiveHandle *AH) vmin, vrev; int fmt; - struct tm crtm; /* * If we haven't already read the header, do so. @@ -3780,6 +3779,8 @@ ReadHead(ArchiveHandle *AH) if (AH->version >= K_VERS_1_4) { + struct tm crtm; + crtm.tm_sec = ReadInt(AH); crtm.tm_min = ReadInt(AH); crtm.tm_hour = ReadInt(AH); @@ -3788,12 +3789,32 @@ ReadHead(ArchiveHandle *AH) crtm.tm_year = ReadInt(AH); crtm.tm_isdst = ReadInt(AH); - AH->archdbname = ReadStr(AH); - + /* + * Newer versions of glibc have mktime() report failure if tm_isdst is + * inconsistent with the prevailing timezone, e.g. tm_isdst = 1 when + * TZ=UTC. This is problematic when restoring an archive under a + * different timezone setting. If we get a failure, try again with + * tm_isdst set to -1 ("don't know"). + * + * XXX with or without this hack, we reconstruct createDate + * incorrectly when the prevailing timezone is different from + * pg_dump's. Next time we bump the archive version, we should flush + * this representation and store a plain seconds-since-the-Epoch + * timestamp instead. + */ AH->createDate = mktime(&crtm); - if (AH->createDate == (time_t) -1) - pg_log_warning("invalid creation date in header"); + { + crtm.tm_isdst = -1; + AH->createDate = mktime(&crtm); + if (AH->createDate == (time_t) -1) + pg_log_warning("invalid creation date in header"); + } + } + + if (AH->version >= K_VERS_1_4) + { + AH->archdbname = ReadStr(AH); } if (AH->version >= K_VERS_1_10)