]> granicus.if.org Git - postgresql/commitdiff
Fix up some problems in handling of zic-style time zone names in datetime
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 17 Oct 2006 21:03:21 +0000 (21:03 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 17 Oct 2006 21:03:21 +0000 (21:03 +0000)
input routines.  Remove the former "DecodePosixTimezone" function in favor of
letting the zic code handle POSIX-style zone specs (see tzparse()).  In
particular this means that "PST+3" now means the same as "-03", whereas it
used to mean "-11" --- the zone abbreviation is effectively just a noise word
in this syntax.  Make sure that all named and POSIX-style zone names will be
parsed as a single token.  Fix long-standing bogosities in printing and input
of fractional-hour timezone offsets (since the tzparse() code will accept
these, we'd better make 'em work).  Also correct an error in the original
coding of the zic-zone-name patch: in "timestamp without time zone" input,
zone names are supposed to be allowed but ignored, but the coding was such
that the zone changed the interpretation anyway.

doc/src/sgml/datatype.sgml
doc/src/sgml/datetime.sgml
src/backend/utils/adt/datetime.c
src/test/regress/expected/horology.out
src/test/regress/expected/timestamp.out
src/test/regress/expected/timestamptz.out
src/test/regress/sql/timestamp.sql
src/test/regress/sql/timestamptz.sql

index 10da8d8d7b477fa7939159564c60edd98a4592ba..2cc9770f65e71abd985d6c1b98da83081bc59326 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/datatype.sgml,v 1.177 2006/10/16 19:58:26 tgl Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/datatype.sgml,v 1.178 2006/10/17 21:03:20 tgl Exp $ -->
 
  <chapter id="datatype">
   <title id="datatype-title">Data Types</title>
@@ -1675,12 +1675,16 @@ SELECT b, char_length(b) FROM test2;
         <tbody>
          <row>
           <entry><literal>PST</literal></entry>
-          <entry>Pacific Standard Time</entry>
+          <entry>Abbreviation (for Pacific Standard Time)</entry>
          </row>
          <row>
           <entry><literal>America/New_York</literal></entry>
           <entry>Full time zone name</entry>
          </row>
+         <row>
+          <entry><literal>PST8PDT</literal></entry>
+          <entry>POSIX-style time zone specification</entry>
+         </row>
          <row>
           <entry><literal>-8:00</literal></entry>
           <entry>ISO-8601 offset for PST</entry>
@@ -2183,7 +2187,7 @@ January 8 04:05:06 1999 PST
       <listitem>
        <para>
         In addition to the timezone names and abbreviations,
-        <productname>PostgreSQL</productname> will accept time zone
+        <productname>PostgreSQL</productname> will accept POSIX-style time zone
         specifications of the form <replaceable>STD</><replaceable>offset</> or
         <replaceable>STD</><replaceable>offset</><replaceable>DST</>, where
         <replaceable>STD</> is a zone abbreviation, <replaceable>offset</> is a
@@ -2220,12 +2224,6 @@ January 8 04:05:06 1999 PST
      prior to 8.2, which were case-sensitive in some contexts and not others.)
     </para>
 
-    <para>
-     Note that timezone names are <emphasis>not</> used for date/time output
-     &mdash; all supported output formats use numeric timezone displays to
-     avoid ambiguity.
-    </para>
-
     <para>
      Neither full names nor abbreviations are hard-wired into the server;
      they are obtained from configuration files stored under
index b275ff803e0aabdadd43797e5095be40d5299e1b..3d80d254f03c5298e009f15fd9132b7da9dd8fe5 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/datetime.sgml,v 2.54 2006/09/22 16:35:55 tgl Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/datetime.sgml,v 2.55 2006/10/17 21:03:20 tgl Exp $ -->
 
  <appendix id="datetime-appendix">
   <title>Date/Time Support</title>
@@ -46,9 +46,9 @@
        <para>
         If the numeric token contains a dash (<literal>-</>), slash
         (<literal>/</>), or two or more dots (<literal>.</>), this is
-        a date string which may have a text month. In case of a slash
-        (<literal>/</>) it can also be a full time zone name like
-        <literal>America/New_York</>.
+        a date string which may have a text month.  If a date token has
+        already been seen, it is instead interpreted as a time zone
+        name (e.g., <literal>America/New_York</>).
        </para>
       </step>
 
@@ -64,7 +64,7 @@
       <step>
        <para>
         If the token starts with a plus (<literal>+</>) or minus
-        (<literal>-</>), then it is either a time zone or a special
+        (<literal>-</>), then it is either a numeric time zone or a special
         field.
        </para>
       </step>
 
     <step>
      <para>
-      If the token is a text string, match up with possible strings.
+      If the token is a text string, match up with possible strings:
      </para>
      
      <substeps>
       <step>
        <para>
-        Do a binary-search table lookup for the token
-        as either a special string (e.g., <literal>today</literal>),
-        day (e.g., <literal>Thursday</literal>),
-        month (e.g., <literal>January</literal>),
-        or noise word (e.g., <literal>at</literal>, <literal>on</literal>).
-       </para>
-
-       <para>
-        Set field values and bit mask for fields.
-        For example, set year, month, day for <literal>today</literal>,
-        and additionally hour, minute, second for <literal>now</literal>.
+        Do a binary-search table lookup for the token as a time zone
+        abbreviation.
        </para>
       </step>
       
       <step>
        <para>
         If not found, do a similar binary-search table lookup to match
-        the token with a time zone.
+        the token as either a special string (e.g., <literal>today</literal>),
+        day (e.g., <literal>Thursday</literal>),
+        month (e.g., <literal>January</literal>),
+        or noise word (e.g., <literal>at</literal>, <literal>on</literal>).
        </para>
       </step>
 
