From 261026575d4b38fd7a39a43c53064de464695f0e Mon Sep 17 00:00:00 2001
From: Bruce Momjian <bruce@momjian.us>
Date: Fri, 22 Jul 2005 21:16:15 +0000
Subject: [PATCH] Fix AT TIME ZONE for timestamps without time zones:

	test=> select ('2005-07-20 00:00:00'::timestamp without time zone) at
	time zone 'Europe/Paris';
	        timezone
	------------------------
	 2005-07-19 22:00:00-04

Udpate documentation.
---
 doc/src/sgml/func.sgml            | 18 +++++++++---------
 src/backend/utils/adt/timestamp.c | 26 +++++++++++++-------------
 2 files changed, 22 insertions(+), 22 deletions(-)

diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 43f720ae10f..59813e16f16 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.268 2005/07/20 16:42:29 momjian Exp $
+$PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.269 2005/07/22 21:16:14 momjian Exp $
 PostgreSQL documentation
 -->
 
@@ -5693,7 +5693,7 @@ SELECT date_trunc('year', TIMESTAMP '2001-02-16 20:38:40');
          <literal><type>timestamp without time zone</type> AT TIME ZONE <replaceable>zone</></literal>
         </entry>
         <entry><type>timestamp with time zone</type></entry>
-        <entry>Convert local time in given time zone to UTC</entry>
+        <entry>Treat given timestamp <emphasis>without time zone</> as located in the specified time zone</entry>
        </row>
 
        <row>
@@ -5701,7 +5701,7 @@ SELECT date_trunc('year', TIMESTAMP '2001-02-16 20:38:40');
          <literal><type>timestamp with time zone</type> AT TIME ZONE <replaceable>zone</></literal>
         </entry>
         <entry><type>timestamp without time zone</type></entry>
-        <entry>Convert UTC to local time in given time zone</entry>
+        <entry>Convert given timestamp <emphasis>with time zone</> to the new time zone</entry>
        </row>
 
        <row>
@@ -5709,7 +5709,7 @@ SELECT date_trunc('year', TIMESTAMP '2001-02-16 20:38:40');
          <literal><type>time with time zone</type> AT TIME ZONE <replaceable>zone</></literal>
         </entry>
         <entry><type>time with time zone</type></entry>
-        <entry>Convert local time across time zones</entry>
+        <entry>Convert given time <emphasis>with time zone</> to the new time zone</entry>
        </row>
       </tbody>
      </tgroup>
@@ -5720,7 +5720,8 @@ 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-set-table">.
+    <xref linkend="datetime-timezone-set-table">.  The time zone can
+    also be implied using the default time zone for that session.
    </para>
 
    <para>
@@ -5732,10 +5733,9 @@ SELECT TIMESTAMP '2001-02-16 20:38:40' AT TIME ZONE 'MST';
 SELECT TIMESTAMP WITH TIME ZONE '2001-02-16 20:38:40-05' AT TIME ZONE 'MST';
 <lineannotation>Result: </lineannotation><computeroutput>2001-02-16 18:38:40</computeroutput>
 </screen>
