Fix breakage in new-in-7.3 timetz_zone() function: was giving random
authorTom Lane
Thu, 21 Nov 2002 23:31:20 +0000 (23:31 +0000)
committerTom Lane
Thu, 21 Nov 2002 23:31:20 +0000 (23:31 +0000)
results due to doing arithmetic on uninitialized values.  Add some
documentation about the AT TIME ZONE construct.  Update some other
date/time documentation that seemed out of date for 7.3.

doc/src/sgml/datatype.sgml
doc/src/sgml/func.sgml
src/backend/utils/adt/date.c

index 1c07a9c5f16e72690f0445eca28c9ede60e7da63..cac65623dc5cc28c128f8cabe28e06006c931eb2 100644 (file)
@@ -1,5 +1,5 @@
 
 
  
@@ -1569,19 +1569,31 @@ SELECT b, char_length(b) FROM test2;
      data type
     
 
+    
+     timestamp with time zone
+     data type
+    
+
     
      timestamp without time zone
      data type
     
 
      
-      Time stamp types exist as timestamp [
-      (p) ], timestamp [
+      The time stamp types are timestamp [
       (p) ] without time zone and
-      timestamp [ (p) ] without time
-      zone.  A plain timestamp is equivalent to
-      timestamp without timezone.
+      timestamp [ (p) ] with time
+      zone.  Writing just timestamp is equivalent to
+      timestamp without time zone.
+     
+
+    
+     
+      Prior to PostgreSQL 7.3, writing just
+      timestamp was equivalent to timestamp with time
+      zone.  This was changed for SQL spec compliance.
      
+    
 
      
       Valid input for the time stamp types consists of a concatenation
@@ -1615,11 +1627,38 @@ January 8 04:05:06 1999 PST
 
      
       For timestamp without time zone, any explicit time
-      zone specified in the input is silently swallowed. That is, the
+      zone specified in the input is silently ignored. That is, the
       resulting date/time value is derived from the explicit date/time
       fields in the input value, and is not adjusted for time zone.
      
 
+     
+      For timestamp with time zone, the internally stored
+      value is always in UTC (GMT).  An input value that has an explicit
+      time zone specified is converted to UTC using the appropriate offset
+      for that time zone.  If no time zone is stated in the input string,
+      then it is assumed to be in the time zone indicated by the system's
+      TimeZone parameter, and is converted to UTC using the
+      offset for the TimeZone zone.
+     
+
+     
+      When a timestamp with time
+      zone value is output, it is always converted from UTC to the
+      current TimeZone zone, and displayed as local time in that
+      zone.  To see the time in another time zone, either change
+      TimeZone or use the AT TIME ZONE construct
+      (see ).
+     
+
+     
+      Conversions between timestamp without time zone and
+      timestamp with time zone normally assume that the
+      timestamp without time zone value should be taken or given
+      as TimeZone local time.  A different zone reference can
+      be specified for the conversion using AT TIME ZONE.
+     
+
       
        Time Zone Input
        
@@ -1707,24 +1746,28 @@ January 8 04:05:06 1999 PST
      
       The following SQL-compatible functions can be
       used as date or time
-      input for the corresponding data type: CURRENT_DATE,
+      values for the corresponding data type: CURRENT_DATE,
       CURRENT_TIME,
       CURRENT_TIMESTAMP. The latter two accept an
-      optional precision specification.  (See also .)
+      optional precision specification.  (See also -current">.)
      
 
      
       PostgreSQL also supports several
-      special constants for convenience, shown in 
-      linkend="datatype-datetime-special-table">.
+      special date/time input values for convenience, as shown in 
+      linkend="datatype-datetime-special-table">.  The values
+      infinity and -infinity
+      are specially represented inside the system and will be displayed
+      the same way; but the others are simply notational shorthands
+      that will be converted to ordinary date/time values when read.
      
 
       
-       Special Date/Time <span class="marked">Constan</span>ts
+       Special Date/Time <span class="marked">Inpu</span>ts
        
    
     
-     Constant
+     Input string
      Description
     
    
@@ -1735,15 +1778,13 @@ January 8 04:05:06 1999 PST
     
     
      infinity
-     later than other valid times
+     later than all other timestamps (not available for
+     type date)
     
     
      -infinity
-     earlier than other valid times
-    
-    
-     invalid
-     illegal entry
+     earlier than all other timestamps (not available for
+     type date)
     
     
      now
@@ -1962,13 +2003,21 @@ January 8 04:05:06 1999 PST
     
 
     
-     There are several ways to affect the time-zone behavior:
+     There are several ways to select the time zone used by the server:
 
      
       
        
    The TZ environment variable on the server host
-   is used by the server as the default time zone.
+   is used by the server as the default time zone, if no other is
+   specified.
+       
+      
+
+      
+       
+   The timezone configuration parameter can be
+   set in postgresql.conf.
        
       
 
@@ -1987,18 +2036,6 @@ January 8 04:05:06 1999 PST
    sets the time zone for the session.
        
       
-
-      
-       
-   The construct
-
-timestamp AT TIME ZONE 'zone'
-
-   where zone can be specified as a
-   text time zone (e.g., 'PST') or as an
-   interval (e.g., INTERVAL '-08:00').
-       
-      
      
     
 
index 717419484579c8b09214c5d328c5f480f10246c9..7443f001ef468e6e8377aa6003cdfb6f48060cf4 100644 (file)
@@ -1,5 +1,5 @@
 
 
@@ -3549,9 +3549,14 @@ SUBSTRING('foobar' FROM 'o(.)b')   o
    *, etc.).  For formatting functions, refer to
    .  You should be familiar with
    the background information on date/time data types (see 
-   linkend="datatype-datetime">).  The date/time operators described
-   below behave similarly for types involving time zones as well as
-   those without.
+   linkend="datatype-datetime">).
+  
+
+  
+   All the functions and operators described below that take time or timestamp
+   inputs actually come in two variants: one that takes time or timestamp
+   with time zone, and one that takes time or timestamp without time zone.
+   For brevity, these variants are not shown separately.
   
 
     
