argument is the value to be formatted and the second argument is a
template that defines the output or input format.
</para>
- <para>
- A single-argument <function>to_timestamp</function> function is also
- available; it accepts a
- <type>double precision</type> argument and converts from Unix epoch
- (seconds since 1970-01-01 00:00:00+00) to
- <type>timestamp with time zone</type>.
- (<type>Integer</type> Unix epochs are implicitly cast to
- <type>double precision</type>.)
- </para>
<table id="functions-formatting-table">
<title>Formatting Functions</title>
<entry>convert string to time stamp</entry>
<entry><literal>to_timestamp('05 Dec 2000', 'DD Mon YYYY')</literal></entry>
</row>
- <row>
- <entry><literal><function>to_timestamp(<type>double precision</type>)</function></literal></entry>
- <entry><type>timestamp with time zone</type></entry>
- <entry>convert Unix epoch to time stamp</entry>
- <entry><literal>to_timestamp(1284352323)</literal></entry>
- </row>
</tbody>
</tgroup>
</table>
+ <note>
+ <para>
+ There is also a single-argument <function>to_timestamp</function>
+ function; see <xref linkend="functions-datetime-table">.
+ </para>
+ </note>
+
<para>
In a <function>to_char</> output template string, there are certain
patterns that are recognized and replaced with appropriately-formatted
<entry><type>timestamp with time zone</type></entry>
<entry>
Create timestamp with time zone from year, month, day, hour, minute
- and seconds fields. When <parameter>timezone</parameter> is not specified,
- then current time zone is used.
+ and seconds fields; if <parameter>timezone</parameter> is not
+ specified, the current time zone is used
</entry>
<entry><literal>make_timestamptz(2013, 7, 15, 8, 15, 23.5)</literal></entry>
<entry><literal>2013-07-15 08:15:23.5+01</literal></entry>
<entry></entry>
<entry></entry>
</row>
+ <row>
+ <entry>
+ <indexterm>
+ <primary>to_timestamp</primary>
+ </indexterm>
+ <literal><function>to_timestamp(<type>double precision</type>)</function></literal>
+ </entry>
+ <entry><type>timestamp with time zone</type></entry>
+ <entry>Convert Unix epoch (seconds since 1970-01-01 00:00:00+00) to
+ timestamp</entry>
+ <entry><literal>to_timestamp(1284352323)</literal></entry>
+ <entry><literal>2010-09-13 04:32:03+00</literal></entry>
+ </row>
</tbody>
</tgroup>
</table>
</screen>
<para>
- Here is how you can convert an epoch value back to a time
- stamp:
+ You can convert an epoch value back to a time stamp
+ with <function>to_timestamp</>:
</para>
<screen>
-SELECT TIMESTAMP WITH TIME ZONE 'epoch' + 982384720.12 * INTERVAL '1 second';
+SELECT to_timestamp(982384720.12);
+<lineannotation>Result: </lineannotation><computeroutput>2001-02-17 04:38:40.12+00</computeroutput>
</screen>
- <para>
- (The <function>to_timestamp</> function encapsulates the above
- conversion.)
- </para>
</listitem>
</varlistentry>
PG_RETURN_TIMESTAMPTZ(result);
}
+/*
+ * to_timestamp(double precision)
+ * Convert UNIX epoch to timestamptz.
+ */
+Datum
+float8_timestamptz(PG_FUNCTION_ARGS)
+{
+ float8 seconds = PG_GETARG_FLOAT8(0);
+ TimestampTz result;
+
+ /* Deal with NaN and infinite inputs ... */
+ if (isnan(seconds))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("timestamp cannot be NaN")));
+
+ if (isinf(seconds))
+ {
+ if (seconds < 0)
+ TIMESTAMP_NOBEGIN(result);
+ else
+ TIMESTAMP_NOEND(result);
+ }
+ else
+ {
+ /* Out of range? */
+ if (seconds <
+ (float8) SECS_PER_DAY * (DATETIME_MIN_JULIAN - UNIX_EPOCH_JDATE))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("timestamp out of range: \"%g\"", seconds)));
+
+ if (seconds >=
+ (float8) SECS_PER_DAY * (TIMESTAMP_END_JULIAN - UNIX_EPOCH_JDATE))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("timestamp out of range: \"%g\"", seconds)));
+
+ /* Convert UNIX epoch to Postgres epoch */
+ seconds -= ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY);
+
+#ifdef HAVE_INT64_TIMESTAMP
+ result = seconds * USECS_PER_SEC;
+#else
+ result = seconds;
+#endif
+
+ /* Recheck in case roundoff produces something just out of range */
+ if (!IS_VALID_TIMESTAMP(result))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("timestamp out of range: \"%g\"",
+ PG_GETARG_FLOAT8(0))));
+ }
+
+ PG_RETURN_TIMESTAMP(result);
+}
+
/* timestamptz_out()
* Convert a timestamp to external form.
*/
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 201603291
+#define CATALOG_VERSION_NO 201603292
#endif
DATA(insert OID = 1155 ( timestamptz_le PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "1184 1184" _null_ _null_ _null_ _null_ _null_ timestamp_le _null_ _null_ _null_ ));
DATA(insert OID = 1156 ( timestamptz_ge PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "1184 1184" _null_ _null_ _null_ _null_ _null_ timestamp_ge _null_ _null_ _null_ ));
DATA(insert OID = 1157 ( timestamptz_gt PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "1184 1184" _null_ _null_ _null_ _null_ _null_ timestamp_gt _null_ _null_ _null_ ));
-DATA(insert OID = 1158 ( to_timestamp PGNSP PGUID 14 1 0 0 0 f f f f t f i s 1 0 1184 "701" _null_ _null_ _null_ _null_ _null_ "select (''epoch''::pg_catalog.timestamptz + $1 * ''1 second''::pg_catalog.interval)" _null_ _null_ _null_ ));
+DATA(insert OID = 1158 ( to_timestamp PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 1184 "701" _null_ _null_ _null_ _null_ _null_ float8_timestamptz _null_ _null_ _null_ ));
DESCR("convert UNIX epoch to timestamptz");
DATA(insert OID = 3995 ( timestamp_zone_transform PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2281 "2281" _null_ _null_ _null_ _null_ _null_ timestamp_zone_transform _null_ _null_ _null_ ));
DESCR("transform a time zone adjustment");
extern Datum make_timestamp(PG_FUNCTION_ARGS);
extern Datum make_timestamptz(PG_FUNCTION_ARGS);
extern Datum make_timestamptz_at_timezone(PG_FUNCTION_ARGS);
+extern Datum float8_timestamptz(PG_FUNCTION_ARGS);
extern Datum timestamptz_eq_timestamp(PG_FUNCTION_ARGS);
extern Datum timestamptz_ne_timestamp(PG_FUNCTION_ARGS);
Sun Dec 09 07:30:00 2007 UTC
(1 row)
+SELECT to_timestamp( 0); -- 1970-01-01 00:00:00+00
+ to_timestamp
+------------------------------
+ Thu Jan 01 00:00:00 1970 UTC
+(1 row)
+
+SELECT to_timestamp( 946684800); -- 2000-01-01 00:00:00+00
+ to_timestamp
+------------------------------
+ Sat Jan 01 00:00:00 2000 UTC
+(1 row)
+
+SELECT to_timestamp(1262349296.7890123); -- 2010-01-01 12:34:56.789012+00
+ to_timestamp
+-------------------------------------
+ Fri Jan 01 12:34:56.789012 2010 UTC
+(1 row)
+
+-- edge cases
+SELECT to_timestamp(-1e20::float8); -- error, out of range
+ERROR: timestamp out of range: "-1e+20"
+SELECT to_timestamp(-210866803200.0625); -- error, out of range
+ERROR: timestamp out of range: "-2.10867e+11"
+SELECT to_timestamp(-210866803200); -- 4714-11-24 00:00:00+00 BC
+ to_timestamp
+---------------------------------
+ Mon Nov 24 00:00:00 4714 UTC BC
+(1 row)
+
+-- The upper boundary differs between integer and float timestamps, so check the biggest one
+SELECT to_timestamp(185331707078400::float8); -- error, out of range
+ERROR: timestamp out of range: "1.85332e+14"
+-- nonfinite values
+SELECT to_timestamp(' Infinity'::float);
+ to_timestamp
+--------------
+ infinity
+(1 row)
+
+SELECT to_timestamp('-Infinity'::float);
+ to_timestamp
+--------------
+ -infinity
+(1 row)
+
+SELECT to_timestamp('NaN'::float);
+ERROR: timestamp cannot be NaN
SET TimeZone to 'Europe/Moscow';
SELECT '2011-03-26 21:00:00 UTC'::timestamptz;
timestamptz
SELECT make_timestamptz(2007, 12, 9, 2, 0, 0, 'VET');
SELECT make_timestamptz(2007, 12, 9, 3, 0, 0, 'VET');
+SELECT to_timestamp( 0); -- 1970-01-01 00:00:00+00
+SELECT to_timestamp( 946684800); -- 2000-01-01 00:00:00+00
+SELECT to_timestamp(1262349296.7890123); -- 2010-01-01 12:34:56.789012+00
+-- edge cases
+SELECT to_timestamp(-1e20::float8); -- error, out of range
+SELECT to_timestamp(-210866803200.0625); -- error, out of range
+SELECT to_timestamp(-210866803200); -- 4714-11-24 00:00:00+00 BC
+-- The upper boundary differs between integer and float timestamps, so check the biggest one
+SELECT to_timestamp(185331707078400::float8); -- error, out of range
+-- nonfinite values
+SELECT to_timestamp(' Infinity'::float);
+SELECT to_timestamp('-Infinity'::float);
+SELECT to_timestamp('NaN'::float);
+
+
SET TimeZone to 'Europe/Moscow';
SELECT '2011-03-26 21:00:00 UTC'::timestamptz;