aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/src/sgml/datetime.sgml8
-rw-r--r--doc/src/sgml/func.sgml8
-rw-r--r--src/backend/utils/adt/date.c60
-rw-r--r--src/backend/utils/adt/timestamp.c142
-rw-r--r--src/include/pgtime.h4
-rw-r--r--src/timezone/pgtz.c6
6 files changed, 140 insertions, 88 deletions
diff --git a/doc/src/sgml/datetime.sgml b/doc/src/sgml/datetime.sgml
index 9610dc36c5c..2cfda15f097 100644
--- a/doc/src/sgml/datetime.sgml
+++ b/doc/src/sgml/datetime.sgml
@@ -1,5 +1,5 @@
<!--
-$PostgreSQL: pgsql/doc/src/sgml/datetime.sgml,v 2.46 2005/06/15 00:34:08 momjian Exp $
+$PostgreSQL: pgsql/doc/src/sgml/datetime.sgml,v 2.47 2005/09/09 02:31:48 tgl Exp $
-->
<appendix id="datetime-appendix">
@@ -990,9 +990,7 @@ $PostgreSQL: pgsql/doc/src/sgml/datetime.sgml,v 2.46 2005/06/15 00:34:08 momjian
<para>
<xref linkend="datetime-timezone-set-table"> shows the time zone
names recognized by <productname>PostgreSQL</productname> as valid
- settings for the <xref linkend="guc-timezone"> parameter, and as
- parameters to the <literal>AT TIME ZONE function</> (see
- <xref linkend="functions-datetime-zoneconvert">). Note that
+ settings for the <xref linkend="guc-timezone"> parameter. Note that
these names are conceptually as well as practically different from
the names shown in <xref linkend="datetime-timezone-input-table">:
most of these names imply a local daylight-savings time rule, whereas
@@ -1006,7 +1004,7 @@ $PostgreSQL: pgsql/doc/src/sgml/datetime.sgml,v 2.46 2005/06/15 00:34:08 momjian
</para>
<table id="datetime-timezone-set-table">
- <title>Time Zone Names for Setting <varname>timezone</> and <literal>AT TIME ZONE</></title>
+ <title>Time Zone Names for Setting <varname>timezone</></title>
<tgroup cols="1">
<thead>
<row>
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 9bef5e13783..41ca4a8cc9b 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -1,5 +1,5 @@
<!--
-$PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.283 2005/08/25 01:29:55 momjian Exp $
+$PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.284 2005/09/09 02:31:48 tgl Exp $
PostgreSQL documentation
-->
@@ -5730,9 +5730,9 @@ SELECT date_trunc('year', TIMESTAMP '2001-02-16 20:38:40');
In these expressions, the desired time zone <replaceable>zone</> can be
specified either as a text string (e.g., <literal>'PST'</literal>)
or as an interval (e.g., <literal>INTERVAL '-08:00'</literal>).
- In the text case, the available zone names are those shown in
- <xref linkend="datetime-timezone-set-table">. The time zone can
- also be implied using the default time zone for that session.
+ In the text case, the available zone names are those shown in either
+ <xref linkend="datetime-timezone-set-table"> or
+ <xref linkend="datetime-timezone-input-table">.
</para>
<para>
diff --git a/src/backend/utils/adt/date.c b/src/backend/utils/adt/date.c
index 477d7993e6f..b36ee180929 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.119 2005/07/23 14:25:33 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.120 2005/09/09 02:31:49 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -2484,37 +2484,53 @@ timetz_zone(PG_FUNCTION_ARGS)
TimeTzADT *t = PG_GETARG_TIMETZADT_P(1);
TimeTzADT *result;
int tz;
- char tzname[TZ_STRLEN_MAX];
+ char tzname[TZ_STRLEN_MAX + 1];
int len;
pg_tz *tzp;
- struct pg_tm *tm;
- pg_time_t now;
- /* Find the specified timezone */
- len = (VARSIZE(zone) - VARHDRSZ > TZ_STRLEN_MAX) ?
- TZ_STRLEN_MAX : VARSIZE(zone) - VARHDRSZ;
+ /*
+ * 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;
+ tzname[len] = '\0';
tzp = pg_tzset(tzname);
- if (!tzp) {
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("time zone \"%s\" not recognized", tzname)));
- PG_RETURN_NULL();
+ 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;
+ int type,
+ val;
- /* Get the offset-from-GMT that is valid today for the selected zone */
- if ((now = time(NULL)) < 0 ||
- (tm = pg_localtime(&now, tzp)) == NULL) {
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("could not determine current time")));
- PG_RETURN_NULL();
+ 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,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("time zone \"%s\" not recognized", tzname)));
+ tz = 0; /* keep compiler quiet */
+ }
}
- result = (TimeTzADT *)palloc(sizeof(TimeTzADT));
+ result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
- tz = -tm->tm_gmtoff;
#ifdef HAVE_INT64_TIMESTAMP
result->time = t->time + (t->zone - tz) * USECS_PER_SEC;
while (result->time < INT64CONST(0))
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index 2b15e64e061..b2d6f774c2f 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.151 2005/08/25 05:01:43 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.152 2005/09/09 02:31:49 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1014,7 +1014,7 @@ dt2time(Timestamp jd, int *hour, int *min, int *sec, fsec_t *fsec)
* 0 on success
* -1 on out of range
*
- * If attimezone is NULL, the global timezone (including possblly brute forced
+ * If attimezone is NULL, the global timezone (including possibly brute forced
* timezone) will be used.
*/
int
@@ -1113,8 +1113,8 @@ timestamp2tm(Timestamp dt, int *tzp, struct pg_tm *tm, fsec_t *fsec, char **tzn,
utime = (pg_time_t) dt;
if ((Timestamp) utime == dt)
{
- struct pg_tm *tx = pg_localtime(&utime, (attimezone != NULL) ?
- attimezone : global_timezone);
+ struct pg_tm *tx = pg_localtime(&utime,
+ attimezone ? attimezone : global_timezone);
tm->tm_year = tx->tm_year + 1900;
tm->tm_mon = tx->tm_mon + 1;
@@ -3948,48 +3948,64 @@ Datum
timestamp_zone(PG_FUNCTION_ARGS)
{
text *zone = PG_GETARG_TEXT_P(0);
- Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
+ Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
TimestampTz result;
int tz;
pg_tz *tzp;
- char tzname[TZ_STRLEN_MAX+1];
+ char tzname[TZ_STRLEN_MAX + 1];
int len;
- struct pg_tm tm;
- fsec_t fsec;
- bool fail;
if (TIMESTAMP_NOT_FINITE(timestamp))
PG_RETURN_TIMESTAMPTZ(timestamp);
- /* Find the specified timezone */
- len = (VARSIZE(zone) - VARHDRSZ>TZ_STRLEN_MAX) ?
- TZ_STRLEN_MAX : VARSIZE(zone) - VARHDRSZ;
+ /*
+ * 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;
+ tzname[len] = '\0';
tzp = pg_tzset(tzname);
- if (!tzp)
+ if (tzp)
{
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("time zone \"%s\" not recognised",
- tzname)));
- PG_RETURN_NULL();
- }
+ /* Apply the timezone change */
+ struct pg_tm tm;
+ fsec_t fsec;
- /* Apply the timezone change */
- fail = (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, tzp) != 0);
- if (!fail)
- {
+ 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);
- fail = (tm2timestamp(&tm, fsec, &tz, &result) != 0);
+ if (tm2timestamp(&tm, fsec, &tz, &result) != 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("could not convert to time zone \"%s\"",
+ tzname)));
}
- if (fail)
+ else
{
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("could not convert to time zone \"%s\"",
- tzname)));
- PG_RETURN_NULL();
+ 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,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("time zone \"%s\" not recognized", tzname)));
+ tz = 0; /* keep compiler quiet */
+ }
+
+ result = dt2local(timestamp, tz);
}
PG_RETURN_TIMESTAMPTZ(result);
@@ -4109,37 +4125,59 @@ timestamptz_zone(PG_FUNCTION_ARGS)
Timestamp result;
int tz;
pg_tz *tzp;
- char tzname[TZ_STRLEN_MAX];
+ char tzname[TZ_STRLEN_MAX + 1];
int len;
- struct pg_tm tm;
- fsec_t fsec = 0;
if (TIMESTAMP_NOT_FINITE(timestamp))
- PG_RETURN_NULL();
+ PG_RETURN_TIMESTAMP(timestamp);
- /* Find the specified zone */
- len = (VARSIZE(zone) - VARHDRSZ > TZ_STRLEN_MAX) ?
- TZ_STRLEN_MAX : VARSIZE(zone) - VARHDRSZ;
+ /*
+ * 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;
+ tzname[len] = '\0';
tzp = pg_tzset(tzname);
-
- if (!tzp)
+ if (tzp)
{
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("time zone \"%s\" not recognized", tzname)));
+ /* Apply the timezone change */
+ struct pg_tm tm;
+ fsec_t fsec;
- PG_RETURN_NULL();
+ 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
+ {
+ char *lowzone;
+ int type,
+ val;
- if (timestamp2tm(timestamp, &tz, &tm, &fsec, NULL, tzp) != 0 ||
- tm2timestamp(&tm, fsec, NULL, &result))
- {
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("could not to convert to time zone \"%s\"", tzname)));
- PG_RETURN_NULL();
+ 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,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("time zone \"%s\" not recognized", tzname)));
+ tz = 0; /* keep compiler quiet */
+ }
+
+ result = dt2local(timestamp, tz);
}
PG_RETURN_TIMESTAMP(result);
diff --git a/src/include/pgtime.h b/src/include/pgtime.h
index ab4bdef1f68..95f21393939 100644
--- a/src/include/pgtime.h
+++ b/src/include/pgtime.h
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/include/pgtime.h,v 1.9 2005/07/22 03:46:34 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/pgtime.h,v 1.10 2005/09/09 02:31:49 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -58,7 +58,7 @@ extern const char *pg_get_timezone_name(pg_tz *tz);
extern pg_tz *global_timezone;
-/* Maximum length of a timezone name */
+/* Maximum length of a timezone name (not including trailing null) */
#define TZ_STRLEN_MAX 255
#endif /* _PGTIME_H */
diff --git a/src/timezone/pgtz.c b/src/timezone/pgtz.c
index 305bea2e5eb..2512061222a 100644
--- a/src/timezone/pgtz.c
+++ b/src/timezone/pgtz.c
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/timezone/pgtz.c,v 1.36 2005/06/26 23:32:34 tgl Exp $
+ * $PostgreSQL: pgsql/src/timezone/pgtz.c,v 1.37 2005/09/09 02:31:50 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -974,7 +974,7 @@ init_timezone_hashtable(void)
MemSet(&hash_ctl, 0, sizeof(hash_ctl));
- hash_ctl.keysize = TZ_STRLEN_MAX;
+ hash_ctl.keysize = TZ_STRLEN_MAX + 1;
hash_ctl.entrysize = sizeof(pg_tz);
timezone_cache = hash_create("Timezones",
@@ -997,7 +997,7 @@ pg_tzset(const char *name)
pg_tz *tzp;
pg_tz tz;
- if (strlen(name) >= TZ_STRLEN_MAX)
+ if (strlen(name) > TZ_STRLEN_MAX)
return NULL; /* not going to fit */
if (!timezone_cache)