@@ -3771,7 +3776,7 @@ SUBSTRING('foobar' FROM 'o(.)b')   o
 
        
    now()
-   timestamp
+   timestamp with time zone
    Current date and time (equivalent to
     current_timestamp); see 
                                                      linkend="functions-datetime-current">
@@ -3898,8 +3903,8 @@ SELECT EXTRACT(DOY FROM TIMESTAMP '2001-02-16 20:38:40');
       
        
         For date and timestamp values, the
-        number of seconds since 1970-01-01 00:00:00-00 (Result may be
-        negative.); for interval values, the total number
+        number of seconds since 1970-01-01 00:00:00-00 (can be negative);
+   for interval values, the total number
         of seconds in the interval
        
 
@@ -4122,12 +4127,12 @@ SELECT EXTRACT(YEAR FROM TIMESTAMP '2001-02-16 20:38:40');
    
     The date_part function is modeled on the traditional
     Ingres equivalent to the
-    SQL-function extract:
+    SQL-standard function extract:
 
 date_part('field', source)
 
-    Note that here the field value needs to
-    be a string.  The valid field values for
+    Note that here the field parameter needs to
+    be a string value, not a name.  The valid field values for
     date_part are the same as for
     extract.
    
@@ -4192,6 +4197,95 @@ SELECT date_trunc('year', TIMESTAMP '2001-02-16 20:38:40');
    
   
 
