]> granicus.if.org Git - postgresql/commitdiff
This patch makes it possible to use the full set of timezones when doing
authorBruce Momjian <bruce@momjian.us>
Wed, 15 Jun 2005 00:34:11 +0000 (00:34 +0000)
committerBruce Momjian <bruce@momjian.us>
Wed, 15 Jun 2005 00:34:11 +0000 (00:34 +0000)
"AT TIME ZONE", and not just the shorlist previously available. For
example:

SELECT CURRENT_TIMESTAMP AT TIME ZONE 'Europe/London';

works fine now. It will also obey whatever DST rules were in effect at
just that date, which the previous implementation did not.

It also supports the AT TIME ZONE on the timetz datatype. The whole
handling of DST is a bit bogus there, so I chose to make it use whatever
DST rules are in effect at the time of executig the query. not sure if
anybody is actuallyi *using* timetz though, it seems pretty
unpredictable just because of this...

Magnus Hagander

doc/src/sgml/datetime.sgml
doc/src/sgml/func.sgml
src/backend/utils/adt/date.c
src/backend/utils/adt/formatting.c
src/backend/utils/adt/nabstime.c
src/backend/utils/adt/timestamp.c
src/include/pgtime.h
src/include/utils/timestamp.h
src/timezone/pgtz.h

index 0e42e34fd69a67df6834b3012dbef3408231fab2..9610dc36c5cada51e4d6c12f98bb37c2fcf75e24 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/datetime.sgml,v 2.45 2005/01/09 18:58:10 tgl Exp $
+$PostgreSQL: pgsql/doc/src/sgml/datetime.sgml,v 2.46 2005/06/15 00:34:08 momjian Exp $
 -->
 
  <appendix id="datetime-appendix">
@@ -990,7 +990,9 @@ $PostgreSQL: pgsql/doc/src/sgml/datetime.sgml,v 2.45 2005/01/09 18:58:10 tgl Exp
    <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.  Note that
+    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
     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
@@ -1004,7 +1006,7 @@ $PostgreSQL: pgsql/doc/src/sgml/datetime.sgml,v 2.45 2005/01/09 18:58:10 tgl Exp
    </para>
 
     <table id="datetime-timezone-set-table">
-     <title>Time Zone Names for Setting <varname>timezone</></title>
+     <title>Time Zone Names for Setting <varname>timezone</> and <literal>AT TIME ZONE</></title>
      <tgroup cols="1">
       <thead>
        <row>
index 4fe5e1d6fca6ff6f20a23436c1d6090668d47087..38e2c4a7001b958b664136e3837459ab815a8543 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.256 2005/06/14 23:47:39 momjian Exp $
+$PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.257 2005/06/15 00:34:08 momjian Exp $
 PostgreSQL documentation
 -->
 
@@ -5679,10 +5679,7 @@ SELECT date_trunc('year', TIMESTAMP '2001-02-16 20:38:40');
     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-input-table">.  (It would be useful
-    to support the more general names shown in
-    <xref linkend="datetime-timezone-set-table">, but this is not yet
-    implemented.)
+    <xref linkend="datetime-timezone-set-table">.
    </para>
 
    <para>
index 5371c64250a7b24f5763c3a108a174f5dd5ba477..abc6155594f137f242268fb8deff5d36c26da894 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.109 2005/05/26 02:04:13 neilc Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.110 2005/06/15 00:34:08 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,6 +18,7 @@
 #include <ctype.h>
 #include <limits.h>
 #include <float.h>
+#include <time.h> 
 
 #include "access/hash.h"
 #include "libpq/pqformat.h"
@@ -724,7 +725,7 @@ timestamp_date(PG_FUNCTION_ARGS)
        if (TIMESTAMP_NOT_FINITE(timestamp))
                PG_RETURN_NULL();
 
-       if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) !=0)
+       if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) !=0)
                ereport(ERROR,
                                (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
                                 errmsg("timestamp out of range")));
@@ -767,7 +768,7 @@ timestamptz_date(PG_FUNCTION_ARGS)
        if (TIMESTAMP_NOT_FINITE(timestamp))
                PG_RETURN_NULL();
 
-       if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) !=0)
+       if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn, NULL) !=0)
                ereport(ERROR,
                                (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
                                 errmsg("timestamp out of range")));
