Pavel Stehule escribió:

> > 7) Why do the functions accept only the timezone abbreviation, not the
> >    full name? I find it rather confusing, because the 'timezone' option
> >    uses the full name, and we're using this as the default. But doing
> >    'show timestamp' and using the returned value fails. Is it possible
> >    to fix this somehow?
> 
> A only abbreviation is allowed for timetz type. Timestamp can work with
> full time zone names. A rules (behave) should be same as input functions
> for types: timestamptz and timetz.
> 
> postgres=# select '10:10:10 CET'::timetz;
>    timetz
> ─────────────
>  10:10:10+01
> (1 row)
> 
> postgres=# select '10:10:10 Europe/Prague'::timetz;
> ERROR:  invalid input syntax for type time with time zone: "10:10:10
> Europe/Prague"
> LINE 1: select '10:10:10 Europe/Prague'::timetz;
>                ^
> 
> This limit is due used routines limits.

I think this is a strange limitation, and perhaps it should be fixed
rather than inflicting the limitation on the new function.

I tweaked your patch a bit, attached; other than defining what to do
about full TZ names in timetz, this seems ready to commit.

-- 
Álvaro Herrera                http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index be548d7..69eb45f 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -6725,6 +6725,32 @@ SELECT SUBSTRING('XY1234Z', 'Y*?([0-9]{1,3})');
        <row>
         <entry>
          <indexterm>
+          <primary>make_interval</primary>
+         </indexterm>
+         <literal>
+          <function>
+           make_interval(<parameter>years</parameter> <type>int</type> DEFAULT 0,
+           <parameter>months</parameter> <type>int</type> DEFAULT 0,
+           <parameter>weeks</parameter> <type>int</type> DEFAULT 0,
+           <parameter>days</parameter> <type>int</type> DEFAULT 0,
+           <parameter>hours</parameter> <type>int</type> DEFAULT 0,
+           <parameter>mins</parameter> <type>int</type> DEFAULT 0,
+           <parameter>secs</parameter> <type>double precision</type> DEFAULT 0.0)
+          </function>
+         </literal>
+        </entry>
+        <entry><type>interval</type></entry>
+        <entry>
+         Create interval from years, months, weeks, days, hours, minutes and
+         seconds fields
+        </entry>
+        <entry><literal>make_interval(days := 10)</literal></entry>
+        <entry><literal>10 days</literal></entry>
+       </row>
+
+       <row>
+        <entry>
+         <indexterm>
           <primary>make_time</primary>
          </indexterm>
          <literal>
@@ -6746,6 +6772,81 @@ SELECT SUBSTRING('XY1234Z', 'Y*?([0-9]{1,3})');
        <row>
         <entry>
          <indexterm>
+          <primary>make_timetz</primary>
+         </indexterm>
+         <literal>
+          <function>
+           make_timetz(<parameter>hour</parameter> <type>int</type>,
+           <parameter>min</parameter> <type>int</type>,
+           <parameter>sec</parameter> <type>double precision</type>,
+           <optional> <parameter>timezone</parameter> <type>text</type> </optional>)
+          </function>
+         </literal>
+        </entry>
+        <entry><type>time with time zone</type></entry>
+        <entry>
+         Create time with time zone from hour, minute and seconds fields. When
+         <parameter>timezone</parameter> is not specified, then current time zone
+         is used.
+        </entry>
+        <entry><literal>make_timetz(8, 15, 23.5)</literal></entry>
+        <entry><literal>08:15:23.5+01</literal></entry>
+       </row>
+
+       <row>
+        <entry>
+         <indexterm>
+          <primary>make_timestamp</primary>
+         </indexterm>
+         <literal>
+          <function>
+           make_timestamp(<parameter>year</parameter> <type>int</type>,
+           <parameter>month</parameter> <type>int</type>,
+           <parameter>day</parameter> <type>int</type>,
+           <parameter>hour</parameter> <type>int</type>,
+           <parameter>min</parameter> <type>int</type>,
+           <parameter>sec</parameter> <type>double precision</type>)
+          </function>
+         </literal>
+        </entry>
+        <entry><type>timestamp</type></entry>
+        <entry>
+         Create timestamp from year, month, day, hour, minute and seconds fields
+        </entry>
+        <entry><literal>make_timestamp(1-23, 7, 15, 8, 15, 23.5)</literal></entry>
+        <entry><literal>2013-07-15 08:15:23.5</literal></entry>
+       </row>
+
+       <row>
+        <entry>
+         <indexterm>
+          <primary>make_timestamptz</primary>
+         </indexterm>
+         <literal>
+          <function>
+           make_timestamptz(<parameter>year</parameter> <type>int</type>,
+           <parameter>month</parameter> <type>int</type>,
+           <parameter>day</parameter> <type>int</type>,
+           <parameter>hour</parameter> <type>int</type>,
+           <parameter>min</parameter> <type>int</type>,
+           <parameter>sec</parameter> <type>double precision</type>,
+           <optional> <parameter>timezone</parameter> <type>text</type> </optional>)
+          </function>
+         </literal>
+        </entry>
+        <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.
+        </entry>
+        <entry><literal>make_timestamp(1-23, 7, 15, 8, 15, 23.5)</literal></entry>
+        <entry><literal>2013-07-15 08:15:23.5+01</literal></entry>
+       </row>
+
+       <row>
+        <entry>
+         <indexterm>
           <primary>now</primary>
          </indexterm>
          <literal><function>now()</function></literal>
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index f02efec..d0852f4 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -819,3 +819,9 @@ CREATE OR REPLACE FUNCTION
 CREATE OR REPLACE FUNCTION
   json_populate_recordset(base anyelement, from_json json, use_json_as_text boolean DEFAULT false)
   RETURNS SETOF anyelement LANGUAGE internal STABLE ROWS 100  AS 'json_populate_recordset';
