diff --git a/src/backend/utils/adt/date.c b/src/backend/utils/adt/date.c index e7374388dd..6f10b666ca 100644 --- a/src/backend/utils/adt/date.c +++ b/src/backend/utils/adt/date.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.141 2008/03/25 22:42:43 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.142 2008/07/07 18:09:46 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -2441,37 +2441,40 @@ timetz_zone(PG_FUNCTION_ARGS) TimeTzADT *result; int tz; char tzname[TZ_STRLEN_MAX + 1]; + char *lowzone; + int type, + val; 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"). + * 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.) */ text_to_cstring_buffer(zone, tzname, sizeof(tzname)); - tzp = pg_tzset(tzname); - if (tzp) - { - /* Get the offset-from-GMT that is valid today for the selected zone */ - pg_time_t now = (pg_time_t) time(NULL); - struct pg_tm *tm; + lowzone = downcase_truncate_identifier(tzname, + strlen(tzname), + false); - tm = pg_localtime(&now, tzp); - tz = -tm->tm_gmtoff; - } + type = DecodeSpecial(0, lowzone, &val); + + if (type == TZ || type == DTZ) + tz = val * 60; else { - char *lowzone; - int type, - val; + tzp = pg_tzset(tzname); + if (tzp) + { + /* Get the offset-from-GMT that is valid today for the zone */ + pg_time_t now = (pg_time_t) time(NULL); + struct pg_tm *tm; - lowzone = downcase_truncate_identifier(tzname, - strlen(tzname), - false); - type = DecodeSpecial(0, lowzone, &val); - - if (type == TZ || type == DTZ) - tz = val * 60; + tm = pg_localtime(&now, tzp); + tz = -tm->tm_gmtoff; + } else { ereport(ERROR, diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c index c266ed0f38..d6a5dee084 100644 --- a/src/backend/utils/adt/timestamp.c +++ b/src/backend/utils/adt/timestamp.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.189 2008/05/04 23:19:23 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.190 2008/07/07 18:09:46 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -4410,58 +4410,62 @@ timestamp_zone(PG_FUNCTION_ARGS) Timestamp timestamp = PG_GETARG_TIMESTAMP(1); TimestampTz result; int tz; - pg_tz *tzp; char tzname[TZ_STRLEN_MAX + 1]; + char *lowzone; + int type, + val; + pg_tz *tzp; if (TIMESTAMP_NOT_FINITE(timestamp)) PG_RETURN_TIMESTAMPTZ(timestamp); /* - * 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"). + * 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.) */ text_to_cstring_buffer(zone, tzname, sizeof(tzname)); - tzp = pg_tzset(tzname); - if (tzp) - { - /* Apply the timezone change */ - struct pg_tm tm; - fsec_t fsec; + lowzone = downcase_truncate_identifier(tzname, + strlen(tzname), + false); - if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, tzp) != 0) - ereport(ERROR, - (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), - errmsg("timestamp out of range"))); - tz = DetermineTimeZoneOffset(&tm, tzp); - if (tm2timestamp(&tm, fsec, &tz, &result) != 0) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("could not convert to time zone \"%s\"", - tzname))); + type = DecodeSpecial(0, lowzone, &val); + + if (type == TZ || type == DTZ) + { + tz = -(val * 60); + result = dt2local(timestamp, tz); } else { - char *lowzone; - int type, - val; + tzp = pg_tzset(tzname); + if (tzp) + { + /* Apply the timezone change */ + struct pg_tm tm; + fsec_t fsec; - lowzone = downcase_truncate_identifier(tzname, - strlen(tzname), - false); - type = DecodeSpecial(0, lowzone, &val); - - if (type == TZ || type == DTZ) - tz = -(val * 60); + if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, tzp) != 0) + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("timestamp out of range"))); + tz = DetermineTimeZoneOffset(&tm, tzp); + if (tm2timestamp(&tm, fsec, &tz, &result) != 0) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("could not convert to time zone \"%s\"", + tzname))); + } else { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), 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); @@ -4580,57 +4584,61 @@ timestamptz_zone(PG_FUNCTION_ARGS) TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1); Timestamp result; int tz; - pg_tz *tzp; char tzname[TZ_STRLEN_MAX + 1]; + char *lowzone; + int type, + val; + pg_tz *tzp; if (TIMESTAMP_NOT_FINITE(timestamp)) PG_RETURN_TIMESTAMP(timestamp); /* - * 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"). + * 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.) */ text_to_cstring_buffer(zone, tzname, sizeof(tzname)); - tzp = pg_tzset(tzname); - if (tzp) - { - /* Apply the timezone change */ - struct pg_tm tm; - fsec_t fsec; + lowzone = downcase_truncate_identifier(tzname, + strlen(tzname), + false); - if (timestamp2tm(timestamp, &tz, &tm, &fsec, NULL, tzp) != 0) - ereport(ERROR, - (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), - errmsg("timestamp out of range"))); - if (tm2timestamp(&tm, fsec, NULL, &result) != 0) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("could not convert to time zone \"%s\"", - tzname))); + type = DecodeSpecial(0, lowzone, &val); + + if (type == TZ || type == DTZ) + { + tz = val * 60; + result = dt2local(timestamp, tz); } else { - char *lowzone; - int type, - val; + tzp = pg_tzset(tzname); + if (tzp) + { + /* Apply the timezone change */ + struct pg_tm tm; + fsec_t fsec; - lowzone = downcase_truncate_identifier(tzname, - strlen(tzname), - false); - type = DecodeSpecial(0, lowzone, &val); - - if (type == TZ || type == DTZ) - tz = val * 60; + if (timestamp2tm(timestamp, &tz, &tm, &fsec, NULL, tzp) != 0) + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("timestamp out of range"))); + if (tm2timestamp(&tm, fsec, NULL, &result) != 0) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("could not convert to time zone \"%s\"", + tzname))); + } else { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), 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);