@@ -1327,7 +1328,7 @@ timestamp_time(PG_FUNCTION_ARGS)
        if (TIMESTAMP_NOT_FINITE(timestamp))
                PG_RETURN_NULL();
 
-       if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) !=0)
+       if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) !=0)
                ereport(ERROR,
                                (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
                                 errmsg("timestamp out of range")));
@@ -1364,7 +1365,7 @@ timestamptz_time(PG_FUNCTION_ARGS)
        if (TIMESTAMP_NOT_FINITE(timestamp))
                PG_RETURN_NULL();
 
-       if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) !=0)
+       if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn, NULL) !=0)
                ereport(ERROR,
                                (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
                                 errmsg("timestamp out of range")));
@@ -2247,7 +2248,7 @@ timestamptz_timetz(PG_FUNCTION_ARGS)
        if (TIMESTAMP_NOT_FINITE(timestamp))
                PG_RETURN_NULL();
 
-       if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) !=0)
+       if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn, NULL) !=0)
                ereport(ERROR,
                                (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
                                 errmsg("timestamp out of range")));
@@ -2463,53 +2464,60 @@ timetz_part(PG_FUNCTION_ARGS)
 
 /* timetz_zone()
  * Encode time with time zone type with specified time zone.
+ * Applies DST rules as of the current date.
  */
 Datum
 timetz_zone(PG_FUNCTION_ARGS)
 {
        text       *zone = PG_GETARG_TEXT_P(0);
-       TimeTzADT  *time = PG_GETARG_TIMETZADT_P(1);
+       TimeTzADT  *t = PG_GETARG_TIMETZADT_P(1);
        TimeTzADT  *result;
        int                     tz;
-       int                     type,
-                               val;
-       char       *lowzone;
-
-       lowzone = downcase_truncate_identifier(VARDATA(zone),
-                                                                                  VARSIZE(zone) - VARHDRSZ,
-                                                                                  false);
-
-       type = DecodeSpecial(0, lowzone, &val);
+       char        tzname[TZ_STRLEN_MAX];
+       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);
+       memcpy(tzname,VARDATA(zone),len);
+       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();
+       }
 
-       result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
+       /* 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();
+       }
 
-       if (type == TZ || type == DTZ)
-       {
-               tz = val * 60;
+       result = (TimeTzADT *)palloc(sizeof(TimeTzADT));
+       
+       tz = -tm->tm_gmtoff;
 #ifdef HAVE_INT64_TIMESTAMP
-               result->time = time->time + (time->zone - tz) * USECS_PER_SEC;
-               while (result->time < INT64CONST(0))
-                       result->time += USECS_PER_DAY;
-               while (result->time >= USECS_PER_DAY)
-                       result->time -= USECS_PER_DAY;
+       result->time = t->time + (t->zone - tz) * USECS_PER_SEC;
+       while (result->time < INT64CONST(0))
+               result->time += USECS_PER_DAY;
+       while (result->time >= USECS_PER_DAY)
+               result->time -= USECS_PER_DAY;
 #else
-               result->time = time->time + (time->zone - tz);
-               while (result->time < 0)
-                       result->time += SECS_PER_DAY;
-               while (result->time >= SECS_PER_DAY)
-                       result->time -= SECS_PER_DAY;
+       result->time = t->time + (t->zone - tz);
+       while (result->time < 0)
+               result->time += SECS_PER_DAY;
+       while (result->time >= SECS_PER_DAY)
+               result->time -= SECS_PER_DAY;
 #endif
 
-               result->zone = tz;
-       }
-       else
-       {
-               ereport(ERROR,
-                               (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-                                errmsg("time zone \"%s\" not recognized", lowzone)));
-
-               PG_RETURN_NULL();
-       }
+       result->zone = tz;
 
        PG_RETURN_TIMETZADT_P(result);
 }      /* timetz_zone() */
index 68a73bbb6fc793866818e41bf8e6c6f08619ec9f..e4de64444eae73e631f6f4d069fa28aef825973f 100644 (file)
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------
  * formatting.c
  *
- * $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.87 2005/05/25 21:40:40 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.88 2005/06/15 00:34:08 momjian Exp $
  *
  *
  *      Portions Copyright (c) 1999-2005, PostgreSQL Global Development Group
@@ -2910,7 +2910,7 @@ timestamp_to_char(PG_FUNCTION_ARGS)
 
        ZERO_tmtc(&tmtc);
 
