Skip to content

Commit be71f4a

Browse files
committed
PGPRO-1026: Store timestamps with timezone, parse timezone from timestamp
from config and command line parameters
1 parent 9813471 commit be71f4a

File tree

9 files changed

+130
-16
lines changed

9 files changed

+130
-16
lines changed

src/backup.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1546,13 +1546,13 @@ pg_stop_backup(pgBackup *backup)
15461546
*/
15471547
sent = pgut_send(conn,
15481548
"SELECT *, txid_snapshot_xmax(txid_current_snapshot()),"
1549-
" current_timestamp(0)::timestamp"
1549+
" current_timestamp(0)::timestamptz"
15501550
" FROM pg_stop_backup(false)",
15511551
0, NULL, WARNING);
15521552
else
15531553
sent = pgut_send(conn,
15541554
"SELECT *, txid_snapshot_xmax(txid_current_snapshot()),"
1555-
" current_timestamp(0)::timestamp"
1555+
" current_timestamp(0)::timestamptz"
15561556
" FROM pg_stop_backup()",
15571557
0, NULL, WARNING);
15581558

src/catalog.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ pgBackupCreateDir(pgBackup *backup)
381381
void
382382
pgBackupWriteControl(FILE *out, pgBackup *backup)
383383
{
384-
char timestamp[20];
384+
char timestamp[100];
385385

386386
fprintf(out, "#Configuration\n");
387387
fprintf(out, "backup-mode = %s\n", pgBackupGetBackupMode(backup));

src/delete.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ pgBackupDeleteFiles(pgBackup *backup)
223223
size_t i;
224224
char *backup_id;
225225
char path[MAXPGPATH];
226-
char timestamp[20];
226+
char timestamp[100];
227227
parray *files;
228228

229229
/*
@@ -428,4 +428,4 @@ do_delete_instance(void)
428428

429429
elog(INFO, "Instance '%s' successfully deleted", instance_name);
430430
return 0;
431-
}
431+
}

src/restore.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,7 @@ create_recovery_conf(time_t backup_id,
720720
PROGRAM_VERSION);
721721
fprintf(fp, "restore_command = 'pg_probackup archive-get -B %s --instance %s --wal-file-path %%p --wal-file-name %%f'\n",
722722
backup_path, instance_name);
723+
fprintf(fp, "recovery_target_action = 'promote'\n");
723724

724725
if (target_time)
725726
fprintf(fp, "recovery_target_time = '%s'\n", target_time);
@@ -736,7 +737,6 @@ create_recovery_conf(time_t backup_id,
736737
* replayed.
737738
*/
738739
fprintf(fp, "recovery_target = 'immediate'\n");
739-
fprintf(fp, "recovery_target_action = 'promote'\n");
740740
}
741741

742742
if (target_inclusive)

src/show.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ show_backup_list(FILE *out, parray *backup_list)
235235
pgBackup *backup = parray_get(backup_list, i);
236236
TimeLineID parent_tli;
237237
char *backup_id;
238-
char timestamp[20] = "----";
238+
char timestamp[100] = "----";
239239
char duration[20] = "----";
240240
char data_bytes_str[10] = "----";
241241

src/util.c

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,9 +144,29 @@ get_data_checksum_version(bool safe)
144144
void
145145
time2iso(char *buf, size_t len, time_t time)
146146
{
147-
struct tm *tm = localtime(&time);
147+
struct tm *ptm = gmtime(&time);
148+
time_t gmt = mktime(ptm);
149+
time_t offset;
148150

149-
strftime(buf, len, "%Y-%m-%d %H:%M:%S", tm);
151+
ptm = localtime(&time);
152+
offset = time - gmt + (ptm->tm_isdst ? 3600 : 0);
153+
154+
strftime(buf, len, "%Y-%m-%d %H:%M:%S", ptm);
155+
156+
if (offset != 0)
157+
{
158+
buf += strlen(buf);
159+
sprintf(buf, "%c%02d",
160+
(offset >= 0) ? '+' : '-',
161+
abs((int) offset) / SECS_PER_HOUR);
162+
163+
if (abs((int) offset) % SECS_PER_HOUR != 0)
164+
{
165+
buf += strlen(buf);
166+
sprintf(buf, ":%02d",
167+
abs((int) offset % SECS_PER_HOUR) / SECS_PER_MINUTE);
168+
}
169+
}
150170
}
151171

152172
/* copied from timestamp.c */

src/utils/logger.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
*
33
* logger.h: - prototypes of logger functions.
44
*
5-
* Portions Copyright (c) 2017-2017, Postgres Professional
5+
* Copyright (c) 2017-2017, Postgres Professional
66
*
77
*-------------------------------------------------------------------------
88
*/

src/utils/pgut.c

Lines changed: 99 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@
2828
#endif
2929
#endif
3030

