aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/date.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/adt/date.c')
-rw-r--r--src/backend/utils/adt/date.c31
1 files changed, 23 insertions, 8 deletions
diff --git a/src/backend/utils/adt/date.c b/src/backend/utils/adt/date.c
index 073104d4bac..bb23b12c171 100644
--- a/src/backend/utils/adt/date.c
+++ b/src/backend/utils/adt/date.c
@@ -2695,24 +2695,39 @@ timetz_zone(PG_FUNCTION_ARGS)
pg_tz *tzp;
/*
- * Look up the requested timezone. First we look in the date token table
- * (to handle cases like "EST"), and if that fails, we look in the
- * timezone database (to handle cases like "America/New_York"). (This
- * matches the order in which timestamp input checks the cases; it's
- * important because the timezone database unwisely uses a few zone names
- * that are identical to offset abbreviations.)
+ * Look up the requested timezone. First we look in the timezone
+ * abbreviation table (to handle cases like "EST"), and if that fails, we
+ * look in the timezone database (to handle cases like
+ * "America/New_York"). (This matches the order in which timestamp input
+ * checks the cases; it's important because the timezone database unwisely
+ * uses a few zone names that are identical to offset abbreviations.)
*/
text_to_cstring_buffer(zone, tzname, sizeof(tzname));
+
+ /* DecodeTimezoneAbbrev requires lowercase input */
lowzone = downcase_truncate_identifier(tzname,
strlen(tzname),
false);
- type = DecodeSpecial(0, lowzone, &val);
+ type = DecodeTimezoneAbbrev(0, lowzone, &val, &tzp);
if (type == TZ || type == DTZ)
- tz = val * MINS_PER_HOUR;
+ {
+ /* fixed-offset abbreviation */
+ tz = -val;
+ }
+ else if (type == DYNTZ)
+ {
+ /* dynamic-offset abbreviation, resolve using current time */
+ pg_time_t now = (pg_time_t) time(NULL);
+ struct pg_tm *tm;
+
+ tm = pg_localtime(&now, tzp);
+ tz = DetermineTimeZoneAbbrevOffset(tm, tzname, tzp);
+ }
else
{
+ /* try it as a full zone name */
tzp = pg_tzset(tzname);
if (tzp)
{