-       if (timestamp2tm(dt, NULL, tmtcTm(&tmtc), &tmtcFsec(&tmtc), NULL) != 0)
+       if (timestamp2tm(dt, NULL, tmtcTm(&tmtc), &tmtcFsec(&tmtc), NULL, NULL) != 0)
                ereport(ERROR,
                                (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
                                 errmsg("timestamp out of range")));
@@ -2935,7 +2935,7 @@ timestamptz_to_char(PG_FUNCTION_ARGS)
 
        ZERO_tmtc(&tmtc);
 
-       if (timestamp2tm(dt, &tz, tmtcTm(&tmtc), &tmtcFsec(&tmtc), &tmtcTzn(&tmtc)) != 0)
+       if (timestamp2tm(dt, &tz, tmtcTm(&tmtc), &tmtcFsec(&tmtc), &tmtcTzn(&tmtc), NULL) != 0)
                ereport(ERROR,
                                (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
                                 errmsg("timestamp out of range")));
index bebd3f9d3256096719094b43502e3cf8341cd2ef..d712d9f8b46e42b9118bd9cae39381b0894b8236 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/adt/nabstime.c,v 1.132 2005/05/26 02:04:13 neilc Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/adt/nabstime.c,v 1.133 2005/06/15 00:34:08 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -556,7 +556,7 @@ timestamp_abstime(PG_FUNCTION_ARGS)
                result = NOSTART_ABSTIME;
        else if (TIMESTAMP_IS_NOEND(timestamp))
                result = NOEND_ABSTIME;
-       else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) == 0)
+       else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0)
        {
                tz = DetermineLocalTimeZone(tm);
                result = tm2abstime(tm, tz);
@@ -632,7 +632,7 @@ timestamptz_abstime(PG_FUNCTION_ARGS)
                result = NOSTART_ABSTIME;
        else if (TIMESTAMP_IS_NOEND(timestamp))
                result = NOEND_ABSTIME;
-       else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) == 0)
+       else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0)
                result = tm2abstime(tm, 0);
        else
        {
index 37308d7451a769316f4040e65103a77744d0c899..035a422bfcc33361afb4ef2769e4107c434a7096 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.125 2005/06/14 21:04:40 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.126 2005/06/15 00:34:09 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -142,7 +142,7 @@ timestamp_out(PG_FUNCTION_ARGS)
 
        if (TIMESTAMP_NOT_FINITE(timestamp))
                EncodeSpecialTimestamp(timestamp, buf);
-       else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) == 0)
+       else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0)
                EncodeDateTime(tm, fsec, NULL, &tzn, DateStyle, buf);
        else
                ereport(ERROR,
@@ -178,7 +178,7 @@ timestamp_recv(PG_FUNCTION_ARGS)
        /* rangecheck: see if timestamp_out would like it */
        if (TIMESTAMP_NOT_FINITE(timestamp))
                 /* ok */ ;
-       else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) !=0)
+       else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) !=0)
                ereport(ERROR,
                                (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
                                 errmsg("timestamp out of range")));
@@ -381,7 +381,7 @@ timestamptz_out(PG_FUNCTION_ARGS)
 
        if (TIMESTAMP_NOT_FINITE(dt))
                EncodeSpecialTimestamp(dt, buf);
-       else if (timestamp2tm(dt, &tz, tm, &fsec, &tzn) == 0)
+       else if (timestamp2tm(dt, &tz, tm, &fsec, &tzn, NULL) == 0)
                EncodeDateTime(tm, fsec, &tz, &tzn, DateStyle, buf);
        else
                ereport(ERROR,
@@ -419,7 +419,7 @@ timestamptz_recv(PG_FUNCTION_ARGS)
        /* rangecheck: see if timestamptz_out would like it */
        if (TIMESTAMP_NOT_FINITE(timestamp))
                 /* ok */ ;
-       else if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) !=0)
+       else if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn, NULL) !=0)
                ereport(ERROR,
                                (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
                                 errmsg("timestamp out of range")));
@@ -984,9 +984,12 @@ dt2time(Timestamp jd, int *hour, int *min, int *sec, fsec_t *fsec)
  * Returns:
  *      0 on success
  *     -1 on out of range
+ *
+ * If attimezone is NULL, the global timezone (including possblly brute forced
+ * timezone) will be used.
  */
 int