+  
+   <function>AT TIME ZONE</function>
+
+   
+    timezone
+    conversion
+   
+
+   
+    The AT TIME ZONE construct allows conversions
+    of timestamps to different timezones.
+   
+
+    
+     AT TIME ZONE Variants
+     
+      
+       
+   Expression
+   Returns
+   Description
+       
+      
+
+      
+
+       
+   
+    timestamp without time zone
+    AT TIME ZONE
+    zone
+   
+   timestamp with time zone
+   Convert local time in given timezone to UTC
+       
+
+       
+   
+    timestamp with time zone
+    AT TIME ZONE
+    zone
+   
+   timestamp without time zone
+   Convert UTC to local time in given timezone
+       
+
+       
+   
+    time with time zone
+    AT TIME ZONE
+    zone
+   
+   time with time zone
+   Convert local time across timezones
+       
+
+      
+     
+    
+
+   
+    In these expressions, the desired time zone can be
+    specified either as a text string (e.g., 'PST')
+    or as an interval (e.g., INTERVAL '-08:00').
+   
+
+   
+    Examples (supposing that TimeZone is PST8PDT):
+
+SELECT TIMESTAMP '2001-02-16 20:38:40' AT TIME ZONE 'MST';
+Result: 2001-02-16 19:38:40-08
+
+SELECT TIMESTAMP WITH TIME ZONE '2001-02-16 20:38:40-05' AT TIME ZONE 'MST';
+Result: 2001-02-16 18:38:40
+
+    The first example takes a zone-less timestamp and interprets it as MST time
+    (GMT-7) to produce a UTC timestamp, which is then rotated to PST (GMT-8)
+    for display.  The second example takes a timestamp specified in EST
+    (GMT-5) and converts it to local time in MST (GMT-7).
+   
+
+   
+    The function timezone(zone,
+    timestamp) is equivalent to the SQL-compliant construct
+    timestamp AT TIME ZONE
+    zone. 
+   
+  
+
   
    Current Date/Time
 
@@ -4219,6 +4313,16 @@ LOCALTIMESTAMP
 LOCALTIME ( precision )
 LOCALTIMESTAMP ( precision )
 
+    
+
+    
+     CURRENT_TIME and
+     CURRENT_TIMESTAMP deliver values with time zone;
+     LOCALTIME and
+     LOCALTIMESTAMP deliver values without time zone.
+    
+
+    
      CURRENT_TIME,
      CURRENT_TIMESTAMP,
      LOCALTIME, and
index 6c35f3ae00965b317a33dbef00bda2d302d2a35e..3b921258890d14fdef817f2d306e18be2162d661 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/adt/date.c,v 1.73 2002/09/21 19:52:41 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/adt/date.c,v 1.74 2002/11/21 23:31:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2013,7 +2013,6 @@ timetz_zone(PG_FUNCTION_ARGS)
    text       *zone = PG_GETARG_TEXT_P(0);
    TimeTzADT  *time = PG_GETARG_TIMETZADT_P(1);
    TimeTzADT  *result;
-   TimeADT     time1;
    int         tz;
    int         type,
                val;
@@ -2040,15 +2039,17 @@ timetz_zone(PG_FUNCTION_ARGS)
    {
        tz = val * 60;
 #ifdef HAVE_INT64_TIMESTAMP
-       time1 = (time->time - ((time->zone + tz) * INT64CONST(1000000)));
-       result->time -= ((result->time / time1) * time1);
-       if (result->time < INT64CONST(0))
+       result->time = time->time + ((time->zone - tz) * INT64CONST(1000000));
+       while (result->time < INT64CONST(0))
            result->time += INT64CONST(86400000000);
+       while (result->time >= INT64CONST(86400000000))
+           result->time -= INT64CONST(86400000000);
 #else
-       time1 = (time->time - time->zone + tz);
-       TMODULO(result->time, time1, 86400e0);
-       if (result->time < 0)
+       result->time = time->time + (time->zone - tz);
+       while (result->time < 0)
            result->time += 86400;
+       while (result->time >= 86400)
+           result->time -= 86400;
 #endif
 
        result->zone = tz;
@@ -2087,13 +2088,13 @@ timetz_izone(PG_FUNCTION_ARGS)
    result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
 
 #ifdef HAVE_INT64_TIMESTAMP
-   result->time = (time->time + ((time->zone - tz) * INT64CONST(1000000)));
+   result->time = time->time + ((time->zone - tz) * INT64CONST(1000000));
    while (result->time < INT64CONST(0))
        result->time += INT64CONST(86400000000);
    while (result->time >= INT64CONST(86400000000))
        result->time -= INT64CONST(86400000000);
 #else
-   result->time = (time->time + (time->zone - tz));
+   result->time = time->time + (time->zone - tz);
    while (result->time < 0)
        result->time += 86400;
    while (result->time >= 86400)