+
+CREATE OR REPLACE FUNCTION
+  make_interval(years int4 DEFAULT 0, months int4 DEFAULT 0, weeks int4 DEFAULT 0,
+                days int4 DEFAULT 0, hours int4 DEFAULT 0, mins int4 DEFAULT 0,
+                secs double precision DEFAULT 0.0)
+  RETURNS interval STRICT IMMUTABLE LANGUAGE internal AS 'make_interval';
diff --git a/src/backend/utils/adt/date.c b/src/backend/utils/adt/date.c
index 06cc0cd..ba801e4 100644
--- a/src/backend/utils/adt/date.c
+++ b/src/backend/utils/adt/date.c
@@ -1106,6 +1106,7 @@ time_in(PG_FUNCTION_ARGS)
 static int
 tm2time(struct pg_tm * tm, fsec_t fsec, TimeADT *result)
 {
+	/* this should match make_time_internal and make_timestamp_internal */
 #ifdef HAVE_INT64_TIMESTAMP
 	*result = ((((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec)
 			   * USECS_PER_SEC) + fsec;
@@ -1244,14 +1245,11 @@ timetypmodout(PG_FUNCTION_ARGS)
 }
 
 /*
- *		make_time			- time constructor
+ * time constructor used for make_time and make_timetz
  */
-Datum
-make_time(PG_FUNCTION_ARGS)
+static TimeADT
+make_time_internal(int tm_hour, int tm_min, double sec)
 {
-	int			tm_hour = PG_GETARG_INT32(0);
-	int			tm_min = PG_GETARG_INT32(1);
-	double		sec = PG_GETARG_FLOAT8(2);
 	TimeADT		time;
 
 	/* This should match the checks in DecodeTimeOnly */
@@ -1273,9 +1271,94 @@ make_time(PG_FUNCTION_ARGS)
 	time = ((tm_hour * MINS_PER_HOUR + tm_min) * SECS_PER_MINUTE) + sec;
 #endif
 
+	return time;
+}
+
+/*
+ *		make_time			- time constructor
+ */
+Datum
+make_time(PG_FUNCTION_ARGS)
+{
+	int         tm_hour = PG_GETARG_INT32(0);
+	int         tm_min = PG_GETARG_INT32(1);
+	double      sec = PG_GETARG_FLOAT8(2);
+	TimeADT		time;
+
+	time = make_time_internal(tm_hour, tm_min, sec);
+
 	PG_RETURN_TIMEADT(time);
 }
 
+/*
+ *		make_timetz			- timetz constructor
+ */
+Datum
+make_timetz(PG_FUNCTION_ARGS)
+{
+	int         tm_hour = PG_GETARG_INT32(0);
+	int         tm_min = PG_GETARG_INT32(1);
+	double      sec = PG_GETARG_FLOAT8(2);
+	TimeADT		time;
+
+	time = make_time_internal(tm_hour, tm_min, sec);
+
+	PG_RETURN_DATUM(DirectFunctionCall1(time_timetz,
+										TimeADTGetDatum(time)));
+}
+
+/*
+ *		make_timetz_at_timezone					- timetz constructor
+ */
+Datum
+make_timetz_at_timezone(PG_FUNCTION_ARGS)
+{
+	int         tm_hour = PG_GETARG_INT32(0);
+	int         tm_min = PG_GETARG_INT32(1);
+	double      sec = PG_GETARG_FLOAT8(2);
+	text	   *zone = PG_GETARG_TEXT_PP(3);
+	TimeADT		t;
+	TimeTzADT  *result;
+	char		tzstr[TZ_STRLEN_MAX + 1];
+	int			tz;
+
+	t = make_time_internal(tm_hour, tm_min, sec);
+
+	/*
+	 * Try to decode the user-supplied timezone.  If it can be parsed as a
+	 * numeric timezone specification, use that; otherwise try to match it
+	 * to the timezone token tables via DecodeSpecial.
+	 */
+	text_to_cstring_buffer(zone, tzstr, sizeof(tzstr));
+	if (DecodeTimezone(tzstr, &tz) != 0)
+	{
+		char	   *lowzone;
+		int			type,
+					val;
+
+		lowzone = downcase_truncate_identifier(tzstr,
+											   strlen(tzstr),
+											   false);
+		type = DecodeSpecial(0, lowzone, &val);
+
+		if (type == TZ || type == DTZ)
+			tz = val * MINS_PER_HOUR;
+		else
+		{
+			/* XXX why not the pg_tzset dance here? */
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+					 errmsg("time zone \"%s\" not recognized", tzstr)));
+			tz = 0;				/* keep compiler quiet */
+		}
+	}
+
+	result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
+	result->time = t;
+	result->zone = tz;
+
+	PG_RETURN_TIMETZADT_P(result);
+}
 
 /* time_transform()
  * Flatten calls to time_scale() and timetz_scale() that solely represent
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 946adfa..f6e05bc 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -40,7 +40,6 @@ static int DecodeNumberField(int len, char *str,
 				  struct pg_tm * tm, fsec_t *fsec, bool *is2digits);
 static int DecodeTime(char *str, int fmask, int range,
 		   int *tmask, struct pg_tm * tm, fsec_t *fsec);
-static int	DecodeTimezone(char *str, int *tzp);
 static const datetkn *datebsearch(const char *key, const datetkn *base, int nel);
 static int DecodeDate(char *str, int fmask, int *tmask, bool *is2digits,
 		   struct pg_tm * tm);
@@ -2075,6 +2074,10 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
 	else if (mer == PM && tm->tm_hour != HOURS_PER_DAY / 2)
 		tm->tm_hour += HOURS_PER_DAY / 2;
 
+	/*
+	 * This should match the checks in make_time_internal and
+	 * make_timestamp_internal
+	 */
 	if (tm->tm_hour < 0 || tm->tm_min < 0 || tm->tm_min > MINS_PER_HOUR - 1 ||
 		tm->tm_sec < 0 || tm->tm_sec > SECS_PER_MINUTE ||
 		tm->tm_hour > HOURS_PER_DAY ||
@@ -2707,7 +2710,7 @@ DecodeNumberField(int len, char *str, int fmask,
  *
  * NB: this must *not* ereport on failure; see commands/variable.c.
  */
-static int
+int
 DecodeTimezone(char *str, int *tzp)
 {
 	int			tz;
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index cf6982b..10a2805 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -483,6 +483,191 @@ timestamptz_in(PG_FUNCTION_ARGS)
 	PG_RETURN_TIMESTAMPTZ(result);
 }
 
+/*
+ * make_timestamp_internal
+ *		workhorse for make_timestamp and make_timestamptz
+ */
+static Timestamp
+make_timestamp_internal(int year, int month, int day,
+						int hour, int min, double sec)
+{
+	struct pg_tm tm;
+	TimeOffset	date;
+	TimeOffset	time;
+	int			dterr;
+	Timestamp	result;
+
+	tm.tm_year = year;
+	tm.tm_mon = month;
+	tm.tm_mday = day;
+
+	/*
+	 * Note: we'll reject zero or negative year values.  Perhaps negatives
+	 * should be allowed to represent BC years?
+	 */
+	dterr = ValidateDate(DTK_DATE_M, false, false, false, &tm);
+
+	if (dterr != 0)
+		ereport(ERROR,
+				(errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
+				 errmsg("date field value out of range: %d-%02d-%02d",
+						year, month, day)));
+
+	if (!IS_VALID_JULIAN(tm.tm_year, tm.tm_mon, tm.tm_mday))
+		ereport(ERROR,
+				(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+				 errmsg("date out of range: %d-%02d-%02d",
+						year, month, day)));
+
+	date = date2j(tm.tm_year, tm.tm_mon, tm.tm_mday) - POSTGRES_EPOCH_JDATE;
+
+	/* This should match the checks in DecodeTimeOnly */
+	if (hour < 0 || min < 0 || min > MINS_PER_HOUR - 1 ||
+		sec < 0 || sec > SECS_PER_MINUTE ||
+		hour > HOURS_PER_DAY ||
+	/* test for > 24:00:00 */
+		(hour == HOURS_PER_DAY && (min > 0 || sec > 0)))
+		ereport(ERROR,
+				(errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
+				 errmsg("time field value out of range: %d:%02d:%02g",
+						hour, min, sec)));
+
+	/* This should match tm2time */
+#ifdef HAVE_INT64_TIMESTAMP
+	time = (((hour * MINS_PER_HOUR + min) * SECS_PER_MINUTE)
+			* USECS_PER_SEC) + rint(sec * USECS_PER_SEC);
+
+	result = date * USECS_PER_DAY + time;
+	/* check for major overflow */
+	if ((result - time) / USECS_PER_DAY != date)
+		ereport(ERROR,
+				(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+				 errmsg("timestamp out of range: %d-%02d-%02d %d:%02d:%02g",
+						year, month, day,
+						hour, min, sec)));
+
+	/* check for just-barely overflow (okay except time-of-day wraps) */
+	/* caution: we want to allow 1999-12-31 24:00:00 */
+	if ((result < 0 && date > 0) ||
+		 (result > 0 && date < -1))
+		ereport(ERROR,
+				(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+				 errmsg("timestamp out of range: %d-%02d-%02d %d:%02d:%02g",
+						year, month, day,
+						hour, min, sec)));
+#else
+	time = ((hour * MINS_PER_HOUR + min) * SECS_PER_MINUTE) + sec;
+	result = date * SECS_PER_DAY + time;
+#endif
+
+	return result;
+}
+
+/*
+ * make_timestamp() - timestamp constructor
+ */
+Datum
+make_timestamp(PG_FUNCTION_ARGS)
+{
+	int32		year = PG_GETARG_INT32(0);
+	int32		month = PG_GETARG_INT32(1);
+	int32		mday = PG_GETARG_INT32(2);
+	int32		hour = PG_GETARG_INT32(3);
+	int32		min = PG_GETARG_INT32(4);
+	float8		sec = PG_GETARG_FLOAT8(5);
+	Timestamp result;
+
+	result = make_timestamp_internal(year, month, mday,
+									 hour, min, sec);
+
+	PG_RETURN_TIMESTAMP(result);
+}
+
+/*
+ * make_timestamptz() - timestamp with time zone constructor
+ */
+Datum
+make_timestamptz(PG_FUNCTION_ARGS)
+{
+	int32		year = PG_GETARG_INT32(0);
+	int32		month = PG_GETARG_INT32(1);
+	int32		mday = PG_GETARG_INT32(2);
+	int32		hour = PG_GETARG_INT32(3);
+	int32		min = PG_GETARG_INT32(4);
+	float8		sec = PG_GETARG_FLOAT8(5);
+	Timestamp result;
+
+	result = make_timestamp_internal(year, month, mday,
+									 hour, min, sec);
+
+	PG_RETURN_TIMESTAMPTZ(timestamp2timestamptz(result));
+}
+
+Datum
+make_timestamptz_at_timezone(PG_FUNCTION_ARGS)
+{
+	int32		year = PG_GETARG_INT32(0);
+	int32		month = PG_GETARG_INT32(1);
+	int32		mday = PG_GETARG_INT32(2);
+	int32		hour = PG_GETARG_INT32(3);
+	int32		min = PG_GETARG_INT32(4);
+	float8		sec = PG_GETARG_FLOAT8(5);
+	text	   *zone = PG_GETARG_TEXT_PP(6);
+	Timestamp	timestamp;
+	char		tzstr[TZ_STRLEN_MAX + 1];
+	int			tz;
+	struct pg_tm tt,
+			   *tm = &tt;
+	fsec_t		fsec;
+
+	timestamp = make_timestamp_internal(year, month, mday,
+										hour, min, sec);
+
+	if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
+		ereport(ERROR,
+				(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+				 errmsg("timestamp out of range")));
+
+	/*
+	 * Try to decode the user-supplied timezone.  If it can be parsed as a
+	 * numeric timezone specification, use that; otherwise try to match it
+	 * to the timezone token tables via DecodeSpecial.
+	 */
+	text_to_cstring_buffer(zone, tzstr, sizeof(tzstr));
+	if (DecodeTimezone(tzstr, &tz) != 0)
+	{
+		char	   *lowzone;
+		int			type,
+					val;
+
+		lowzone = downcase_truncate_identifier(tzstr,
+											   strlen(tzstr),
+											   false);
+		type = DecodeSpecial(0, lowzone, &val);
+
+		if (type == TZ || type == DTZ)
+			tz = val * MINS_PER_HOUR;
+		else
+		{
+			pg_tz	   *tzp;
+
+			tzp = pg_tzset(tzstr);
+
+			if (tzp)
+				tz = DetermineTimeZoneOffset(tm, tzp);
+			else
+			{
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("time zone \"%s\" not recognized", tzstr)));
+				tz = 0;						/* keep compiler quiet */
+			}
+		}
+	}
+
+	PG_RETURN_TIMESTAMPTZ((TimestampTz) dt2local(timestamp, -tz));
+}
+
 /* timestamptz_out()
  * Convert a timestamp to external form.
  */