-timestamp2tm(Timestamp dt, int *tzp, struct pg_tm * tm, fsec_t *fsec, char **tzn)
+timestamp2tm(Timestamp dt, int *tzp, struct pg_tm * tm, fsec_t *fsec, char **tzn, pg_tz *attimezone)
 {
        Timestamp date;
        Timestamp       time;
@@ -997,7 +1000,7 @@ timestamp2tm(Timestamp dt, int *tzp, struct pg_tm * tm, fsec_t *fsec, char **tzn
         * specified. Go ahead and rotate to the local time zone since we will
         * later bypass any calls which adjust the tm fields.
         */
-       if (HasCTZSet && (tzp != NULL))
+       if ((attimezone==NULL) && HasCTZSet && (tzp != NULL))
        {
 #ifdef HAVE_INT64_TIMESTAMP
                dt -= CTimeZone * USECS_PER_SEC;
@@ -1050,7 +1053,7 @@ timestamp2tm(Timestamp dt, int *tzp, struct pg_tm * tm, fsec_t *fsec, char **tzn
         * We have a brute force time zone per SQL99? Then use it without
         * change since we have already rotated to the time zone.
         */
-       if (HasCTZSet)
+       if ((attimezone==NULL) && HasCTZSet)
        {
                *tzp = CTimeZone;
                tm->tm_isdst = 0;
@@ -1081,7 +1084,7 @@ 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, global_timezone);
+               struct pg_tm *tx = pg_localtime(&utime, (attimezone!=NULL)?attimezone:global_timezone);
 
                tm->tm_year = tx->tm_year + 1900;
                tm->tm_mon = tx->tm_mon + 1;
@@ -1926,7 +1929,7 @@ timestamp_pl_interval(PG_FUNCTION_ARGS)
                                           *tm = &tt;
                        fsec_t          fsec;
 
-                       if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) !=0)
+                       if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) !=0)
                                ereport(ERROR,
                                                (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
                                                 errmsg("timestamp out of range")));
@@ -2005,7 +2008,7 @@ timestamptz_pl_interval(PG_FUNCTION_ARGS)
                                           *tm = &tt;
                        fsec_t          fsec;
 
-                       if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) !=0)
+                       if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn, NULL) !=0)
                                ereport(ERROR,
                                                (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
                                                 errmsg("timestamp out of range")));
@@ -2332,8 +2335,8 @@ timestamp_age(PG_FUNCTION_ARGS)
 
        result = (Interval *) palloc(sizeof(Interval));
 
-       if (timestamp2tm(dt1, NULL, tm1, &fsec1, NULL) == 0 &&
-               timestamp2tm(dt2, NULL, tm2, &fsec2, NULL) == 0)
+       if (timestamp2tm(dt1, NULL, tm1, &fsec1, NULL, NULL) == 0 &&
+               timestamp2tm(dt2, NULL, tm2, &fsec2, NULL, NULL) == 0)
        {
                fsec = (fsec1 - fsec2);
                tm->tm_sec = tm1->tm_sec - tm2->tm_sec;
@@ -2446,8 +2449,8 @@ timestamptz_age(PG_FUNCTION_ARGS)
 
        result = (Interval *) palloc(sizeof(Interval));
 
-       if (timestamp2tm(dt1, &tz1, tm1, &fsec1, &tzn) == 0 &&
-               timestamp2tm(dt2, &tz2, tm2, &fsec2, &tzn) == 0)
+       if (timestamp2tm(dt1, &tz1, tm1, &fsec1, &tzn, NULL) == 0 &&
+               timestamp2tm(dt2, &tz2, tm2, &fsec2, &tzn, NULL) == 0)
        {
                fsec = fsec1 - fsec2;
                tm->tm_sec = tm1->tm_sec - tm2->tm_sec;
@@ -2750,7 +2753,7 @@ timestamp_trunc(PG_FUNCTION_ARGS)
 
        if (type == UNITS)
        {
-               if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) !=0)
+               if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) !=0)
                        ereport(ERROR,
                                        (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
                                         errmsg("timestamp out of range")));
@@ -2881,7 +2884,7 @@ timestamptz_trunc(PG_FUNCTION_ARGS)
 
        if (type == UNITS)
        {
-               if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) !=0)
+               if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn, NULL) !=0)
                        ereport(ERROR,
                                        (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
                                         errmsg("timestamp out of range")));
