diff options
Diffstat (limited to 'src/backend/utils/adt/date.c')
-rw-r--r-- | src/backend/utils/adt/date.c | 31 |
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) { |