@@ -1220,6 +1405,40 @@ AdjustIntervalForTypmod(Interval *interval, int32 typmod)
 	}
 }
 
+/*
+ * make_interval - numeric Interval constructor
+ */
+Datum
+make_interval(PG_FUNCTION_ARGS)
+{
+	Interval	 *result;
+
+	int32 years = PG_GETARG_INT32(0);
+	int32 months = PG_GETARG_INT32(1);
+	int32 weeks = PG_GETARG_INT32(2);
+	int32 days = PG_GETARG_INT32(3);
+	int32 hours = PG_GETARG_INT32(4);
+	int32 mins= PG_GETARG_INT32(5);
+	double secs = PG_GETARG_FLOAT8(6);
+
+	result = (Interval *) palloc(sizeof(Interval));
+	result->month = years * MONTHS_PER_YEAR + months;
+	result->day = weeks * 7 + days;
+
+#ifdef HAVE_INT64_TIMESTAMP
+	result->time = (((((hours * INT64CONST(60)) +
+					 mins) * INT64CONST(60)) +
+				   secs) * USECS_PER_SEC);
+#else
+	result->time = (((hours * (double) MINS_PER_HOUR) +
+				   mins) * (double) SECS_PER_MINUTE) +
+		secs;
+#endif
+
+	AdjustIntervalForTypmod(result, -1);
+
+	PG_RETURN_INTERVAL_P(result);
+}
 
 /* EncodeSpecialTimestamp()
  * Convert reserved timestamp data type to string.
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index e6713a6..a8930ce 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -4701,11 +4701,23 @@ DESCR("int8range constructor");
 DATA(insert OID = 3946 (  int8range PGNSP PGUID 12 1 0 0 0 f f f f f f i 3 0 3926 "20 20 25" _null_ _null_ _null_ _null_ range_constructor3 _null_ _null_ _null_ ));
 DESCR("int8range constructor");
 
-/* date, time constructors */
+/* date, time, timestamp constructors */
 DATA(insert OID = 3846 ( make_date	PGNSP PGUID 12 1 0 0 0 f f f f t f i 3 0 1082 "23 23 23" _null_ _null_ "{year,month,day}" _null_ make_date _null_ _null_ _null_ ));
 DESCR("construct date");
 DATA(insert OID = 3847 ( make_time	PGNSP PGUID 12 1 0 0 0 f f f f t f i 3 0 1083 "23 23 701" _null_ _null_ "{hour,min,sec}" _null_ make_time _null_ _null_ _null_ ));
 DESCR("construct time");
