mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-12-27 08:39:28 +08:00
Fix AT TIME ZONE (in all three variants) so that we first try to interpret
the timezone argument as a timezone abbreviation, and only try it as a full timezone name if that fails. The zic database has four zones (CET, EET, MET, WET) that are full daylight-savings zones and yet have names that are the same as their abbreviations for standard time, resulting in ambiguity. In the timestamp input functions we resolve the ambiguity by preferring the abbreviation, and AT TIME ZONE should work the same way. (No functionality is lost because the zic database also has other names for these zones, eg Europe/Zurich.) Per gripe from Jaromir Talir. Backpatch to 8.1. Older releases did not have the issue because AT TIME ZONE only accepted abbreviations not zone names. (Thus, this patch also arguably fixes a compatibility botch introduced at 8.1: in ambiguous cases we now behave the same as 8.0 did.)
This commit is contained in:
parent
5b924b1c9b
commit
495d327b11
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.125.2.1 2007/06/02 16:41:15 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.125.2.2 2008/07/07 18:10:03 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -2508,33 +2508,19 @@ timetz_zone(PG_FUNCTION_ARGS)
|
|||||||
int tz;
|
int tz;
|
||||||
char tzname[TZ_STRLEN_MAX + 1];
|
char tzname[TZ_STRLEN_MAX + 1];
|
||||||
int len;
|
int len;
|
||||||
pg_tz *tzp;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Look up the requested timezone. First we look in the timezone database
|
|
||||||
* (to handle cases like "America/New_York"), and if that fails, we look
|
|
||||||
* in the date token table (to handle cases like "EST").
|
|
||||||
*/
|
|
||||||
len = Min(VARSIZE(zone) - VARHDRSZ, TZ_STRLEN_MAX);
|
|
||||||
memcpy(tzname, VARDATA(zone), len);
|
|
||||||
tzname[len] = '\0';
|
|
||||||
tzp = pg_tzset(tzname);
|
|
||||||
if (tzp)
|
|
||||||
{
|
|
||||||
/* Get the offset-from-GMT that is valid today for the selected zone */
|
|
||||||
pg_time_t now;
|
|
||||||
struct pg_tm *tm;
|
|
||||||
|
|
||||||
now = time(NULL);
|
|
||||||
tm = pg_localtime(&now, tzp);
|
|
||||||
tz = -tm->tm_gmtoff;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
char *lowzone;
|
char *lowzone;
|
||||||
int type,
|
int type,
|
||||||
val;
|
val;
|
||||||
|
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.)
|
||||||
|
*/
|
||||||
lowzone = downcase_truncate_identifier(VARDATA(zone),
|
lowzone = downcase_truncate_identifier(VARDATA(zone),
|
||||||
VARSIZE(zone) - VARHDRSZ,
|
VARSIZE(zone) - VARHDRSZ,
|
||||||
false);
|
false);
|
||||||
@ -2543,6 +2529,22 @@ timetz_zone(PG_FUNCTION_ARGS)
|
|||||||
if (type == TZ || type == DTZ)
|
if (type == TZ || type == DTZ)
|
||||||
tz = val * 60;
|
tz = val * 60;
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
len = Min(VARSIZE(zone) - VARHDRSZ, TZ_STRLEN_MAX);
|
||||||
|
memcpy(tzname, VARDATA(zone), len);
|
||||||
|
tzname[len] = '\0';
|
||||||
|
tzp = pg_tzset(tzname);
|
||||||
|
if (tzp)
|
||||||
|
{
|
||||||
|
/* Get the offset-from-GMT that is valid today for the zone */
|
||||||
|
pg_time_t now;
|
||||||
|
struct pg_tm *tm;
|
||||||
|
|
||||||
|
now = time(NULL);
|
||||||
|
tm = pg_localtime(&now, tzp);
|
||||||
|
tz = -tm->tm_gmtoff;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.169.2.1 2007/09/16 15:56:32 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.169.2.2 2008/07/07 18:10:03 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -4223,18 +4223,36 @@ timestamp_zone(PG_FUNCTION_ARGS)
|
|||||||
Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
|
Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
|
||||||
TimestampTz result;
|
TimestampTz result;
|
||||||
int tz;
|
int tz;
|
||||||
pg_tz *tzp;
|
|
||||||
char tzname[TZ_STRLEN_MAX + 1];
|
char tzname[TZ_STRLEN_MAX + 1];
|
||||||
int len;
|
int len;
|
||||||
|
char *lowzone;
|
||||||
|
int type,
|
||||||
|
val;
|
||||||
|
pg_tz *tzp;
|
||||||
|
|
||||||
if (TIMESTAMP_NOT_FINITE(timestamp))
|
if (TIMESTAMP_NOT_FINITE(timestamp))
|
||||||
PG_RETURN_TIMESTAMPTZ(timestamp);
|
PG_RETURN_TIMESTAMPTZ(timestamp);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Look up the requested timezone. First we look in the timezone database
|
* Look up the requested timezone. First we look in the date token table
|
||||||
* (to handle cases like "America/New_York"), and if that fails, we look
|
* (to handle cases like "EST"), and if that fails, we look in the
|
||||||
* in the date token table (to handle cases like "EST").
|
* 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.)
|
||||||
*/
|
*/
|
||||||
|
lowzone = downcase_truncate_identifier(VARDATA(zone),
|
||||||
|
VARSIZE(zone) - VARHDRSZ,
|
||||||
|
false);
|
||||||
|
type = DecodeSpecial(0, lowzone, &val);
|
||||||
|
|
||||||
|
if (type == TZ || type == DTZ)
|
||||||
|
{
|
||||||
|
tz = -(val * 60);
|
||||||
|
result = dt2local(timestamp, tz);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
len = Min(VARSIZE(zone) - VARHDRSZ, TZ_STRLEN_MAX);
|
len = Min(VARSIZE(zone) - VARHDRSZ, TZ_STRLEN_MAX);
|
||||||
memcpy(tzname, VARDATA(zone), len);
|
memcpy(tzname, VARDATA(zone), len);
|
||||||
tzname[len] = '\0';
|
tzname[len] = '\0';
|
||||||
@ -4257,27 +4275,12 @@ timestamp_zone(PG_FUNCTION_ARGS)
|
|||||||
tzname)));
|
tzname)));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
char *lowzone;
|
|
||||||
int type,
|
|
||||||
val;
|
|
||||||
|
|
||||||
lowzone = downcase_truncate_identifier(VARDATA(zone),
|
|
||||||
VARSIZE(zone) - VARHDRSZ,
|
|
||||||
false);
|
|
||||||
type = DecodeSpecial(0, lowzone, &val);
|
|
||||||
|
|
||||||
if (type == TZ || type == DTZ)
|
|
||||||
tz = -(val * 60);
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||||
errmsg("time zone \"%s\" not recognized", tzname)));
|
errmsg("time zone \"%s\" not recognized", tzname)));
|
||||||
tz = 0; /* keep compiler quiet */
|
result = 0; /* keep compiler quiet */
|
||||||
}
|
}
|
||||||
|
|
||||||
result = dt2local(timestamp, tz);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PG_RETURN_TIMESTAMPTZ(result);
|
PG_RETURN_TIMESTAMPTZ(result);
|
||||||
@ -4396,18 +4399,36 @@ timestamptz_zone(PG_FUNCTION_ARGS)
|
|||||||
TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
|
TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
|
||||||
Timestamp result;
|
Timestamp result;
|
||||||
int tz;
|
int tz;
|
||||||
pg_tz *tzp;
|
|
||||||
char tzname[TZ_STRLEN_MAX + 1];
|
char tzname[TZ_STRLEN_MAX + 1];
|
||||||
int len;
|
int len;
|
||||||
|
char *lowzone;
|
||||||
|
int type,
|
||||||
|
val;
|
||||||
|
pg_tz *tzp;
|
||||||
|
|
||||||
if (TIMESTAMP_NOT_FINITE(timestamp))
|
if (TIMESTAMP_NOT_FINITE(timestamp))
|
||||||
PG_RETURN_TIMESTAMP(timestamp);
|
PG_RETURN_TIMESTAMP(timestamp);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Look up the requested timezone. First we look in the timezone database
|
* Look up the requested timezone. First we look in the date token table
|
||||||
* (to handle cases like "America/New_York"), and if that fails, we look
|
* (to handle cases like "EST"), and if that fails, we look in the
|
||||||
* in the date token table (to handle cases like "EST").
|
* 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.)
|
||||||
*/
|
*/
|
||||||
|
lowzone = downcase_truncate_identifier(VARDATA(zone),
|
||||||
|
VARSIZE(zone) - VARHDRSZ,
|
||||||
|
false);
|
||||||
|
type = DecodeSpecial(0, lowzone, &val);
|
||||||
|
|
||||||
|
if (type == TZ || type == DTZ)
|
||||||
|
{
|
||||||
|
tz = val * 60;
|
||||||
|
result = dt2local(timestamp, tz);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
len = Min(VARSIZE(zone) - VARHDRSZ, TZ_STRLEN_MAX);
|
len = Min(VARSIZE(zone) - VARHDRSZ, TZ_STRLEN_MAX);
|
||||||
memcpy(tzname, VARDATA(zone), len);
|
memcpy(tzname, VARDATA(zone), len);
|
||||||
tzname[len] = '\0';
|
tzname[len] = '\0';
|
||||||
@ -4429,27 +4450,12 @@ timestamptz_zone(PG_FUNCTION_ARGS)
|
|||||||
tzname)));
|
tzname)));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
char *lowzone;
|
|
||||||
int type,
|
|
||||||
val;
|
|
||||||
|
|
||||||
lowzone = downcase_truncate_identifier(VARDATA(zone),
|
|
||||||
VARSIZE(zone) - VARHDRSZ,
|
|
||||||
false);
|
|
||||||
type = DecodeSpecial(0, lowzone, &val);
|
|
||||||
|
|
||||||
if (type == TZ || type == DTZ)
|
|
||||||
tz = val * 60;
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||||
errmsg("time zone \"%s\" not recognized", tzname)));
|
errmsg("time zone \"%s\" not recognized", tzname)));
|
||||||
tz = 0; /* keep compiler quiet */
|
result = 0; /* keep compiler quiet */
|
||||||
}
|
}
|
||||||
|
|
||||||
result = dt2local(timestamp, tz);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PG_RETURN_TIMESTAMP(result);
|
PG_RETURN_TIMESTAMP(result);
|
||||||
|
Loading…
Reference in New Issue
Block a user