index fac642ddc97935f93de303a08f6ede9b423a0d99..cfb29dce5687742fbe18b93b22d688b1f418dff0 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.172 2006/10/04 00:29:58 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.173 2006/10/17 21:03:21 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -39,8 +39,6 @@ static int DecodeNumberField(int len, char *str,
 static int DecodeTime(char *str, int fmask, int *tmask,
                   struct pg_tm * tm, fsec_t *fsec);
 static int     DecodeTimezone(char *str, int *tzp);
-static int     DecodePosixTimezone(char *str, int *tzp);
-static int     DecodeZicTimezone(char *str, int *tzp, struct pg_tm * tm);
 static const datetkn *datebsearch(const char *key, const datetkn *base, int nel);
 static int     DecodeDate(char *str, int fmask, int *tmask, struct pg_tm * tm);
 static void TrimTrailingZeros(char *str);
@@ -173,7 +171,7 @@ static const datetkn datetktbl[] = {
        {"wednesday", DOW, 3},
        {"weds", DOW, 3},
        {"y", UNITS, DTK_YEAR},         /* "year" for ISO input */
-       {YESTERDAY, RESERV, DTK_YESTERDAY}, /* yesterday midnight */
+       {YESTERDAY, RESERV, DTK_YESTERDAY}      /* yesterday midnight */
 };
 
 static int     szdatetktbl = sizeof datetktbl / sizeof datetktbl[0];
@@ -243,7 +241,7 @@ static datetkn deltatktbl[] = {
        {DYEAR, UNITS, DTK_YEAR},       /* "year" relative */
        {"years", UNITS, DTK_YEAR}, /* "years" relative */
        {"yr", UNITS, DTK_YEAR},        /* "year" relative */
-       {"yrs", UNITS, DTK_YEAR},       /* "years" relative */
+       {"yrs", UNITS, DTK_YEAR}        /* "years" relative */
 };
 
 static int     szdeltatktbl = sizeof deltatktbl / sizeof deltatktbl[0];
@@ -427,14 +425,14 @@ TrimTrailingZeros(char *str)
  *     DTK_NUMBER - digits and (possibly) a decimal point
  *     DTK_DATE - digits and two delimiters, or digits and text
  *     DTK_TIME - digits, colon delimiters, and possibly a decimal point
- *     DTK_STRING - text (no digits)
+ *     DTK_STRING - text (no digits or punctuation)
  *     DTK_SPECIAL - leading "+" or "-" followed by text
- *     DTK_TZ - leading "+" or "-" followed by digits
+ *     DTK_TZ - leading "+" or "-" followed by digits (also eats ':' or '.')
  *
  * Note that some field types can hold unexpected items:
  *     DTK_NUMBER can hold date fields (yy.ddd)
  *     DTK_STRING can hold months (January) and time zones (PST)
- *     DTK_DATE can hold Posix time zones (GMT-8)
+ *     DTK_DATE can hold time zone names (America/New_York, GMT-8)
  */
 int
 ParseDateTime(const char *timestr, char *workbuf, size_t buflen,
@@ -546,46 +544,42 @@ ParseDateTime(const char *timestr, char *workbuf, size_t buflen,
                 */
                else if (isalpha((unsigned char) *cp))
                {
+                       bool    is_date;
+
                        ftype[nf] = DTK_STRING;
                        APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
                        while (isalpha((unsigned char) *cp))
                                APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
 
                        /*
-                        * Full date string with leading text month? Could also be a POSIX
-                        * time zone...
+                        * Dates can have embedded '-', '/', or '.' separators.  It could
+                        * also be a timezone name containing embedded '/', '+', '-',
+                        * '_', or ':' (but '_' or ':' can't be the first punctuation).
+                        * If the next character is a digit or '+', we need to check
+                        * whether what we have so far is a recognized non-timezone
+                        * keyword --- if so, don't believe that this is the start of
+                        * a timezone.
                         */
+                       is_date = false;
                        if (*cp == '-' || *cp == '/' || *cp == '.')
+                               is_date = true;
+                       else if (*cp == '+' || isdigit((unsigned char) *cp))
                        {
-                               char            delim = *cp;
-
-                               if (*cp == '/')
-                               {
-                                       ftype[nf] = DTK_TZ;
-
-                                       /*
-                                        * set the first character of the region to upper case
-                                        * again
-                                        */
-                                       field[nf][0] = pg_toupper((unsigned char) field[nf][0]);
-
-                                       /*
-                                        * we have seen "Region/" of a POSIX timezone, continue to
-                                        * read the City part
-                                        */
-                                       do
-                                       {
-                                               APPEND_CHAR(bufp, bufend, *cp++);
-                                               /* there is for example America/New_York */
-                                       } while (isalpha((unsigned char) *cp) || *cp == '_');
-                               }
-                               else
+                               *bufp = '\0';   /* null-terminate current field value */
+                               /* we need search only the core token table, not TZ names */
+                               if (datebsearch(field[nf], datetktbl, szdatetktbl) == NULL)
+                                       is_date = true;
+                       }
+                       if (is_date)
+                       {
+                               ftype[nf] = DTK_DATE;
+                               do
                                {
-                                       ftype[nf] = DTK_DATE;
-                                       APPEND_CHAR(bufp, bufend, *cp++);
-                               }
-                               while (isdigit((unsigned char) *cp) || *cp == delim)
-                                       APPEND_CHAR(bufp, bufend, *cp++);
+                                       APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
+                               } while (*cp == '+' || *cp == '-' ||
+                                                *cp == '/' || *cp == '_' ||
+                                                *cp == '.' || *cp == ':' ||
+                                                isalnum((unsigned char) *cp));
                        }
                }
                /* sign? then special or numeric timezone */
@@ -674,7 +668,7 @@ DecodeDateTime(char **field, int *ftype, int nf,
        bool            haveTextMonth = FALSE;
        int                     is2digits = FALSE;
        int                     bc = FALSE;
-       int                     zicTzFnum = -1;
+       pg_tz      *namedTz = NULL;
 
        /*
         * We'll insist on at least all of the date fields, but initialize the
@@ -724,8 +718,8 @@ DecodeDateTime(char **field, int *ftype, int nf,
                                        break;
                                }
                                /***
-                                * Already have a date? Then this might be a POSIX time
-                                * zone with an embedded dash (e.g. "PST-3" == "EST") or
+                                * Already have a date? Then this might be a time zone name
+                                * with embedded punctuation (e.g. "America/New_York") or
                                 * a run-together time with trailing time zone (e.g. hhmmss-zz).
                                 * - thomas 2001-12-25
                                 ***/
@@ -774,7 +768,6 @@ DecodeDateTime(char **field, int *ftype, int nf,
                                                                                                  fsec, &is2digits);
                                                if (dterr < 0)
                                                        return dterr;
-                                               ftype[i] = dterr;
 
                                                /*
                                                 * modify tmask after returning from
@@ -784,11 +777,20 @@ DecodeDateTime(char **field, int *ftype, int nf,
                                        }
                                        else
                                        {
-                                               dterr = DecodePosixTimezone(field[i], tzp);
-                                               if (dterr)
-                                                       return dterr;
-
-                                               ftype[i] = DTK_TZ;
+                                               namedTz = pg_tzset(field[i]);
+                                               if (!namedTz)
+                                               {
+                                                       /*
+                                                        * We should return an error code instead of
+                                                        * ereport'ing directly, but then there is no
+                                                        * way to report the bad time zone name.
+                                                        */
+                                                       ereport(ERROR,
+                                                                       (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                                                                        errmsg("time zone \"%s\" not recognized",
+                                                                                       field[i])));
+                                               }
+                                               /* we'll apply the zone setting below */
                                                tmask = DTK_M(TZ);
                                        }
                                }