+DATA(insert OID = 3548 ( make_timetz	PGNSP PGUID 12 1 0 0 0 f f f f t f s 3 0 1266 "23 23 701" _null_ _null_ "{hour,min,sec}" _null_ make_timetz _null_ _null_ _null_ ));
+DESCR("construct time with time zone");
+DATA(insert OID = 3549 ( make_timetz	PGNSP PGUID 12 1 0 0 0 f f f f t f i 4 0 1266 "23 23 701 25" _null_ _null_ "{hour,min,sec,timezone}" _null_ make_timetz_at_timezone _null_ _null_ _null_ ));
+DESCR("construct time with time zone");
+DATA(insert OID = 3550 ( make_timestamp	PGNSP PGUID 12 1 0 0 0 f f f f t f i 6 0 1114 "23 23 23 23 23 701" _null_ _null_ "{year,month,mday,hour,min,sec}" _null_ make_timestamp _null_ _null_ _null_ ));
+DESCR("construct timestamp");
+DATA(insert OID = 3551 ( make_timestamptz	PGNSP PGUID 12 1 0 0 0 f f f f t f s 6 0 1184 "23 23 23 23 23 701" _null_ _null_ "{year,month,mday,hour,min,sec}" _null_ make_timestamptz _null_ _null_ _null_ ));
+DESCR("construct timestamp with time zone");
+DATA(insert OID = 3552 ( make_timestamptz	PGNSP PGUID 12 1 0 0 0 f f f f t f s 7 0 1184 "23 23 23 23 23 701 25" _null_ _null_ "{year,month,mday,hour,min,sec,timezone}" _null_ make_timestamptz_at_timezone _null_ _null_ _null_ ));
+DESCR("construct timestamp with time zone");
+DATA(insert OID = 3553 ( make_interval	PGNSP PGUID 12 1 0 0 0 f f f f t f i 7 0 1186 "23 23 23 23 23 23 701" _null_ _null_ "{years,months,weeks,days,hours,mins,secs}" _null_ make_interval _null_ _null_ _null_ ));
+DESCR("construct interval");
 
 /* spgist support functions */
 DATA(insert OID = 4001 (  spggettuple	   PGNSP PGUID 12 1 0 0 0 f f f f t f v 2 0 16 "2281 2281" _null_ _null_ _null_ _null_	spggettuple _null_ _null_ _null_ ));
