diff --git a/src/backup.c b/src/backup.c index db7da003..1d7ffd95 100644 --- a/src/backup.c +++ b/src/backup.c @@ -1546,13 +1546,13 @@ pg_stop_backup(pgBackup *backup) */ sent = pgut_send(conn, "SELECT *, txid_snapshot_xmax(txid_current_snapshot())," - " current_timestamp(0)::timestamp" + " current_timestamp(0)::timestamptz" " FROM pg_stop_backup(false)", 0, NULL, WARNING); else sent = pgut_send(conn, "SELECT *, txid_snapshot_xmax(txid_current_snapshot())," - " current_timestamp(0)::timestamp" + " current_timestamp(0)::timestamptz" " FROM pg_stop_backup()", 0, NULL, WARNING); diff --git a/src/catalog.c b/src/catalog.c index 1b5cc383..fa91e89a 100644 --- a/src/catalog.c +++ b/src/catalog.c @@ -381,7 +381,7 @@ pgBackupCreateDir(pgBackup *backup) void pgBackupWriteControl(FILE *out, pgBackup *backup) { - char timestamp[20]; + char timestamp[100]; fprintf(out, "#Configuration\n"); fprintf(out, "backup-mode = %s\n", pgBackupGetBackupMode(backup)); diff --git a/src/delete.c b/src/delete.c index b5eb6395..86bf4f50 100644 --- a/src/delete.c +++ b/src/delete.c @@ -223,7 +223,7 @@ pgBackupDeleteFiles(pgBackup *backup) size_t i; char *backup_id; char path[MAXPGPATH]; - char timestamp[20]; + char timestamp[100]; parray *files; /* @@ -428,4 +428,4 @@ do_delete_instance(void) elog(INFO, "Instance '%s' successfully deleted", instance_name); return 0; -} \ No newline at end of file +} diff --git a/src/restore.c b/src/restore.c index 88e5938e..217e70a1 100644 --- a/src/restore.c +++ b/src/restore.c @@ -720,6 +720,7 @@ create_recovery_conf(time_t backup_id, PROGRAM_VERSION); fprintf(fp, "restore_command = 'pg_probackup archive-get -B %s --instance %s --wal-file-path %%p --wal-file-name %%f'\n", backup_path, instance_name); + fprintf(fp, "recovery_target_action = 'promote'\n"); if (target_time) fprintf(fp, "recovery_target_time = '%s'\n", target_time); @@ -736,7 +737,6 @@ create_recovery_conf(time_t backup_id, * replayed. */ fprintf(fp, "recovery_target = 'immediate'\n"); - fprintf(fp, "recovery_target_action = 'promote'\n"); } if (target_inclusive) diff --git a/src/show.c b/src/show.c index 92c6da3c..aba0ce9d 100644 --- a/src/show.c +++ b/src/show.c @@ -235,7 +235,7 @@ show_backup_list(FILE *out, parray *backup_list) pgBackup *backup = parray_get(backup_list, i); TimeLineID parent_tli; char *backup_id; - char timestamp[20] = "----"; + char timestamp[100] = "----"; char duration[20] = "----"; char data_bytes_str[10] = "----"; diff --git a/src/util.c b/src/util.c index 71a06f64..ad7b1efa 100644 --- a/src/util.c +++ b/src/util.c @@ -144,9 +144,29 @@ get_data_checksum_version(bool safe) void time2iso(char *buf, size_t len, time_t time) { - struct tm *tm = localtime(&time); + struct tm *ptm = gmtime(&time); + time_t gmt = mktime(ptm); + time_t offset; - strftime(buf, len, "%Y-%m-%d %H:%M:%S", tm); + ptm = localtime(&time); + offset = time - gmt + (ptm->tm_isdst ? 3600 : 0); + + strftime(buf, len, "%Y-%m-%d %H:%M:%S", ptm); + + if (offset != 0) + { + buf += strlen(buf); + sprintf(buf, "%c%02d", + (offset >= 0) ? '+' : '-', + abs((int) offset) / SECS_PER_HOUR); + + if (abs((int) offset) % SECS_PER_HOUR != 0) + { + buf += strlen(buf); + sprintf(buf, ":%02d", + abs((int) offset % SECS_PER_HOUR) / SECS_PER_MINUTE); + } + } } /* copied from timestamp.c */ diff --git a/src/utils/logger.h b/src/utils/logger.h index 828a1b61..b9294d98 100644 --- a/src/utils/logger.h +++ b/src/utils/logger.h @@ -2,7 +2,7 @@ * * logger.h: - prototypes of logger functions. * - * Portions Copyright (c) 2017-2017, Postgres Professional + * Copyright (c) 2017-2017, Postgres Professional * *------------------------------------------------------------------------- */ diff --git a/src/utils/pgut.c b/src/utils/pgut.c index e805d922..bc30f6fb 100644 --- a/src/utils/pgut.c +++ b/src/utils/pgut.c @@ -28,6 +28,10 @@ #endif #endif +#define MAX_TZDISP_HOUR 15 /* maximum allowed hour part */ +#define SECS_PER_MINUTE 60 +#define MINS_PER_HOUR 60 + const char *PROGRAM_NAME = NULL; const char *pgut_dbname = NULL; @@ -496,19 +500,91 @@ parse_uint64(const char *value, uint64 *result) * Convert ISO-8601 format string to time_t value. */ bool -parse_time(const char *value, time_t *time) +parse_time(const char *value, time_t *result) { size_t len; + int fields_num, + tz = 0, + i; char *tmp; - int i; struct tm tm; char junk[2]; /* tmp = replace( value, !isalnum, ' ' ) */ tmp = pgut_malloc(strlen(value) + + 1); len = 0; - for (i = 0; value[i]; i++) - tmp[len++] = (IsAlnum(value[i]) ? value[i] : ' '); + fields_num = 1; + + while (*value) + { + if (IsAlnum(*value)) + { + tmp[len++] = *value; + value++; + } + else if (fields_num < 6) + { + fields_num++; + tmp[len++] = ' '; + value++; + } + /* timezone field is 7th */ + else if ((*value == '-' || *value == '+') && fields_num == 6) + { + int hr, + min, + sec = 0; + char *cp; + + errno = 0; + hr = strtol(value + 1, &cp, 10); + if ((value + 1) == cp || errno == ERANGE) + return false; + + /* explicit delimiter? */ + if (*cp == ':') + { + errno = 0; + min = strtol(cp + 1, &cp, 10); + if (errno == ERANGE) + return false; + if (*cp == ':') + { + errno = 0; + sec = strtol(cp + 1, &cp, 10); + if (errno == ERANGE) + return false; + } + } + /* otherwise, might have run things together... */ + else if (*cp == '\0' && strlen(value) > 3) + { + min = hr % 100; + hr = hr / 100; + /* we could, but don't, support a run-together hhmmss format */ + } + else + min = 0; + + /* Range-check the values; see notes in datatype/timestamp.h */ + if (hr < 0 || hr > MAX_TZDISP_HOUR) + return false; + if (min < 0 || min >= MINS_PER_HOUR) + return false; + if (sec < 0 || sec >= SECS_PER_MINUTE) + return false; + + tz = (hr * MINS_PER_HOUR + min) * SECS_PER_MINUTE + sec; + if (*value == '-') + tz = -tz; + + fields_num++; + value = cp; + } + /* wrong format */ + else if (!IsSpace(*value)) + return false; + } tmp[len] = '\0'; /* parse for "YYYY-MM-DD HH:MI:SS" */ @@ -540,7 +616,25 @@ parse_time(const char *value, time_t *time) /* determine whether Daylight Saving Time is in effect */ tm.tm_isdst = -1; - *time = mktime(&tm); + *result = mktime(&tm); + + /* adjust time zone */ + if (tz != 0) + { + time_t ltime = time(NULL); + struct tm *ptm = gmtime(<ime); + time_t gmt = mktime(ptm); + time_t offset; + + /* UTC time */ + *result -= tz; + + /* Get local time */ + ptm = localtime(<ime); + offset = ltime - gmt + (ptm->tm_isdst ? 3600 : 0); + + *result += offset; + } return true; } diff --git a/src/utils/pgut.h b/src/utils/pgut.h index 18acfdae..f5f0440e 100644 --- a/src/utils/pgut.h +++ b/src/utils/pgut.h @@ -195,7 +195,7 @@ extern bool parse_int32(const char *value, int32 *result); extern bool parse_uint32(const char *value, uint32 *result); extern bool parse_int64(const char *value, int64 *result); extern bool parse_uint64(const char *value, uint64 *result); -extern bool parse_time(const char *value, time_t *time); +extern bool parse_time(const char *value, time_t *result); extern bool parse_int(const char *value, int *result, int flags, const char **hintmsg);