diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml index 07f0385d80d4eeb4f568e43efbf387f4791a3a56..dea5195786a45ff18bb3d327d35ccb7c5b4cb050 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 <literal>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 (<literal><></>). + 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 <literal>zoneinfo</> time zone database's <filename>posixrules</> entry. In a standard <productname>PostgreSQL</productname> installation, diff --git a/doc/src/sgml/ref/set.sgml b/doc/src/sgml/ref/set.sgml index d108dd4831c56757ccabd394406c2ec976a0fa6b..6290c9de70852cb6cb502b9e4804e456fe7c9973 100644 --- a/doc/src/sgml/ref/set.sgml +++ b/doc/src/sgml/ref/set.sgml @@ -243,7 +243,16 @@ SELECT setseed(<replaceable>value</replaceable>); </listitem> </varlistentry> </variablelist> + </para> + <para> + Timezone settings given as numbers or intervals are internally + translated to POSIX timezone syntax. For example, after + <literal>SET TIME ZONE -7</>, <command>SHOW TIME ZONE</> would + report <literal><-07>+07</>. + </para> + + <para> See <xref linkend="datatype-timezones"> for more information about time zones. </para> diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index b6af6e7e2531300a6ccb887465fc3a26a982eb56..e1ce6ff5b0a45ab008a358933fd3298b460310ec 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 33efb3c3cca933f69aa16286aa8c0e68d67bb754..e76704f315334e9be0f3cae5af06de41d0e5829b 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 0aa540a08ef8e53db4e1aa339df27a20c4de66b6..98ca5539a4ca7e1a7f2ee0cf544f5eecdbce4be1 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 3ed9c8c1a095e939ef8cdd1c050fac307a96cdc5..87a695144eaf4f2ea1457dabefb8074e2182a5a9 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;