diff --git a/src/include/utils/date.h b/src/include/utils/date.h
index 622aa19..2077b1f 100644
--- a/src/include/utils/date.h
+++ b/src/include/utils/date.h
@@ -156,6 +156,8 @@ extern Datum time_send(PG_FUNCTION_ARGS);
 extern Datum timetypmodin(PG_FUNCTION_ARGS);
 extern Datum timetypmodout(PG_FUNCTION_ARGS);
 extern Datum make_time(PG_FUNCTION_ARGS);
+extern Datum make_timetz(PG_FUNCTION_ARGS);
+extern Datum make_timetz_at_timezone(PG_FUNCTION_ARGS);
 extern Datum time_transform(PG_FUNCTION_ARGS);
 extern Datum time_scale(PG_FUNCTION_ARGS);
 extern Datum time_eq(PG_FUNCTION_ARGS);
diff --git a/src/include/utils/datetime.h b/src/include/utils/datetime.h
index 12f1e77..079d20e 100644
--- a/src/include/utils/datetime.h
+++ b/src/include/utils/datetime.h
@@ -278,6 +278,7 @@ extern int ParseDateTime(const char *timestr, char *workbuf, size_t buflen,
 extern int DecodeDateTime(char **field, int *ftype,
 			   int nf, int *dtype,
 			   struct pg_tm * tm, fsec_t *fsec, int *tzp);
+extern int DecodeTimezone(char *str, int *tzp);
 extern int DecodeTimeOnly(char **field, int *ftype,
 			   int nf, int *dtype,
 			   struct pg_tm * tm, fsec_t *fsec, int *tzp);
diff --git a/src/include/utils/timestamp.h b/src/include/utils/timestamp.h
index 47fb866..2731c6a 100644
--- a/src/include/utils/timestamp.h
+++ b/src/include/utils/timestamp.h
@@ -121,6 +121,10 @@ extern Datum timestamp_gt_timestamptz(PG_FUNCTION_ARGS);
 extern Datum timestamp_ge_timestamptz(PG_FUNCTION_ARGS);
 extern Datum timestamp_cmp_timestamptz(PG_FUNCTION_ARGS);
 
+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 timestamptz_eq_timestamp(PG_FUNCTION_ARGS);
 extern Datum timestamptz_ne_timestamp(PG_FUNCTION_ARGS);
 extern Datum timestamptz_lt_timestamp(PG_FUNCTION_ARGS);
@@ -151,6 +155,7 @@ extern Datum interval_larger(PG_FUNCTION_ARGS);
 extern Datum interval_justify_interval(PG_FUNCTION_ARGS);
 extern Datum interval_justify_hours(PG_FUNCTION_ARGS);
 extern Datum interval_justify_days(PG_FUNCTION_ARGS);
+extern Datum make_interval(PG_FUNCTION_ARGS);
 
 extern Datum timestamp_trunc(PG_FUNCTION_ARGS);
 extern Datum interval_trunc(PG_FUNCTION_ARGS);
diff --git a/src/test/regress/expected/interval.out b/src/test/regress/expected/interval.out
index 3bf2211..47400f8 100644
--- a/src/test/regress/expected/interval.out
+++ b/src/test/regress/expected/interval.out
@@ -800,3 +800,34 @@ select interval_hash('30 days'::interval) = interval_hash('1 month'::interval) a
  t
 (1 row)
 
+-- numeric constructor
+select make_interval(years := 2);
+ make_interval 
+---------------
+ @ 2 years
+(1 row)
+
+select make_interval(years := 1, months := 6);
+  make_interval  
+-----------------
+ @ 1 year 6 mons
+(1 row)
+
+select make_interval(weeks := 3);
+ make_interval 
+---------------
+ @ 21 days
+(1 row)
+
+select make_interval(days := 10);
+ make_interval 
+---------------
+ @ 10 days
+(1 row)
+
+select make_interval(hours := 2, mins := 10, secs := 25.3);
+        make_interval        
+-----------------------------
+ @ 2 hours 10 mins 25.3 secs
+(1 row)
+
diff --git a/src/test/regress/expected/timestamp.out b/src/test/regress/expected/timestamp.out
index db2cfe6..a092fc2 100644
--- a/src/test/regress/expected/timestamp.out
+++ b/src/test/regress/expected/timestamp.out
@@ -1585,3 +1585,10 @@ SELECT '' AS to_char_11, to_char(d1, 'FMIYYY FMIYY FMIY FMI FMIW FMIDDD FMID')
             | 2001 1 1 1 1 1 1
 (65 rows)
 
+-- timestamp numeric fields constructor
+SELECT make_timestamp(2014,12,28,6,30,45.887);
+        make_timestamp        
+------------------------------
+ Sun Dec 28 06:30:45.887 2014
+(1 row)
+
diff --git a/src/test/regress/expected/timestamptz.out b/src/test/regress/expected/timestamptz.out
index 9f4f7a4..1382dda 100644
--- a/src/test/regress/expected/timestamptz.out
+++ b/src/test/regress/expected/timestamptz.out
@@ -1697,3 +1697,54 @@ SELECT * FROM TIMESTAMPTZ_TST ORDER BY a;
 
 --Cleanup
 DROP TABLE TIMESTAMPTZ_TST;
+-- timestamp numeric constructor
+SELECT make_timestamptz(1973, 07, 15, 08, 15, 55.33);
+        make_timestamptz         
+---------------------------------
+ Sun Jul 15 08:15:55.33 1973 PDT
+(1 row)
+
+SELECT make_timestamptz(1973, 07, 15, 08, 15, 55.33, '+2');
+        make_timestamptz         
+---------------------------------
+ Sat Jul 14 23:15:55.33 1973 PDT
+(1 row)
+
+-- should be true
+SELECT make_timestamptz(1973, 07, 15, 08, 15, 55.33, '+2') = '1973-07-15 08:15:55.33+02'::timestamptz;
+ ?column? 
+----------
+ t
+(1 row)
+
+-- timestamp with full time zone name
+select make_timestamptz(2014, 12, 10, 10, 10, 10, 'Europe/Moscow') = '2014-12-10 10:10:10 Europe/Moscow'::timestamptz;
+ ?column? 
+----------
+ t
+(1 row)
+
+select make_timestamptz(2014, 12, 10, 10, 10, 10, 'Europe/London') = '2014-12-10 10:10:10 Europe/London'::timestamptz;
+ ?column? 
+----------
+ t
+(1 row)
+
+select make_timestamptz(2014, 12, 10, 10, 10, 10, 'Europe/Prague') = '2014-12-10 10:10:10 Europe/Prague'::timestamptz;
+ ?column? 
+----------
+ t
+(1 row)
+
+select make_timestamptz(2014, 12, 10, 10, 10, 10, 'Australia/Sydney') = '2014-12-10 10:10:10 Australia/Sydney'::timestamptz;
+ ?column? 
+----------
+ t
+(1 row)
+
+select make_timestamptz(2014, 12, 10, 10, 10, 10, 'America/Vancouver') = '2014-12-10 10:10:10 America/Vancouver'::timestamptz;
+ ?column? 
+----------
+ t
+(1 row)
+
diff --git a/src/test/regress/expected/timetz.out b/src/test/regress/expected/timetz.out
index 4391131..2469f4b 100644
--- a/src/test/regress/expected/timetz.out
+++ b/src/test/regress/expected/timetz.out
@@ -93,3 +93,56 @@ ERROR:  operator does not exist: time with time zone + time with time zone
 LINE 1: SELECT f1 + time with time zone '00:01' AS "Illegal" FROM TI...
                   ^
 HINT:  No operator matches the given name and argument type(s). You might need to add explicit type casts.
+-- check time with time zone numeric constructor
+SELECT make_timetz(8, 15, 55.333);
+   make_timetz   
+-----------------
+ 08:15:55.333-08
+(1 row)
+
+SELECT make_timetz(8, 15, 55.333, 'HKT');
+   make_timetz   
+-----------------
+ 08:15:55.333+08
+(1 row)
+
+SELECT make_timetz(8, 15, 55.333, '+1:30');
+    make_timetz     
+--------------------
+ 08:15:55.333+01:30
+(1 row)
+
+SELECT make_timetz(8, 15, 55.333, '-1:30');
+    make_timetz     
+--------------------
+ 08:15:55.333-01:30
+(1 row)
+
+-- should be true
+SELECT make_timetz(8, 15, 55.333) = '8:15:55.333'::timetz;
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT make_timetz(8, 15, 55.333, 'HKT') = '8:15:55.333 HKT'::timetz;
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT make_timetz(8, 15, 55.333, '+1:30') = '8:15:55.333 +1:30'::timetz;
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT make_timetz(8, 15, 55.333, '-1:30') = '8:15:55.333 -1:30'::timetz;
+ ?column? 
+----------
+ t
+(1 row)
+
+-- only abbreviations are supported, should fail
+SELECT make_timetz(8, 15, 55.333, 'Europe/Prague');
+ERROR:  time zone "Europe/Prague" not recognized
diff --git a/src/test/regress/sql/interval.sql b/src/test/regress/sql/interval.sql
index f1da4c2..8459e3f 100644
--- a/src/test/regress/sql/interval.sql
+++ b/src/test/regress/sql/interval.sql
@@ -259,3 +259,10 @@ select interval '0:0:0.7', interval '@ 0.70 secs', interval '0.7 seconds';
 -- check that '30 days' equals '1 month' according to the hash function
 select '30 days'::interval = '1 month'::interval as t;
 select interval_hash('30 days'::interval) = interval_hash('1 month'::interval) as t;
+
+-- numeric constructor
+select make_interval(years := 2);
+select make_interval(years := 1, months := 6);
+select make_interval(weeks := 3);
+select make_interval(days := 10);
+select make_interval(hours := 2, mins := 10, secs := 25.3);
diff --git a/src/test/regress/sql/timestamp.sql b/src/test/regress/sql/timestamp.sql
index c4ed4ee..b22cd48 100644
--- a/src/test/regress/sql/timestamp.sql
+++ b/src/test/regress/sql/timestamp.sql
@@ -222,3 +222,6 @@ SELECT '' AS to_char_10, to_char(d1, 'IYYY IYY IY I IW IDDD ID')
 
 SELECT '' AS to_char_11, to_char(d1, 'FMIYYY FMIYY FMIY FMI FMIW FMIDDD FMID')
    FROM TIMESTAMP_TBL;
+
+-- timestamp numeric fields constructor
+SELECT make_timestamp(2014,12,28,6,30,45.887);
diff --git a/src/test/regress/sql/timestamptz.sql b/src/test/regress/sql/timestamptz.sql
index 4eef62e..06affbc 100644
--- a/src/test/regress/sql/timestamptz.sql
+++ b/src/test/regress/sql/timestamptz.sql
@@ -254,3 +254,17 @@ INSERT INTO TIMESTAMPTZ_TST VALUES(4, '1000000312 23:58:48 IST');
 SELECT * FROM TIMESTAMPTZ_TST ORDER BY a;
 --Cleanup
 DROP TABLE TIMESTAMPTZ_TST;
+
+-- timestamp numeric constructor
+SELECT make_timestamptz(1973, 07, 15, 08, 15, 55.33);
+SELECT make_timestamptz(1973, 07, 15, 08, 15, 55.33, '+2');
+
+-- should be true
+SELECT make_timestamptz(1973, 07, 15, 08, 15, 55.33, '+2') = '1973-07-15 08:15:55.33+02'::timestamptz;
+
+-- timestamp with full time zone name
+select make_timestamptz(2014, 12, 10, 10, 10, 10, 'Europe/Moscow') = '2014-12-10 10:10:10 Europe/Moscow'::timestamptz;
+select make_timestamptz(2014, 12, 10, 10, 10, 10, 'Europe/London') = '2014-12-10 10:10:10 Europe/London'::timestamptz;
+select make_timestamptz(2014, 12, 10, 10, 10, 10, 'Europe/Prague') = '2014-12-10 10:10:10 Europe/Prague'::timestamptz;
+select make_timestamptz(2014, 12, 10, 10, 10, 10, 'Australia/Sydney') = '2014-12-10 10:10:10 Australia/Sydney'::timestamptz;
+select make_timestamptz(2014, 12, 10, 10, 10, 10, 'America/Vancouver') = '2014-12-10 10:10:10 America/Vancouver'::timestamptz;
diff --git a/src/test/regress/sql/timetz.sql b/src/test/regress/sql/timetz.sql
index c41686a..e02b393 100644
--- a/src/test/regress/sql/timetz.sql
+++ b/src/test/regress/sql/timetz.sql
@@ -40,3 +40,18 @@ SELECT f1 AS "Ten" FROM TIMETZ_TBL WHERE f1 >= '00:00-07';
 -- where we do mixed-type arithmetic. - thomas 2000-12-02
 
 SELECT f1 + time with time zone '00:01' AS "Illegal" FROM TIMETZ_TBL;
+
+-- check time with time zone numeric constructor
+SELECT make_timetz(8, 15, 55.333);
+SELECT make_timetz(8, 15, 55.333, 'HKT');
+SELECT make_timetz(8, 15, 55.333, '+1:30');
+SELECT make_timetz(8, 15, 55.333, '-1:30');
+
+-- should be true
+SELECT make_timetz(8, 15, 55.333) = '8:15:55.333'::timetz;
+SELECT make_timetz(8, 15, 55.333, 'HKT') = '8:15:55.333 HKT'::timetz;
+SELECT make_timetz(8, 15, 55.333, '+1:30') = '8:15:55.333 +1:30'::timetz;
+SELECT make_timetz(8, 15, 55.333, '-1:30') = '8:15:55.333 -1:30'::timetz;
+
+-- only abbreviations are supported, should fail
+SELECT make_timetz(8, 15, 55.333, 'Europe/Prague');
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to