31+
#define MAX_TZDISP_HOUR 15 /* maximum allowed hour part */
32+
#define SECS_PER_MINUTE 60
33+
#define MINS_PER_HOUR 60
34+
3135
const char *PROGRAM_NAME = NULL;
3236

3337
const char *pgut_dbname = NULL;
@@ -496,19 +500,91 @@ parse_uint64(const char *value, uint64 *result)
496500
* Convert ISO-8601 format string to time_t value.
497501
*/
498502
bool
499-
parse_time(const char *value, time_t *time)
503+
parse_time(const char *value, time_t *result)
500504
{
501505
size_t len;
506+
int fields_num,
507+
tz = 0,
508+
i;
502509
char *tmp;
503-
int i;
504510
struct tm tm;
505511
char junk[2];
506512

507513
/* tmp = replace( value, !isalnum, ' ' ) */
508514
tmp = pgut_malloc(strlen(value) + + 1);
509515
len = 0;
510-
for (i = 0; value[i]; i++)
511-
tmp[len++] = (IsAlnum(value[i]) ? value[i] : ' ');
516+
fields_num = 1;
517+
518+
while (*value)
519+
{
520+
if (IsAlnum(*value))
521+
{
522+
tmp[len++] = *value;
523+
value++;
524+
}
525+
else if (fields_num < 6)
526+
{
527+
fields_num++;
528+
tmp[len++] = ' ';
529+
value++;
530+
}
531+
/* timezone field is 7th */
532+
else if ((*value == '-' || *value == '+') && fields_num == 6)
533+
{
534+
int hr,
535+
min,
536+
sec = 0;
537+
char *cp;
538+
539+
errno = 0;
540+
hr = strtol(value + 1, &cp, 10);
541+
if ((value + 1) == cp || errno == ERANGE)
542+
return false;
543+
544+
/* explicit delimiter? */
545+
if (*cp == ':')
546+
{
547+
errno = 0;
548+
min = strtol(cp + 1, &cp, 10);
549+
if (errno == ERANGE)
550+
return false;
551+
if (*cp == ':')
552+
{
553+
errno = 0;
554+
sec = strtol(cp + 1, &cp, 10);
555+
if (errno == ERANGE)
556+
return false;
557+
}
558+
}
559+
/* otherwise, might have run things together... */
560+
else if (*cp == '\0' && strlen(value) > 3)
561+
{
562+
min = hr % 100;
563+
hr = hr / 100;
564+
/* we could, but don't, support a run-together hhmmss format */
565+
}
566+
else
567+
min = 0;
568+
569+
/* Range-check the values; see notes in datatype/timestamp.h */
570+
if (hr < 0 || hr > MAX_TZDISP_HOUR)
571+
return false;
572+
if (min < 0 || min >= MINS_PER_HOUR)
573+
return false;
574+
if (sec < 0 || sec >= SECS_PER_MINUTE)
575+
return false;
576+
577+
tz = (hr * MINS_PER_HOUR + min) * SECS_PER_MINUTE + sec;
578+
if (*value == '-')
579+
tz = -tz;
580+
581+
fields_num++;
582+
value = cp;
583+
}
584+
/* wrong format */
585+
else if (!IsSpace(*value))
586+
return false;
587+
}
512588
tmp[len] = '\0';
513589

514590
/* parse for "YYYY-MM-DD HH:MI:SS" */
@@ -540,7 +616,25 @@ parse_time(const char *value, time_t *time)
540616
/* determine whether Daylight Saving Time is in effect */
541617
tm.tm_isdst = -1;
542618

543-
*time = mktime(&tm);
619+
*result = mktime(&tm);
620+
621+
/* adjust time zone */
622+
if (tz != 0)
623+
{
624+
time_t ltime = time(NULL);
625+
struct tm *ptm = gmtime(&ltime);
626+
time_t gmt = mktime(ptm);
627+
time_t offset;
628+
629+
/* UTC time */
630+
*result -= tz;
631+
632+
/* Get local time */
633+
ptm = localtime(&ltime);
634+
offset = ltime - gmt + (ptm->tm_isdst ? 3600 : 0);
635+
636+
*result += offset;
637+
}
544638

545639
return true;
546640
}

src/utils/pgut.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ extern bool parse_int32(const char *value, int32 *result);
195195
extern bool parse_uint32(const char *value, uint32 *result);
196196
extern bool parse_int64(const char *value, int64 *result);
197197
extern bool parse_uint64(const char *value, uint64 *result);
198-
extern bool parse_time(const char *value, time_t *time);
198+
extern bool parse_time(const char *value, time_t *result);
199199
extern bool parse_int(const char *value, int *result, int flags,
200200
const char **hintmsg);
201201

0 commit comments

Comments
 (0)