@@ -822,34 +824,11 @@ DecodeDateTime(char **field, int *ftype, int nf,
                                        if (tzp == NULL)
                                                return DTERR_BAD_FORMAT;
 
-                                       if (strchr(field[i], '/') != NULL)
-                                       {
-                                               /* remember to apply the timezone at the end */
-                                               zicTzFnum = i;
-                                               tmask = DTK_M(TZ);
-                                               break;
-                                       }
-                                       else
-                                               dterr = DecodeTimezone(field[i], &tz);
+                                       dterr = DecodeTimezone(field[i], &tz);
                                        if (dterr)
                                                return dterr;
-
-                                       /*
-                                        * Already have a time zone? Then maybe this is the second
-                                        * field of a POSIX time: EST+3 (equivalent to PST)
-                                        */
-                                       if (i > 0 && (fmask & DTK_M(TZ)) != 0 &&
-                                               ftype[i - 1] == DTK_TZ &&
-                                               isalpha((unsigned char) *field[i - 1]))
-                                       {
-                                               *tzp -= tz;
-                                               tmask = 0;
-                                       }
-                                       else
-                                       {
-                                               *tzp = tz;
-                                               tmask = DTK_M(TZ);
-                                       }
+                                       *tzp = tz;
+                                       tmask = DTK_M(TZ);
                                }
                                break;
 
@@ -988,8 +967,6 @@ DecodeDateTime(char **field, int *ftype, int nf,
                                                                                                          fsec, &is2digits);
                                                        if (dterr < 0)
                                                                return dterr;
-                                                       ftype[i] = dterr;
-
                                                        if (tmask != DTK_TIME_M)
                                                                return DTERR_BAD_FORMAT;
                                                        break;
@@ -1030,7 +1007,6 @@ DecodeDateTime(char **field, int *ftype, int nf,
                                                                                                  fsec, &is2digits);
                                                if (dterr < 0)
                                                        return dterr;
-                                               ftype[i] = dterr;
                                        }
                                        else if (flen > 4)
                                        {
@@ -1039,7 +1015,6 @@ DecodeDateTime(char **field, int *ftype, int nf,
                                                                                                  fsec, &is2digits);
                                                if (dterr < 0)
                                                        return dterr;
-                                               ftype[i] = dterr;
                                        }
                                        /* otherwise it is a single date/time field... */
                                        else