@@ -3271,7 +3274,7 @@ timestamp_part(PG_FUNCTION_ARGS)
 
        if (type == UNITS)
        {
-               if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) !=0)
+               if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) !=0)
                        ereport(ERROR,
                                        (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
                                         errmsg("timestamp out of range")));
@@ -3405,7 +3408,7 @@ timestamp_part(PG_FUNCTION_ARGS)
                                         * convert to timestamptz to produce consistent
                                         * results
                                         */
-                                       if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) !=0)
+                                       if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) !=0)
                                                ereport(ERROR,
                                                   (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
                                                        errmsg("timestamp out of range")));
@@ -3425,7 +3428,7 @@ timestamp_part(PG_FUNCTION_ARGS)
                                        break;
                                }
                        case DTK_DOW:
-                               if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) !=0)
+                               if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) !=0)
                                        ereport(ERROR,
                                                        (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
                                                         errmsg("timestamp out of range")));
@@ -3433,7 +3436,7 @@ timestamp_part(PG_FUNCTION_ARGS)
                                break;
 
                        case DTK_DOY:
-                               if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) !=0)
+                               if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) !=0)
                                        ereport(ERROR,
                                                        (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
                                                         errmsg("timestamp out of range")));
@@ -3496,7 +3499,7 @@ timestamptz_part(PG_FUNCTION_ARGS)
 
        if (type == UNITS)
        {
-               if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) !=0)
+               if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn, NULL) !=0)
                        ereport(ERROR,
                                        (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
                                         errmsg("timestamp out of range")));
@@ -3631,7 +3634,7 @@ timestamptz_part(PG_FUNCTION_ARGS)
                                break;
 
                        case DTK_DOW:
-                               if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) !=0)
+                               if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn, NULL) !=0)
                                        ereport(ERROR,
                                                        (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
                                                         errmsg("timestamp out of range")));
@@ -3639,7 +3642,7 @@ timestamptz_part(PG_FUNCTION_ARGS)
                                break;
 
                        case DTK_DOY:
-                               if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) !=0)
+                               if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn, NULL) !=0)
                                        ereport(ERROR,
                                                        (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
                                                         errmsg("timestamp out of range")));
@@ -3815,38 +3818,40 @@ timestamp_zone(PG_FUNCTION_ARGS)
 {
        text       *zone = PG_GETARG_TEXT_P(0);
        Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
-       TimestampTz result;
+       Timestamp result;
        int                     tz;
-       int                     type,
-                               val;
-       char       *lowzone;
+       pg_tz      *tzp;
+       char        tzname[TZ_STRLEN_MAX+1];
+       int         len;
+       struct pg_tm tm;
+       fsec_t      fsec;
 
        if (TIMESTAMP_NOT_FINITE(timestamp))
                PG_RETURN_TIMESTAMPTZ(timestamp);
 
-       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
-       {
+       /* Find the specified timezone? */
+       len = (VARSIZE(zone)-VARHDRSZ>TZ_STRLEN_MAX)?TZ_STRLEN_MAX:(VARSIZE(zone)-VARHDRSZ);
+       memcpy(tzname,VARDATA(zone),len);
+       tzname[len] = 0;
+       tzp = pg_tzset(tzname);
+       if (!tzp) {
                ereport(ERROR,
                                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-                                errmsg("time zone \"%s\" not recognized",
-                                               lowzone)));
-
+                                errmsg("time zone \"%s\" not recognised",
+                                       tzname)));
                PG_RETURN_NULL();
        }
 
