A use case that I see quite a lot of is needing to do reports and other
calculations on data per day/hour/etc but in the user's time zone.  The
way to do that is fairly trivial, but it's not obvious what it does so
reading queries becomes just a little bit more difficult.

Attached is a patch to create a function for it, based off 5953c99697.
-- 
Vik Fearing                                          +33 6 46 75 15 36
http://2ndQuadrant.fr     PostgreSQL : Expertise, Formation et Support
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 96d45419e5..304fa638fe 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -7185,6 +7185,15 @@ SELECT regexp_match('abc01234xyz', '(?:(.*?)(\d+)(.*)){1,1}');
         <entry><literal>2001-02-16 20:00:00</literal></entry>
        </row>
 
+       <row>
+        <entry><literal><function>date_trunc(<type>text</type>, <type>timestamp with time zone</type>, <type>text</type>)</function></literal></entry>
+        <entry><type>timestamp with time zone</type></entry>
+        <entry>Truncate to specified precision at the specified time zone; see also <xref linkend="functions-datetime-trunc"/>
+        </entry>
+        <entry><literal>date_trunc('day', timestamptz '2001-02-16 20:38:40+00', 'Australia/Sydney')</literal></entry>
+        <entry><literal>2001-02-16 13:00:00+00</literal></entry>
+       </row>
+
        <row>
         <entry><literal><function>date_trunc(<type>text</type>, <type>interval</type>)</function></literal></entry>
         <entry><type>interval</type></entry>
@@ -8078,7 +8087,7 @@ SELECT date_part('hour', INTERVAL '4 hours 3 minutes');
 
    <para>
 <synopsis>
-date_trunc('<replaceable>field</replaceable>', <replaceable>source</replaceable>)
+date_trunc('<replaceable>field</replaceable>', <replaceable>source</replaceable> [, <replaceable>time_zone</replaceable>])
 </synopsis>
     <replaceable>source</replaceable> is a value expression of type
     <type>timestamp</type> or <type>interval</type>.
@@ -8090,6 +8099,9 @@ date_trunc('<replaceable>field</replaceable>', <replaceable>source</replaceable>
     <type>timestamp</type> or <type>interval</type>
     with all fields that are less significant than the
     selected one set to zero (or one, for day and month).
+    If the optional <replaceable>time_zone</replaceable> is present,
+    the <replaceable>source</replaceable> value is truncated in the
+    specified time zone.
    </para>
 
    <para>
@@ -8119,6 +8131,9 @@ SELECT date_trunc('hour', TIMESTAMP '2001-02-16 20:38:40');
 
 SELECT date_trunc('year', TIMESTAMP '2001-02-16 20:38:40');
 <lineannotation>Result: </lineannotation><computeroutput>2001-01-01 00:00:00</computeroutput>
+
+SELECT date_trunc('day', TIMESTAMP WITH TIME ZONE '2001-02-16 20:38:40+00');
+<lineannotation>Result: </lineannotation><computeroutput>2001-02-16 13:00:00+00</computeroutput>
 </screen>
    </para>
   </sect2>
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 4d7fe1b383..9b20752cde 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -2280,6 +2280,10 @@
   descr => 'truncate timestamp with time zone to specified units',
   proname => 'date_trunc', provolatile => 's', prorettype => 'timestamptz',
   proargtypes => 'text timestamptz', prosrc => 'timestamptz_trunc' },
+{ oid => '1284',
+  descr => 'truncate timestamp with time zone to specified units at specified time zone',
+  proname => 'date_trunc', prolang => '14', provolatile => 's', prorettype => 'timestamptz',
+  proargtypes => 'text timestamptz text', prosrc => 'select pg_catalog.date_trunc($1, $2 at time zone $3) at time zone $3' },
 { oid => '1218', descr => 'truncate interval to specified units',
   proname => 'date_trunc', prorettype => 'interval',
   proargtypes => 'text interval', prosrc => 'interval_trunc' },
diff --git a/src/test/regress/expected/timestamptz.out b/src/test/regress/expected/timestamptz.out
index 2340f30794..bac5c36591 100644
--- a/src/test/regress/expected/timestamptz.out
+++ b/src/test/regress/expected/timestamptz.out
@@ -649,6 +649,12 @@ SELECT '' AS date_trunc_week, date_trunc( 'week', timestamp with time zone '2004
                  | Mon Feb 23 00:00:00 2004 PST
 (1 row)
 
+SELECT '' AS date_trunc_at_tz, date_trunc('day', timestamp with time zone '2001-02-16 20:38:40+00', 'Australia/Sydney') as sydney_trunc;
+ date_trunc_at_tz |         sydney_trunc         
+------------------+------------------------------
+                  | Fri Feb 16 05:00:00 2001 PST
+(1 row)
+
 -- Test casting within a BETWEEN qualifier
 SELECT '' AS "54", d1 - timestamp with time zone '1997-01-02' AS diff
   FROM TIMESTAMPTZ_TBL
diff --git a/src/test/regress/sql/timestamptz.sql b/src/test/regress/sql/timestamptz.sql
index f17d153fcc..b7eff45a5b 100644
--- a/src/test/regress/sql/timestamptz.sql
+++ b/src/test/regress/sql/timestamptz.sql
@@ -192,6 +192,7 @@ SELECT '' AS "54", d1 - timestamp with time zone '1997-01-02' AS diff
    FROM TIMESTAMPTZ_TBL WHERE d1 BETWEEN '1902-01-01' AND '2038-01-01';
 
 SELECT '' AS date_trunc_week, date_trunc( 'week', timestamp with time zone '2004-02-29 15:44:17.71393' ) AS week_trunc;
+SELECT '' AS date_trunc_at_tz, date_trunc('day', timestamp with time zone '2001-02-16 20:38:40+00', 'Australia/Sydney') as sydney_trunc;
 
 -- Test casting within a BETWEEN qualifier
 SELECT '' AS "54", d1 - timestamp with time zone '1997-01-02' AS diff

Reply via email to