@@ -1168,7 +1143,6 @@ DecodeDateTime(char **field, int *ftype, int nf,
                                                if (tzp == NULL)
                                                        return DTERR_BAD_FORMAT;
                                                *tzp = val * MINS_PER_HOUR;
-                                               ftype[i] = DTK_TZ;
                                                break;
 
                                        case TZ:
@@ -1176,7 +1150,6 @@ DecodeDateTime(char **field, int *ftype, int nf,
                                                if (tzp == NULL)
                                                        return DTERR_BAD_FORMAT;
                                                *tzp = val * MINS_PER_HOUR;
-                                               ftype[i] = DTK_TZ;
                                                break;
 
                                        case IGNORE_DTF:
@@ -1308,18 +1281,17 @@ DecodeDateTime(char **field, int *ftype, int nf,
                if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
                        return DTERR_FIELD_OVERFLOW;
 
-               if (zicTzFnum != -1)
+               /*
+                * If we had a full timezone spec, compute the offset (we could not
+                * do it before, because we need the date to resolve DST status).
+                */
+               if (namedTz != NULL)
                {
-                       Datum           tsTz;
-                       Timestamp       timestamp;
-
-                       tm2timestamp(tm, *fsec, NULL, &timestamp);
-                       tsTz = DirectFunctionCall2(timestamp_zone,
-                                                                          DirectFunctionCall1(textin,
-                                                                                 CStringGetDatum(field[zicTzFnum])),
-                                                                          TimestampGetDatum(timestamp));
-                       timestamp2tm(DatumGetTimestampTz(tsTz), tzp, tm, fsec, NULL, NULL);
-                       fmask &= ~DTK_M(TZ);
+                       /* daylight savings time modifier disallowed with full TZ */
+                       if (fmask & DTK_M(DTZMOD))
+                               return DTERR_BAD_FORMAT;
+
+                       *tzp = DetermineTimeZoneOffset(tm, namedTz);
                }
 
                /* timezone not specified? then find local timezone if possible */
@@ -1492,6 +1464,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
        int                     dterr;
        int                     is2digits = FALSE;
        int                     mer = HR24;
+       pg_tz      *namedTz = NULL;
 
        *dtype = DTK_TIME;
        tm->tm_hour = 0;
@@ -1567,10 +1540,20 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
                                        }
                                        else
                                        {
-                                               dterr = DecodePosixTimezone(field[i], tzp);
-                                               if (dterr)
-                                                       return dterr;
-
+                                               namedTz = pg_tzset(field[i]);
+                                               if (!namedTz)
+                                               {
+                                                       /*
+                                                        * We should return an error code instead of
+                                                        * ereport'ing directly, but then there is no
+                                                        * way to report the bad time zone name.
+                                                        */
+                                                       ereport(ERROR,
+                                                                       (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                                                                        errmsg("time zone \"%s\" not recognized",
+                                                                                       field[i])));
+                                               }
+                                               /* we'll apply the zone setting below */
                                                ftype[i] = DTK_TZ;
                                                tmask = DTK_M(TZ);
                                        }
@@ -1591,34 +1574,11 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
                                        if (tzp == NULL)
                                                return DTERR_BAD_FORMAT;
 
-                                       if (strchr(field[i], '/') != NULL)
-                                       {
-                                               /* a date has to be specified */
-                                               if ((fmask & DTK_DATE_M) != DTK_DATE_M)
-                                                       return DTERR_BAD_FORMAT;
-                                               dterr = DecodeZicTimezone(field[i], &tz, tm);
-                                       }
-                                       else
-                                               dterr = DecodeTimezone(field[i], &tz);
+                                       dterr = DecodeTimezone(field[i], &tz);
                                        if (dterr)
                                                return dterr;
-
-                                       /*
-                                        * Already have a time zone? Then maybe this is the second
-                                        * field of a POSIX time: EST+3 (equivalent to PST)
-                                        */
-                                       if (i > 0 && (fmask & DTK_M(TZ)) != 0 &&
-                                               ftype[i - 1] == DTK_TZ &&
-                                               isalpha((unsigned char) *field[i - 1]))
-                                       {
-                                               *tzp -= tz;
-                                               tmask = 0;
-                                       }
-                                       else
-                                       {
-                                               *tzp = tz;
-                                               tmask = DTK_M(TZ);
-                                       }
+                                       *tzp = tz;
+                                       tmask = DTK_M(TZ);
                                }
                                break;
 
@@ -1974,21 +1934,38 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
 
        if (tm->tm_hour < 0 || tm->tm_min < 0 || tm->tm_min > 59 ||
                tm->tm_sec < 0 || tm->tm_sec > 60 || tm->tm_hour > 24 ||
-       /* test for > 24:00:00 */
-               (tm->tm_hour == 24 && (tm->tm_min > 0 || tm->tm_sec > 0 ||
+               /* test for > 24:00:00 */
 #ifdef HAVE_INT64_TIMESTAMP
+               (tm->tm_hour == 24 && (tm->tm_min > 0 || tm->tm_sec > 0 ||
                                                           *fsec > INT64CONST(0))) ||
-               *fsec < INT64CONST(0) || *fsec >= USECS_PER_SEC)
-               return DTERR_FIELD_OVERFLOW;
+               *fsec < INT64CONST(0) || *fsec >= USECS_PER_SEC
 #else
+               (tm->tm_hour == 24 && (tm->tm_min > 0 || tm->tm_sec > 0 ||
                                                           *fsec > 0)) ||
-               *fsec < 0 || *fsec >= 1)
-               return DTERR_FIELD_OVERFLOW;
+               *fsec < 0 || *fsec >= 1
 #endif
+               )
+               return DTERR_FIELD_OVERFLOW;
 
        if ((fmask & DTK_TIME_M) != DTK_TIME_M)
                return DTERR_BAD_FORMAT;
 
+       /*
+        * If we had a full timezone spec, compute the offset (we could not
+        * do it before, because we need the date to resolve DST status).
+        */
+       if (namedTz != NULL)
+       {
+               /* a date has to be specified */
+               if ((fmask & DTK_DATE_M) != DTK_DATE_M)
+                       return DTERR_BAD_FORMAT;
+               /* daylight savings time modifier disallowed with full TZ */
+               if (fmask & DTK_M(DTZMOD))
+                       return DTERR_BAD_FORMAT;
+
+               *tzp = DetermineTimeZoneOffset(tm, namedTz);
+       }
+
        /* timezone not specified? then find local timezone if possible */
        if (tzp != NULL && !(fmask & DTK_M(TZ)))
        {
@@ -2548,7 +2525,8 @@ DecodeTimezone(char *str, int *tzp)
 {
        int                     tz;
        int                     hr,
-                               min;
+                               min,
+                               sec = 0;
        char       *cp;
 
        /* leading character must be "+" or "-" */
@@ -2567,22 +2545,32 @@ DecodeTimezone(char *str, int *tzp)
                min = strtol(cp + 1, &cp, 10);
                if (errno == ERANGE)
                        return DTERR_TZDISP_OVERFLOW;
+               if (*cp == ':')
+               {
+                       errno = 0;
+                       sec = strtol(cp + 1, &cp, 10);
+                       if (errno == ERANGE)
+                               return DTERR_TZDISP_OVERFLOW;
+               }
        }
        /* otherwise, might have run things together... */
        else if (*cp == '\0' && strlen(str) > 3)
        {
                min = hr % 100;
                hr = hr / 100;
+               /* we could, but don't, support a run-together hhmmss format */
        }
        else
                min = 0;
 
-       if (hr < 0 || hr > 13)
+       if (hr < 0 || hr > 14)
                return DTERR_TZDISP_OVERFLOW;
        if (min < 0 || min >= 60)
                return DTERR_TZDISP_OVERFLOW;
+       if (sec < 0 || sec >= 60)
+               return DTERR_TZDISP_OVERFLOW;
 
-       tz = (hr * MINS_PER_HOUR + min) * SECS_PER_MINUTE;
+       tz = (hr * MINS_PER_HOUR + min) * SECS_PER_MINUTE + sec;
        if (*str == '-')
                tz = -tz;
 
@@ -2594,75 +2582,6 @@ DecodeTimezone(char *str, int *tzp)
        return 0;
 }
 
-
-/* DecodePosixTimezone()
- * Interpret string as a POSIX-compatible timezone:
- *     PST-hh:mm
- *     PST+h
- *     PST
- * - thomas 2000-03-15
- *
- * Return 0 if okay (and set *tzp), a DTERR code if not okay.
- */
-static int
-DecodePosixTimezone(char *str, int *tzp)
-{
-       int                     val,
-                               tz;
-       int                     type;
-       int                     dterr;
-       char       *cp;
-       char            delim;
-
-       /* advance over name part */
-       cp = str;
-       while (*cp && isalpha((unsigned char) *cp))
-               cp++;
-
-       /* decode offset, if present */
-       if (*cp)
-       {
-               dterr = DecodeTimezone(cp, &tz);
-               if (dterr)
-                       return dterr;
-       }
-       else
-               tz = 0;
-
-       /* decode name part.  We must temporarily scribble on the input! */
-       delim = *cp;
-       *cp = '\0';
-       type = DecodeSpecial(MAXDATEFIELDS - 1, str, &val);
-       *cp = delim;
-
-       switch (type)
-       {
-               case DTZ:
-               case TZ:
-                       *tzp = (val * MINS_PER_HOUR) - tz;
-                       break;
-
-               default:
-                       return DTERR_BAD_FORMAT;
-       }
-
-       return 0;
-}
-
-static int
-DecodeZicTimezone(char *str, int *tzp, struct pg_tm * tm)
-{
-       struct pg_tz *tz;
-
-       tz = pg_tzset(str);
-       if (!tz)
-               return DTERR_BAD_FORMAT;
-
-       *tzp = DetermineTimeZoneOffset(tm, tz);
-
-       return 0;
-}
-
 /* DecodeSpecial()
  * Decode text string using lookup table.
  *
@@ -3194,6 +3113,33 @@ datebsearch(const char *key, const datetkn *base, int nel)
        return NULL;
 }
 
+/* EncodeTimezone()
+ *             Append representation of a numeric timezone offset to str.
+ */
+static void
+EncodeTimezone(char *str, int tz)
+{
+       int                     hour,
+                               min,
+                               sec;
+
+       sec = abs(tz);
+       min = sec / SECS_PER_MINUTE;
+       sec -= min * SECS_PER_MINUTE;
+       hour = min / MINS_PER_HOUR;
+       min -= hour * MINS_PER_HOUR;
+
+       str += strlen(str);
+       /* TZ is negated compared to sign we wish to display ... */
+       *str++ = (tz <= 0 ? '+' : '-');
+
+       if (sec != 0)
+               sprintf(str, "%02d:%02d:%02d", hour, min, sec);
+       else if (min != 0)
+               sprintf(str, "%02d:%02d", hour, min);
+       else
+               sprintf(str, "%02d", hour);
+}
 
 /* EncodeDateOnly()
  * Encode date as local time.
@@ -3284,14 +3230,7 @@ EncodeTimeOnly(struct pg_tm * tm, fsec_t fsec, int *tzp, int style, char *str)
                sprintf(str + strlen(str), ":%02d", tm->tm_sec);
 
        if (tzp != NULL)
-       {
-               int                     hour,
-                                       min;
-
-               hour = -(*tzp / SECS_PER_HOUR);
-               min = (abs(*tzp) / MINS_PER_HOUR) % MINS_PER_HOUR;
-               sprintf(str + strlen(str), (min != 0) ? "%+03d:%02d" : "%+03d", hour, min);
-       }
+               EncodeTimezone(str, *tzp);
 
        return TRUE;
 }      /* EncodeTimeOnly() */
@@ -3311,9 +3250,7 @@ EncodeTimeOnly(struct pg_tm * tm, fsec_t fsec, int *tzp, int style, char *str)
 int
 EncodeDateTime(struct pg_tm * tm, fsec_t fsec, int *tzp, char **tzn, int style, char *str)
 {
-       int                     day,
-                               hour,
-                               min;
+       int                     day;
 
        /*
         * Why are we checking only the month field? Change this to an assert...
@@ -3360,11 +3297,7 @@ EncodeDateTime(struct pg_tm * tm, fsec_t fsec, int *tzp, char **tzn, int style,
                         * a valid time zone translation.
                         */
                        if (tzp != NULL && tm->tm_isdst >= 0)
-                       {
-                               hour = -(*tzp / SECS_PER_HOUR);
-                               min = (abs(*tzp) / MINS_PER_HOUR) % MINS_PER_HOUR;
-                               sprintf(str + strlen(str), (min != 0) ? "%+03d:%02d" : "%+03d", hour, min);
-                       }
+                               EncodeTimezone(str, *tzp);
 
                        if (tm->tm_year <= 0)
                                sprintf(str + strlen(str), " BC");
@@ -3410,11 +3343,7 @@ EncodeDateTime(struct pg_tm * tm, fsec_t fsec, int *tzp, char **tzn, int style,
                                if (*tzn != NULL)
                                        sprintf(str + strlen(str), " %.*s", MAXTZLEN, *tzn);
                                else
-                               {
-                                       hour = -(*tzp / SECS_PER_HOUR);
-                                       min = (abs(*tzp) / MINS_PER_HOUR) % MINS_PER_HOUR;
-                                       sprintf(str + strlen(str), (min != 0) ? "%+03d:%02d" : "%+03d", hour, min);
-                               }
+                                       EncodeTimezone(str, *tzp);
                        }
 
                        if (tm->tm_year <= 0)
@@ -3458,11 +3387,7 @@ EncodeDateTime(struct pg_tm * tm, fsec_t fsec, int *tzp, char **tzn, int style,
                                if (*tzn != NULL)
                                        sprintf(str + strlen(str), " %.*s", MAXTZLEN, *tzn);
                                else
-                               {
-                                       hour = -(*tzp / SECS_PER_HOUR);
-                                       min = (abs(*tzp) / MINS_PER_HOUR) % MINS_PER_HOUR;
-                                       sprintf(str + strlen(str), (min != 0) ? "%+03d:%02d" : "%+03d", hour, min);
-                               }
+                                       EncodeTimezone(str, *tzp);
                        }
 
                        if (tm->tm_year <= 0)
@@ -3524,9 +3449,8 @@ EncodeDateTime(struct pg_tm * tm, fsec_t fsec, int *tzp, char **tzn, int style,
                                         * avoid formatting something which would be rejected by
                                         * the date/time parser later. - thomas 2001-10-19
                                         */
-                                       hour = -(*tzp / SECS_PER_HOUR);
-                                       min = (abs(*tzp) / MINS_PER_HOUR) % MINS_PER_HOUR;
-                                       sprintf(str + strlen(str), (min != 0) ? " %+03d:%02d" : " %+03d", hour, min);
+                                       sprintf(str + strlen(str), " ");
+                                       EncodeTimezone(str, *tzp);
                                }
                        }
 
index 15b397c74f2b92e4e8a9291b0549ae7e43d505d7..3aa8e3714bfca3f49b3523cb451077b3e37d5fae 100644 (file)
@@ -448,7 +448,7 @@ SELECT '' AS "64", d1 + interval '1 year' AS one_year FROM TIMESTAMP_TBL;
     | Tue Feb 10 17:32:01 1998
     | Tue Feb 10 17:32:01 1998
     | Tue Feb 10 17:32:01 1998
-    | Tue Feb 10 14:32:01 1998
+    | Tue Feb 10 17:32:01 1998
     | Wed Jun 10 18:32:01 1998
     | Tue Feb 10 17:32:01 1998
     | Wed Feb 11 17:32:01 1998
@@ -518,7 +518,7 @@ SELECT '' AS "64", d1 - interval '1 year' AS one_year FROM TIMESTAMP_TBL;
     | Sat Feb 10 17:32:01 1996
     | Sat Feb 10 17:32:01 1996
     | Sat Feb 10 17:32:01 1996
-    | Sat Feb 10 14:32:01 1996
+    | Sat Feb 10 17:32:01 1996
     | Mon Jun 10 18:32:01 1996
     | Sat Feb 10 17:32:01 1996
     | Sun Feb 11 17:32:01 1996
@@ -936,8 +936,8 @@ SELECT t.d1 + i.f1 AS "102" FROM TIMESTAMP_TBL t, INTERVAL_TBL i
  Mon Feb 10 22:32:01 1997
  Mon Feb 10 17:33:01 1997
  Mon Feb 10 22:32:01 1997
- Mon Feb 10 14:33:01 1997
- Mon Feb 10 19:32:01 1997
+ Mon Feb 10 17:33:01 1997
+ Mon Feb 10 22:32:01 1997
  Tue Jun 10 18:33:01 1997
  Tue Jun 10 23:32:01 1997
  Mon Feb 10 17:33:01 1997
@@ -1047,8 +1047,8 @@ SELECT t.d1 - i.f1 AS "102" FROM TIMESTAMP_TBL t, INTERVAL_TBL i
  Mon Feb 10 12:32:01 1997
  Mon Feb 10 17:31:01 1997
  Mon Feb 10 12:32:01 1997
- Mon Feb 10 14:31:01 1997
- Mon Feb 10 09:32:01 1997
+ Mon Feb 10 17:31:01 1997
+ Mon Feb 10 12:32:01 1997
  Tue Jun 10 18:31:01 1997
  Tue Jun 10 13:32:01 1997
  Mon Feb 10 17:31:01 1997
@@ -2538,7 +2538,7 @@ SELECT '' AS "64", d1 AS us_postgres FROM TIMESTAMP_TBL;
     | Mon Feb 10 17:32:01 1997
     | Mon Feb 10 17:32:01 1997
     | Mon Feb 10 17:32:01 1997
-    | Mon Feb 10 14:32:01 1997
+    | Mon Feb 10 17:32:01 1997
     | Tue Jun 10 18:32:01 1997
     | Mon Feb 10 17:32:01 1997
     | Tue Feb 11 17:32:01 1997
@@ -2621,7 +2621,7 @@ SELECT '' AS "64", d1 AS us_iso FROM TIMESTAMP_TBL;
     | 1997-02-10 17:32:01
     | 1997-02-10 17:32:01
     | 1997-02-10 17:32:01
-    | 1997-02-10 14:32:01
+    | 1997-02-10 17:32:01
     | 1997-06-10 18:32:01
     | 1997-02-10 17:32:01
     | 1997-02-11 17:32:01
@@ -2710,7 +2710,7 @@ SELECT '' AS "64", d1 AS us_sql FROM TIMESTAMP_TBL;
     | 02/10/1997 17:32:01
     | 02/10/1997 17:32:01
     | 02/10/1997 17:32:01
-    | 02/10/1997 14:32:01
+    | 02/10/1997 17:32:01
     | 06/10/1997 18:32:01
     | 02/10/1997 17:32:01
     | 02/11/1997 17:32:01
@@ -2806,7 +2806,7 @@ SELECT '' AS "65", d1 AS european_postgres FROM TIMESTAMP_TBL;
     | Mon 10 Feb 17:32:01 1997
     | Mon 10 Feb 17:32:01 1997
     | Mon 10 Feb 17:32:01 1997
-    | Mon 10 Feb 14:32:01 1997
+    | Mon 10 Feb 17:32:01 1997
     | Tue 10 Jun 18:32:01 1997
     | Mon 10 Feb 17:32:01 1997
     | Tue 11 Feb 17:32:01 1997
@@ -2896,7 +2896,7 @@ SELECT '' AS "65", d1 AS european_iso FROM TIMESTAMP_TBL;
     | 1997-02-10 17:32:01
     | 1997-02-10 17:32:01
     | 1997-02-10 17:32:01
-    | 1997-02-10 14:32:01
+    | 1997-02-10 17:32:01
     | 1997-06-10 18:32:01
     | 1997-02-10 17:32:01
     | 1997-02-11 17:32:01
@@ -2986,7 +2986,7 @@ SELECT '' AS "65", d1 AS european_sql FROM TIMESTAMP_TBL;
     | 10/02/1997 17:32:01
     | 10/02/1997 17:32:01
     | 10/02/1997 17:32:01
-    | 10/02/1997 14:32:01
+    | 10/02/1997 17:32:01
     | 10/06/1997 18:32:01
     | 10/02/1997 17:32:01
     | 11/02/1997 17:32:01
index 5f3de34149a7470c192a25512db1850e7a95c10b..c145279e73e9013ef267463cf0fc900fd385867f 100644 (file)
@@ -80,12 +80,12 @@ INSERT INTO TIMESTAMP_TBL VALUES ('1997-02-10 17:32:01 -08:00');
 INSERT INTO TIMESTAMP_TBL VALUES ('19970210 173201 -0800');
 INSERT INTO TIMESTAMP_TBL VALUES ('1997-06-10 17:32:01 -07:00');
 INSERT INTO TIMESTAMP_TBL VALUES ('2001-09-22T18:19:20');
--- POSIX format
+-- POSIX format (note that the timezone abbrev is just decoration here)
 INSERT INTO TIMESTAMP_TBL VALUES ('2000-03-15 08:14:01 GMT+8');
 INSERT INTO TIMESTAMP_TBL VALUES ('2000-03-15 13:14:02 GMT-1');
-INSERT INTO TIMESTAMP_TBL VALUES ('2000-03-15 12:14:03 GMT -2');
-INSERT INTO TIMESTAMP_TBL VALUES ('2000-03-15 03:14:04 EST+3');
-INSERT INTO TIMESTAMP_TBL VALUES ('2000-03-15 02:14:05 EST +2:00');
+INSERT INTO TIMESTAMP_TBL VALUES ('2000-03-15 12:14:03 GMT-2');
+INSERT INTO TIMESTAMP_TBL VALUES ('2000-03-15 03:14:04 PST+8');
+INSERT INTO TIMESTAMP_TBL VALUES ('2000-03-15 02:14:05 MST+7:00');
 -- Variations for acceptable input formats
 INSERT INTO TIMESTAMP_TBL VALUES ('Feb 10 17:32:01 1997 -0800');
 INSERT INTO TIMESTAMP_TBL VALUES ('Feb 10 17:32:01 1997');
@@ -101,9 +101,9 @@ INSERT INTO TIMESTAMP_TBL VALUES ('97/02/10 17:32:01 UTC');
 reset datestyle;
 INSERT INTO TIMESTAMP_TBL VALUES ('1997.041 17:32:01 UTC');
 INSERT INTO TIMESTAMP_TBL VALUES ('19970210 173201 America/New_York');
--- this fails
+-- this fails (even though TZ is a no-op, we still look it up)
 INSERT INTO TIMESTAMP_TBL VALUES ('19970710 173201 America/Does_not_exist');
-ERROR:  time zone "America/Does_not_exist" not recognized
+ERROR:  time zone "america/does_not_exist" not recognized
 -- Check date conversion and date arithmetic
 INSERT INTO TIMESTAMP_TBL VALUES ('1997-06-10 18:32:01 PDT');
 INSERT INTO TIMESTAMP_TBL VALUES ('Feb 10 17:32:01 1997');
@@ -179,7 +179,7 @@ SELECT '' AS "64", d1 FROM TIMESTAMP_TBL;
     | Mon Feb 10 17:32:01 1997
     | Mon Feb 10 17:32:01 1997
     | Mon Feb 10 17:32:01 1997
-    | Mon Feb 10 14:32:01 1997
+    | Mon Feb 10 17:32:01 1997
     | Tue Jun 10 18:32:01 1997
     | Mon Feb 10 17:32:01 1997
     | Tue Feb 11 17:32:01 1997
@@ -248,7 +248,7 @@ SELECT '' AS "48", d1 FROM TIMESTAMP_TBL
     | Mon Feb 10 17:32:01 1997
     | Mon Feb 10 17:32:01 1997
     | Mon Feb 10 17:32:01 1997
-    | Mon Feb 10 14:32:01 1997
+    | Mon Feb 10 17:32:01 1997
     | Tue Jun 10 18:32:01 1997
     | Mon Feb 10 17:32:01 1997
     | Tue Feb 11 17:32:01 1997
@@ -333,7 +333,7 @@ SELECT '' AS "63", d1 FROM TIMESTAMP_TBL
     | Mon Feb 10 17:32:01 1997
     | Mon Feb 10 17:32:01 1997
     | Mon Feb 10 17:32:01 1997
-    | Mon Feb 10 14:32:01 1997
+    | Mon Feb 10 17:32:01 1997
     | Tue Jun 10 18:32:01 1997
     | Mon Feb 10 17:32:01 1997
     | Tue Feb 11 17:32:01 1997
@@ -424,7 +424,7 @@ SELECT '' AS "49", d1 FROM TIMESTAMP_TBL
     | Mon Feb 10 17:32:01 1997
     | Mon Feb 10 17:32:01 1997
     | Mon Feb 10 17:32:01 1997
-    | Mon Feb 10 14:32:01 1997
+    | Mon Feb 10 17:32:01 1997
     | Tue Jun 10 18:32:01 1997
     | Mon Feb 10 17:32:01 1997
     | Tue Feb 11 17:32:01 1997
@@ -480,7 +480,7 @@ SELECT '' AS "54", d1 - timestamp without time zone '1997-01-02' AS diff
     | @ 39 days 17 hours 32 mins 1 sec
     | @ 39 days 17 hours 32 mins 1 sec
     | @ 39 days 17 hours 32 mins 1 sec
-    | @ 39 days 14 hours 32 mins 1 sec
+    | @ 39 days 17 hours 32 mins 1 sec
     | @ 159 days 18 hours 32 mins 1 sec
     | @ 39 days 17 hours 32 mins 1 sec
     | @ 40 days 17 hours 32 mins 1 sec
@@ -550,7 +550,7 @@ SELECT '' AS "54", d1 - timestamp without time zone '1997-01-02' AS diff
     | @ 39 days 17 hours 32 mins 1 sec
     | @ 39 days 17 hours 32 mins 1 sec
     | @ 39 days 17 hours 32 mins 1 sec
-    | @ 39 days 14 hours 32 mins 1 sec
+    | @ 39 days 17 hours 32 mins 1 sec
     | @ 159 days 18 hours 32 mins 1 sec
     | @ 39 days 17 hours 32 mins 1 sec
     | @ 40 days 17 hours 32 mins 1 sec
@@ -614,7 +614,7 @@ SELECT '' AS "54", d1 as "timestamp",
     | Mon Feb 10 17:32:01 1997    | 1997 |     2 |  10 |   17 |     32 |      1
     | Mon Feb 10 17:32:01 1997    | 1997 |     2 |  10 |   17 |     32 |      1
     | Mon Feb 10 17:32:01 1997    | 1997 |     2 |  10 |   17 |     32 |      1
-    | Mon Feb 10 14:32:01 1997    | 1997 |     2 |  10 |   14 |     32 |      1
+    | Mon Feb 10 17:32:01 1997    | 1997 |     2 |  10 |   17 |     32 |      1
     | Tue Jun 10 18:32:01 1997    | 1997 |     6 |  10 |   18 |     32 |      1
     | Mon Feb 10 17:32:01 1997    | 1997 |     2 |  10 |   17 |     32 |      1
     | Tue Feb 11 17:32:01 1997    | 1997 |     2 |  11 |   17 |     32 |      1
@@ -677,7 +677,7 @@ SELECT '' AS "54", d1 as "timestamp",
     | Mon Feb 10 17:32:01 1997    |       1 |  1000 |  1000000
     | Mon Feb 10 17:32:01 1997    |       1 |  1000 |  1000000
     | Mon Feb 10 17:32:01 1997    |       1 |  1000 |  1000000
-    | Mon Feb 10 14:32:01 1997    |       1 |  1000 |  1000000
+    | Mon Feb 10 17:32:01 1997    |       1 |  1000 |  1000000
     | Tue Jun 10 18:32:01 1997    |       2 |  1000 |  1000000
     | Mon Feb 10 17:32:01 1997    |       1 |  1000 |  1000000
     | Tue Feb 11 17:32:01 1997    |       1 |  1000 |  1000000
@@ -1025,7 +1025,7 @@ SELECT '' AS to_char_5, to_char(d1, 'HH HH12 HH24 MI SS SSSS')
            | 05 05 17 32 01 63121
            | 05 05 17 32 01 63121
            | 05 05 17 32 01 63121
-           | 02 02 14 32 01 52321
+           | 05 05 17 32 01 63121
            | 06 06 18 32 01 66721
            | 05 05 17 32 01 63121
            | 05 05 17 32 01 63121
@@ -1096,7 +1096,7 @@ SELECT '' AS to_char_6, to_char(d1, E'"HH:MI:SS is" HH:MI:SS "\\"text between qu
            | HH:MI:SS is 05:32:01 "text between quote marks"
            | HH:MI:SS is 05:32:01 "text between quote marks"
            | HH:MI:SS is 05:32:01 "text between quote marks"
-           | HH:MI:SS is 02:32:01 "text between quote marks"
+           | HH:MI:SS is 05:32:01 "text between quote marks"
            | HH:MI:SS is 06:32:01 "text between quote marks"
            | HH:MI:SS is 05:32:01 "text between quote marks"
            | HH:MI:SS is 05:32:01 "text between quote marks"
@@ -1167,7 +1167,7 @@ SELECT '' AS to_char_7, to_char(d1, 'HH24--text--MI--text--SS')
            | 17--text--32--text--01
            | 17--text--32--text--01
            | 17--text--32--text--01
-           | 14--text--32--text--01
+           | 17--text--32--text--01
            | 18--text--32--text--01
            | 17--text--32--text--01
            | 17--text--32--text--01
@@ -1310,7 +1310,7 @@ SELECT '' AS to_char_9, to_char(d1, 'YYYY A.D. YYYY a.d. YYYY bc HH:MI:SS P.M. H
            | 1997 A.D. 1997 a.d. 1997 ad 05:32:01 P.M. 05:32:01 p.m. 05:32:01 pm
            | 1997 A.D. 1997 a.d. 1997 ad 05:32:01 P.M. 05:32:01 p.m. 05:32:01 pm
            | 1997 A.D. 1997 a.d. 1997 ad 05:32:01 P.M. 05:32:01 p.m. 05:32:01 pm
-           | 1997 A.D. 1997 a.d. 1997 ad 02:32:01 P.M. 02:32:01 p.m. 02:32:01 pm
+           | 1997 A.D. 1997 a.d. 1997 ad 05:32:01 P.M. 05:32:01 p.m. 05:32:01 pm
            | 1997 A.D. 1997 a.d. 1997 ad 06:32:01 P.M. 06:32:01 p.m. 06:32:01 pm
            | 1997 A.D. 1997 a.d. 1997 ad 05:32:01 P.M. 05:32:01 p.m. 05:32:01 pm
            | 1997 A.D. 1997 a.d. 1997 ad 05:32:01 P.M. 05:32:01 p.m. 05:32:01 pm
index 4448ef6e20a1bf19ce42b48d7dc5c9f1741f85de..4a17503324d5f10c0eb8f815a60288e8dae24e19 100644 (file)
@@ -75,12 +75,12 @@ INSERT INTO TIMESTAMPTZ_TBL VALUES ('1997-02-10 17:32:01 -08:00');
 INSERT INTO TIMESTAMPTZ_TBL VALUES ('19970210 173201 -0800');
 INSERT INTO TIMESTAMPTZ_TBL VALUES ('1997-06-10 17:32:01 -07:00');
 INSERT INTO TIMESTAMPTZ_TBL VALUES ('2001-09-22T18:19:20');
--- POSIX format
+-- POSIX format (note that the timezone abbrev is just decoration here)
 INSERT INTO TIMESTAMPTZ_TBL VALUES ('2000-03-15 08:14:01 GMT+8');
 INSERT INTO TIMESTAMPTZ_TBL VALUES ('2000-03-15 13:14:02 GMT-1');
-INSERT INTO TIMESTAMPTZ_TBL VALUES ('2000-03-15 12:14:03 GMT -2');
-INSERT INTO TIMESTAMPTZ_TBL VALUES ('2000-03-15 03:14:04 EST+3');
-INSERT INTO TIMESTAMPTZ_TBL VALUES ('2000-03-15 02:14:05 EST +2:00');
+INSERT INTO TIMESTAMPTZ_TBL VALUES ('2000-03-15 12:14:03 GMT-2');
+INSERT INTO TIMESTAMPTZ_TBL VALUES ('2000-03-15 03:14:04 PST+8');
+INSERT INTO TIMESTAMPTZ_TBL VALUES ('2000-03-15 02:14:05 MST+7:00');
 -- Variations for acceptable input formats
 INSERT INTO TIMESTAMPTZ_TBL VALUES ('Feb 10 17:32:01 1997 -0800');
 INSERT INTO TIMESTAMPTZ_TBL VALUES ('Feb 10 17:32:01 1997');
@@ -111,7 +111,7 @@ SELECT '19970710 173201' AT TIME ZONE 'America/New_York';
 (1 row)
 
 INSERT INTO TIMESTAMPTZ_TBL VALUES ('19970710 173201 America/Does_not_exist');
-ERROR:  time zone "America/Does_not_exist" not recognized
+ERROR:  time zone "america/does_not_exist" not recognized
 SELECT '19970710 173201' AT TIME ZONE 'America/Does_not_exist';
 ERROR:  time zone "America/Does_not_exist" not recognized
 -- Check date conversion and date arithmetic
index 31235704a9c418bd54464e3b1341928b46d7f7e5..34689564daec969df82b72371b2a8bd00cbc8303 100644 (file)
@@ -62,12 +62,12 @@ INSERT INTO TIMESTAMP_TBL VALUES ('19970210 173201 -0800');
 INSERT INTO TIMESTAMP_TBL VALUES ('1997-06-10 17:32:01 -07:00');
 INSERT INTO TIMESTAMP_TBL VALUES ('2001-09-22T18:19:20');
 
--- POSIX format
+-- POSIX format (note that the timezone abbrev is just decoration here)
 INSERT INTO TIMESTAMP_TBL VALUES ('2000-03-15 08:14:01 GMT+8');
 INSERT INTO TIMESTAMP_TBL VALUES ('2000-03-15 13:14:02 GMT-1');
-INSERT INTO TIMESTAMP_TBL VALUES ('2000-03-15 12:14:03 GMT -2');
-INSERT INTO TIMESTAMP_TBL VALUES ('2000-03-15 03:14:04 EST+3');
-INSERT INTO TIMESTAMP_TBL VALUES ('2000-03-15 02:14:05 EST +2:00');
+INSERT INTO TIMESTAMP_TBL VALUES ('2000-03-15 12:14:03 GMT-2');
+INSERT INTO TIMESTAMP_TBL VALUES ('2000-03-15 03:14:04 PST+8');
+INSERT INTO TIMESTAMP_TBL VALUES ('2000-03-15 02:14:05 MST+7:00');
 
 -- Variations for acceptable input formats
 INSERT INTO TIMESTAMP_TBL VALUES ('Feb 10 17:32:01 1997 -0800');
@@ -83,12 +83,10 @@ INSERT INTO TIMESTAMP_TBL VALUES ('97FEB10 5:32:01PM UTC');
 INSERT INTO TIMESTAMP_TBL VALUES ('97/02/10 17:32:01 UTC');
 reset datestyle;
 INSERT INTO TIMESTAMP_TBL VALUES ('1997.041 17:32:01 UTC');
-
 INSERT INTO TIMESTAMP_TBL VALUES ('19970210 173201 America/New_York');
--- this fails
+-- this fails (even though TZ is a no-op, we still look it up)
 INSERT INTO TIMESTAMP_TBL VALUES ('19970710 173201 America/Does_not_exist');
 
-
 -- Check date conversion and date arithmetic
 INSERT INTO TIMESTAMP_TBL VALUES ('1997-06-10 18:32:01 PDT');
 
index 65af1b04173ff02e9c022ab6003f8cb52c5ab5f3..fc597a6b2cf477da44d86c11282dd7833e378937 100644 (file)
@@ -56,12 +56,12 @@ INSERT INTO TIMESTAMPTZ_TBL VALUES ('19970210 173201 -0800');
 INSERT INTO TIMESTAMPTZ_TBL VALUES ('1997-06-10 17:32:01 -07:00');
 INSERT INTO TIMESTAMPTZ_TBL VALUES ('2001-09-22T18:19:20');
 
--- POSIX format
+-- POSIX format (note that the timezone abbrev is just decoration here)
 INSERT INTO TIMESTAMPTZ_TBL VALUES ('2000-03-15 08:14:01 GMT+8');
 INSERT INTO TIMESTAMPTZ_TBL VALUES ('2000-03-15 13:14:02 GMT-1');
-INSERT INTO TIMESTAMPTZ_TBL VALUES ('2000-03-15 12:14:03 GMT -2');
-INSERT INTO TIMESTAMPTZ_TBL VALUES ('2000-03-15 03:14:04 EST+3');
-INSERT INTO TIMESTAMPTZ_TBL VALUES ('2000-03-15 02:14:05 EST +2:00');
+INSERT INTO TIMESTAMPTZ_TBL VALUES ('2000-03-15 12:14:03 GMT-2');
+INSERT INTO TIMESTAMPTZ_TBL VALUES ('2000-03-15 03:14:04 PST+8');
+INSERT INTO TIMESTAMPTZ_TBL VALUES ('2000-03-15 02:14:05 MST+7:00');
 
 -- Variations for acceptable input formats
 INSERT INTO TIMESTAMPTZ_TBL VALUES ('Feb 10 17:32:01 1997 -0800');