-       PG_RETURN_TIMESTAMPTZ(result);
+       /* Apply the timezone change */
+       if (timestamp2tm(timestamp, &tz, &tm, &fsec, NULL, tzp) != 0 ||
+           tm2timestamp(&tm, fsec, NULL, &result) != 0) {
+               ereport(ERROR,
+                               (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                                errmsg("could not convert to time zone \"%s\"",
+                                       tzname)));
+               PG_RETURN_NULL();
+       }
+       PG_RETURN_TIMESTAMPTZ(timestamp2timestamptz(result));
 }      /* timestamp_zone() */
 
 /* timestamp_izone()
@@ -3906,7 +3911,7 @@ timestamp2timestamptz(Timestamp timestamp)
 
        else
        {
-               if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) !=0)
+               if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) !=0)
                        ereport(ERROR,
                                        (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
                                         errmsg("timestamp out of range")));
@@ -3941,7 +3946,7 @@ timestamptz_timestamp(PG_FUNCTION_ARGS)
 
        else
        {
-               if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) !=0)
+               if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn, NULL) !=0)
                        ereport(ERROR,
                                        (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
                                         errmsg("timestamp out of range")));
@@ -3950,7 +3955,6 @@ timestamptz_timestamp(PG_FUNCTION_ARGS)
                                        (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
                                         errmsg("timestamp out of range")));
        }
-
        PG_RETURN_TIMESTAMP(result);
 }
 
@@ -3966,31 +3970,34 @@ timestamptz_zone(PG_FUNCTION_ARGS)
        Timestamp       result;
 
        int                     tz;
-       int                     type,
-                               val;
-       char       *lowzone;
+       pg_tz      *tzp;
+       char        tzname[TZ_STRLEN_MAX];
+       int         len;
+       struct pg_tm tm;
+       fsec_t      fsec = 0;
 
        if (TIMESTAMP_NOT_FINITE(timestamp))
                PG_RETURN_NULL();
 
-       lowzone = downcase_truncate_identifier(VARDATA(zone),
-                                                                                  VARSIZE(zone) - VARHDRSZ,
-                                                                                  false);
-
-       type = DecodeSpecial(0, lowzone, &val);
+       /* Find the specified zone */
+       len = (VARSIZE(zone)-VARHDRSZ>TZ_STRLEN_MAX)?TZ_STRLEN_MAX:(VARSIZE(zone)-VARHDRSZ);
+       memcpy(tzname,VARDATA(zone),len);
+       tzname[len] = 0;
+       tzp = pg_tzset(tzname);
 
-       if (type == TZ || type == DTZ)
-       {
-               tz = val * 60;
+       if (!tzp) {
+               ereport(ERROR,
+                       (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                        errmsg("time zone \"%s\" not recognized", tzname)));
 
-               result = dt2local(timestamp, tz);
+               PG_RETURN_NULL();
        }
-       else
-       {
-               ereport(ERROR,
-                               (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-                                errmsg("time zone \"%s\" not recognized", lowzone)));
 
+       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();
        }
 
index b3322234e19ce26939d09f6c4ab9f7a0ef824151..c36a871fb33c6aca3156d836ffcb9d5448a93e76 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/include/pgtime.h,v 1.7 2005/04/19 03:13:59 momjian Exp $
+ *       $PostgreSQL: pgsql/src/include/pgtime.h,v 1.8 2005/06/15 00:34:09 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -57,4 +57,8 @@ extern bool tz_acceptable(pg_tz *tz);
 extern const char *pg_get_timezone_name(pg_tz *tz);
 
 extern pg_tz *global_timezone;
+
+/* Maximum length of a timezone name */
+#define TZ_STRLEN_MAX 255
+
 #endif   /* _PGTIME_H */
index 782b75ec8dfd5e01d45623e1bd9d36687ab808c5..7475dacbe7c0532cbff949076f813bdeb71f2cd6 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/timestamp.h,v 1.44 2005/06/14 21:04:42 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/utils/timestamp.h,v 1.45 2005/06/15 00:34:10 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -264,7 +264,7 @@ extern TimestampTz StartTime;
 
 extern int     tm2timestamp(struct pg_tm * tm, fsec_t fsec, int *tzp, Timestamp *dt);
 extern int timestamp2tm(Timestamp dt, int *tzp, struct pg_tm * tm,
-                        fsec_t *fsec, char **tzn);
+                        fsec_t *fsec, char **tzn, pg_tz *attimezone);
 extern void dt2time(Timestamp dt, int *hour, int *min, int *sec, fsec_t *fsec);
 
 extern int     interval2tm(Interval span, struct pg_tm * tm, fsec_t *fsec);
index e325dec48328e3125f3a9cd49309956c8b2cd5ad..a6e6bbf97f61a965376208fdfc92821b51fc6e52 100644 (file)
@@ -9,7 +9,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/timezone/pgtz.h,v 1.11 2005/04/19 03:13:59 momjian Exp $
+ *       $PostgreSQL: pgsql/src/timezone/pgtz.h,v 1.12 2005/06/15 00:34:11 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,8 +18,6 @@
 
 #include "tzfile.h"
 
-#define TZ_STRLEN_MAX 255
-
 extern char *pg_TZDIR(void);
 
 #define BIGGEST(a, b)  (((a) > (b)) ? (a) : (b))