diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml index 07f0385d80..dea5195786 100644 --- a/doc/src/sgml/datatype.sgml +++ b/doc/src/sgml/datatype.sgml @@ -2419,8 +2419,11 @@ January 8 04:05:06 1999 PST optional daylight-savings zone abbreviation, assumed to stand for one hour ahead of the given offset. For example, if EST5EDT were not already a recognized zone name, it would be accepted and would - be functionally equivalent to United States East Coast time. When a - daylight-savings zone name is present, it is assumed to be used + be functionally equivalent to United States East Coast time. In this + syntax, a zone abbreviation can be a string of letters, or an + arbitrary string surrounded by angle brackets (<>). + When a daylight-savings zone abbreviation is present, + it is assumed to be used according to the same daylight-savings transition rules used in the zoneinfo time zone database's posixrules entry. In a standard PostgreSQL installation, diff --git a/doc/src/sgml/ref/set.sgml b/doc/src/sgml/ref/set.sgml index d108dd4831..6290c9de70 100644 --- a/doc/src/sgml/ref/set.sgml +++ b/doc/src/sgml/ref/set.sgml @@ -243,7 +243,16 @@ SELECT setseed(value); + + + Timezone settings given as numbers or intervals are internally + translated to POSIX timezone syntax. For example, after + SET TIME ZONE -7, SHOW TIME ZONE would + report <-07>+07. + + + See for more information about time zones. diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index b6af6e7e25..e1ce6ff5b0 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -243,34 +243,17 @@ assign_datestyle(const char *newval, void *extra) * TIMEZONE */ -typedef struct -{ - pg_tz *session_timezone; - int CTimeZone; - bool HasCTZSet; -} timezone_extra; - /* * check_timezone: GUC check_hook for timezone */ bool check_timezone(char **newval, void **extra, GucSource source) { - timezone_extra myextra; + pg_tz *new_tz; + long gmtoffset; char *endptr; double hours; - /* - * Initialize the "extra" struct that will be passed to assign_timezone. - * We don't want to change any of the three global variables except as - * specified by logic below. To avoid leaking memory during failure - * returns, we set up the struct contents in a local variable, and only - * copy it to *extra at the end. - */ - myextra.session_timezone = session_timezone; - myextra.CTimeZone = CTimeZone; - myextra.HasCTZSet = HasCTZSet; - if (pg_strncasecmp(*newval, "interval", 8) == 0) { /* @@ -323,12 +306,11 @@ check_timezone(char **newval, void **extra, GucSource source) /* Here we change from SQL to Unix sign convention */ #ifdef HAVE_INT64_TIMESTAMP - myextra.CTimeZone = -(interval->time / USECS_PER_SEC); + gmtoffset = -(interval->time / USECS_PER_SEC); #else - myextra.CTimeZone = -interval->time; + gmtoffset = -interval->time; #endif - myextra.session_timezone = pg_tzset_offset(myextra.CTimeZone); - myextra.HasCTZSet = true; + new_tz = pg_tzset_offset(gmtoffset); pfree(interval); } @@ -341,17 +323,14 @@ check_timezone(char **newval, void **extra, GucSource source) if (endptr != *newval && *endptr == '\0') { /* Here we change from SQL to Unix sign convention */ - myextra.CTimeZone = -hours * SECS_PER_HOUR; - myextra.session_timezone = pg_tzset_offset(myextra.CTimeZone); - myextra.HasCTZSet = true; + gmtoffset = -hours * SECS_PER_HOUR; + new_tz = pg_tzset_offset(gmtoffset); } else { /* * Otherwise assume it is a timezone name, and try to load it. */ - pg_tz *new_tz; - new_tz = pg_tzset(*newval); if (!new_tz) @@ -367,40 +346,16 @@ check_timezone(char **newval, void **extra, GucSource source) GUC_check_errdetail("PostgreSQL does not support leap seconds."); return false; } - - myextra.session_timezone = new_tz; - myextra.HasCTZSet = false; } } - /* - * Prepare the canonical string to return. GUC wants it malloc'd. - * - * Note: the result string should be something that we'd accept as input. - * We use the numeric format for interval cases, because it's simpler to - * reload. In the named-timezone case, *newval is already OK and need not - * be changed; it might not have the canonical casing, but that's taken - * care of by show_timezone. - */ - if (myextra.HasCTZSet) - { - char *result = (char *) malloc(64); - - if (!result) - return false; - snprintf(result, 64, "%.5f", - (double) (-myextra.CTimeZone) / (double) SECS_PER_HOUR); - free(*newval); - *newval = result; - } - /* * Pass back data for assign_timezone to use */ - *extra = malloc(sizeof(timezone_extra)); + *extra = malloc(sizeof(pg_tz *)); if (!*extra) return false; - memcpy(*extra, &myextra, sizeof(timezone_extra)); + *((pg_tz **) *extra) = new_tz; return true; } @@ -411,43 +366,19 @@ check_timezone(char **newval, void **extra, GucSource source) void assign_timezone(const char *newval, void *extra) { - timezone_extra *myextra = (timezone_extra *) extra; - - session_timezone = myextra->session_timezone; - CTimeZone = myextra->CTimeZone; - HasCTZSet = myextra->HasCTZSet; + session_timezone = *((pg_tz **) extra); } /* * show_timezone: GUC show_hook for timezone - * - * We wouldn't need this, except that historically interval values have been - * shown without an INTERVAL prefix, so the display format isn't what would - * be accepted as input. Otherwise we could have check_timezone return the - * preferred string to begin with. */ const char * show_timezone(void) { const char *tzn; - if (HasCTZSet) - { - Interval interval; - - interval.month = 0; - interval.day = 0; -#ifdef HAVE_INT64_TIMESTAMP - interval.time = -(CTimeZone * USECS_PER_SEC); -#else - interval.time = -CTimeZone; -#endif - - tzn = DatumGetCString(DirectFunctionCall1(interval_out, - IntervalPGetDatum(&interval))); - } - else - tzn = pg_get_timezone_name(session_timezone); + /* Always show the zone's canonical name */ + tzn = pg_get_timezone_name(session_timezone); if (tzn != NULL) return tzn; @@ -497,7 +428,7 @@ check_log_timezone(char **newval, void **extra, GucSource source) *extra = malloc(sizeof(pg_tz *)); if (!*extra) return false; - memcpy(*extra, &new_tz, sizeof(pg_tz *)); + *((pg_tz **) *extra) = new_tz; return true; } @@ -519,6 +450,7 @@ show_log_timezone(void) { const char *tzn; + /* Always show the zone's canonical name */ tzn = pg_get_timezone_name(log_timezone); if (tzn != NULL) diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c index 33efb3c3cc..e76704f315 100644 --- a/src/backend/utils/init/globals.c +++ b/src/backend/utils/init/globals.c @@ -93,8 +93,6 @@ bool ExitOnAnyError = false; int DateStyle = USE_ISO_DATES; int DateOrder = DATEORDER_MDY; int IntervalStyle = INTSTYLE_POSTGRES; -bool HasCTZSet = false; -int CTimeZone = 0; bool enableFsync = true; bool allowSystemTableMods = false; diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h index 0aa540a08e..98ca5539a4 100644 --- a/src/include/miscadmin.h +++ b/src/include/miscadmin.h @@ -219,15 +219,6 @@ extern int DateOrder; extern int IntervalStyle; -/* - * HasCTZSet is true if user has set timezone as a numeric offset from UTC. - * If so, CTimeZone is the timezone offset in seconds (using the Unix-ish - * sign convention, ie, positive offset is west of UTC, rather than the - * SQL-ish convention that positive is east of UTC). - */ -extern bool HasCTZSet; -extern int CTimeZone; - #define MAXTZLEN 10 /* max TZ name len, not counting tr. null */ extern bool enableFsync; diff --git a/src/test/regress/expected/horology.out b/src/test/regress/expected/horology.out index 3ed9c8c1a0..87a695144e 100644 --- a/src/test/regress/expected/horology.out +++ b/src/test/regress/expected/horology.out @@ -2941,9 +2941,9 @@ DETAIL: Value must be in the range -2147483648 to 2147483647. SET TIME ZONE 'America/New_York'; SET TIME ZONE '-1.5'; SHOW TIME ZONE; - TimeZone ----------------------- - @ 1 hour 30 mins ago + TimeZone +---------------- + <-01:30>+01:30 (1 row) SELECT '2012-12-12 12:00'::timestamptz;