-    The first example takes a zone-less time stamp and interprets it as MST time
-    (UTC-7) to produce a UTC time stamp, which is then rotated to PST (UTC-8)
-    for display.  The second example takes a time stamp specified in EST
-    (UTC-5) and converts it to local time in MST (UTC-7).
+    The first example takes a time stamp without time zone and interprets it as MST time
+    (UTC-7), which is then converted to PST (UTC-8) for display.  The second example takes 
+    a time stamp specified in EST (UTC-5) and converts it to local time in MST (UTC-7).
    </para>
 
    <para>
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index 73a68a1a22e..2d9b5ad7d0d 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.141 2005/07/22 19:00:54 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.142 2005/07/22 21:16:15 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1035,7 +1035,7 @@ timestamp2tm(Timestamp dt, int *tzp, struct pg_tm *tm, fsec_t *fsec, char **tzn,
 #endif
 
 	/* add offset to go from J2000 back to standard Julian date */
-	date	  +=POSTGRES_EPOCH_JDATE;
+	date += POSTGRES_EPOCH_JDATE;
 
 	/* Julian day routine does not work for negative Julian days */
 	if (date <0 || date >(Timestamp) INT_MAX)
@@ -1147,8 +1147,8 @@ tm2timestamp(struct pg_tm *tm, fsec_t fsec, int *tzp, Timestamp *result)
 		return -1;
 
 	date = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
-
 	time = time2t(tm->tm_hour, tm->tm_min, tm->tm_sec, fsec);
+
 #ifdef HAVE_INT64_TIMESTAMP
 	*result = date * USECS_PER_DAY + time;
 	/* check for major overflow */
@@ -2673,7 +2673,7 @@ timestamp_text(PG_FUNCTION_ARGS)
 	result = palloc(len);
 
 	VARATT_SIZEP(result) = len;
-	memmove(VARDATA(result), str, (len - VARHDRSZ));
+	memmove(VARDATA(result), str, len - VARHDRSZ);
 
 	pfree(str);
 
@@ -2704,7 +2704,7 @@ text_timestamp(PG_FUNCTION_ARGS)
 
 	sp = VARDATA(str);
 	dp = dstr;
-	for (i = 0; i < (VARSIZE(str) - VARHDRSZ); i++)
+	for (i = 0; i < VARSIZE(str) - VARHDRSZ; i++)
 		*dp++ = *sp++;
 	*dp = '\0';
 
@@ -2729,12 +2729,12 @@ timestamptz_text(PG_FUNCTION_ARGS)
 
 	str = DatumGetCString(DirectFunctionCall1(timestamptz_out, timestamp));
 
-	len = (strlen(str) + VARHDRSZ);
+	len = strlen(str) + VARHDRSZ;
 
 	result = palloc(len);
 
 	VARATT_SIZEP(result) = len;
-	memmove(VARDATA(result), str, (len - VARHDRSZ));
+	memmove(VARDATA(result), str, len - VARHDRSZ);
 
 	pfree(str);
 
@@ -2764,7 +2764,7 @@ text_timestamptz(PG_FUNCTION_ARGS)
 
 	sp = VARDATA(str);
 	dp = dstr;
-	for (i = 0; i < (VARSIZE(str) - VARHDRSZ); i++)
+	for (i = 0; i < VARSIZE(str) - VARHDRSZ; i++)
 		*dp++ = *sp++;
 	*dp = '\0';
 
@@ -2789,7 +2789,7 @@ interval_text(PG_FUNCTION_ARGS)
 	str = DatumGetCString(DirectFunctionCall1(interval_out,
 										   IntervalPGetDatum(interval)));
 
-	len = (strlen(str) + VARHDRSZ);
+	len = strlen(str) + VARHDRSZ;
 
 	result = palloc(len);
 
@@ -3084,7 +3084,7 @@ timestamptz_trunc(PG_FUNCTION_ARGS)
 
 			case DTK_MILLISEC:
 #ifdef HAVE_INT64_TIMESTAMP
-				fsec = ((fsec / 1000) * 1000);
+				fsec = (fsec / 1000) * 1000;
 #else
 				fsec = rint(fsec * 1000) / 1000;
 #endif
@@ -3181,7 +3181,7 @@ interval_trunc(PG_FUNCTION_ARGS)
 
 				case DTK_MILLISEC:
 #ifdef HAVE_INT64_TIMESTAMP
-					fsec = ((fsec / 1000) * 1000);
+					fsec = (fsec / 1000) * 1000;
 #else
 					fsec = rint(fsec * 1000) / 1000;
 #endif
@@ -3932,7 +3932,7 @@ timestamp_zone(PG_FUNCTION_ARGS)
 {
 	text	   *zone = PG_GETARG_TEXT_P(0);
 	Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
-	Timestamp result;
+	TimestampTz	result;
 	int			tz;
 	pg_tz      *tzp;
 	char        tzname[TZ_STRLEN_MAX+1];
@@ -3968,7 +3968,7 @@ timestamp_zone(PG_FUNCTION_ARGS)
 				        tzname)));
 		PG_RETURN_NULL();
 	}
-	PG_RETURN_TIMESTAMPTZ(timestamp2timestamptz(result));
+	PG_RETURN_TIMESTAMPTZ(result);
 }
 
 /* timestamp_izone()
-- 
GitLab