Constructors for interval, timestamp, timestamptz

Author: Pavel Stěhule, editorialized somewhat by Álvaro Herrera
Reviewed-by: Tomáš Vondra, Marko Tiikkaja
With input from Fabrízio de Royes Mello, Jim Nasby
This commit is contained in:
Alvaro Herrera 2014-03-04 15:09:43 -03:00
parent af2543e884
commit 84df54b22e
14 changed files with 590 additions and 4 deletions

View File

@ -6720,6 +6720,32 @@ SELECT SUBSTRING('XY1234Z', 'Y*?([0-9]{1,3})');
<entry><literal>2013-07-15</literal></entry>
</row>
<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>
@ -6741,6 +6767,57 @@ SELECT SUBSTRING('XY1234Z', 'Y*?([0-9]{1,3})');
<entry><literal>08:15:23.5</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>

View File

@ -856,3 +856,12 @@ RETURNS SETOF RECORD
LANGUAGE INTERNAL
VOLATILE ROWS 1000 COST 1000
AS 'pg_logical_slot_peek_binary_changes';
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
LANGUAGE INTERNAL
STRICT IMMUTABLE
AS 'make_interval';

View File

@ -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,9 @@ 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_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 +2709,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;

View File

@ -483,6 +483,234 @@ timestamptz_in(PG_FUNCTION_ARGS)
PG_RETURN_TIMESTAMPTZ(result);
}
/*
* Try to parse a timezone specification, and return its timezone offset value
* if it's acceptable. Otherwise, an error is thrown.
*/
static int
parse_sane_timezone(struct pg_tm *tm, text *zone)
{
char tzname[TZ_STRLEN_MAX + 1];
int rt;
int tz;
text_to_cstring_buffer(zone, tzname, sizeof(tzname));
/*
* Look up the requested timezone. First we try to interpret it as a
* numeric timezone specification; if DecodeTimezone decides it doesn't
* like the format, we look in the date token table (to handle cases like
* "EST"), and if that also fails, we look in the timezone database (to
* handle cases like "America/New_York"). (This matches the order in
* which timestamp input checks the cases; it's important because the
* timezone database unwisely uses a few zone names that are identical to
* offset abbreviations.)
*
* Note pg_tzset happily parses numeric input that DecodeTimezone would
* reject. To avoid having it accept input that would otherwise be seen
* as invalid, it's enough to disallow having a digit in the first
* position of our input string.
*/
if (isdigit(*tzname))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid input syntax for numeric time zone: \"%s\"",
tzname),
errhint("Numeric time zones must have \"-\" or \"+\" as first character.")));
rt = DecodeTimezone(tzname, &tz);
if (rt != 0)
{
char *lowzone;
int type,
val;
if (rt == DTERR_TZDISP_OVERFLOW)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("numeric time zone \"%s\" out of range", tzname)));
else if (rt != DTERR_BAD_FORMAT)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("time zone \"%s\" not recognized", tzname)));
lowzone = downcase_truncate_identifier(tzname,
strlen(tzname),
false);
type = DecodeSpecial(0, lowzone, &val);
if (type == TZ || type == DTZ)
tz = val * MINS_PER_HOUR;
else
{
pg_tz *tzp;
tzp = pg_tzset(tzname);
if (tzp)
tz = DetermineTimeZoneOffset(tm, tzp);
else
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("time zone \"%s\" not recognized", tzname)));
}
}
return tz;
}
/*
* 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));
}
/*
* Construct a timestamp with time zone.
* As above, but the time zone is specified as seventh argument.
*/
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;
struct pg_tm tt;
int tz;
fsec_t fsec;
timestamp = make_timestamp_internal(year, month, mday,
hour, min, sec);
if (timestamp2tm(timestamp, NULL, &tt, &fsec, NULL, NULL) != 0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
tz = parse_sane_timezone(&tt, zone);
PG_RETURN_TIMESTAMPTZ((TimestampTz) dt2local(timestamp, -tz));
}
/* timestamptz_out()
* Convert a timestamp to external form.
*/
@ -1220,6 +1448,42 @@ AdjustIntervalForTypmod(Interval *interval, int32 typmod)
}
}
/*
* make_interval - numeric Interval constructor
*/
Datum
make_interval(PG_FUNCTION_ARGS)
{
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);
Interval *result;
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
#ifdef NOT_USED
/* this is a no-op for negative typmods */
AdjustIntervalForTypmod(result, -1);
#endif
PG_RETURN_INTERVAL_P(result);
}
/* EncodeSpecialTimestamp()
* Convert reserved timestamp data type to string.

View File

@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 201403032
#define CATALOG_VERSION_NO 201403041
#endif

View File

@ -4718,11 +4718,19 @@ 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 = 3461 ( 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 = 3462 ( 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 = 3463 ( 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 = 3464 ( 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_ ));

View File

@ -283,6 +283,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);

View File

@ -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);

View File

@ -807,3 +807,48 @@ 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(years := 1, months := -1, weeks := 5, days := -7, hours := 25, mins := -180);
make_interval
----------------------------
@ 11 mons 28 days 22 hours
(1 row)
select make_interval() = make_interval(years := 0, months := 0, weeks := 0, days := 0, mins := 0, secs := 0.0);
?column?
----------
t
(1 row)
select make_interval(hours := -2, mins := -10, secs := -25.3);
make_interval
---------------------------------
@ 2 hours 10 mins 25.3 secs ago
(1 row)
select make_interval(years := 'inf'::float::int);
ERROR: integer out of range
select make_interval(months := 'NaN'::float::int);
ERROR: integer out of range
select make_interval(secs := 'inf');
ERROR: interval out of range
select make_interval(secs := 'NaN');
ERROR: interval out of range
select make_interval(secs := 7e12);
make_interval
------------------------------------
@ 1944444444 hours 26 mins 40 secs
(1 row)

View File

@ -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)

View File

@ -1697,3 +1697,117 @@ SELECT * FROM TIMESTAMPTZ_TST ORDER BY a;
--Cleanup
DROP TABLE TIMESTAMPTZ_TST;
-- test timestamptz constructors
set TimeZone to 'America/Santiago';
-- numeric timezone
SELECT make_timestamptz(1973, 07, 15, 08, 15, 55.33);
make_timestamptz
---------------------------------
Sun Jul 15 08:15:55.33 1973 CLT
(1 row)
SELECT make_timestamptz(1973, 07, 15, 08, 15, 55.33, '+2');
make_timestamptz
---------------------------------
Sun Jul 15 02:15:55.33 1973 CLT
(1 row)
SELECT make_timestamptz(1973, 07, 15, 08, 15, 55.33, '-2');
make_timestamptz
---------------------------------
Sun Jul 15 06:15:55.33 1973 CLT
(1 row)
WITH tzs (tz) AS (VALUES
('+1'), ('+1:'), ('+1:0'), ('+100'), ('+1:00'), ('+01:00'),
('+10'), ('+1000'), ('+10:'), ('+10:0'), ('+10:00'), ('+10:00:'),
('+10:00:1'), ('+10:00:01'),
('+10:00:10'))
SELECT make_timestamptz(2010, 2, 27, 3, 45, 00, tz), tz FROM tzs;
make_timestamptz | tz
-------------------------------+-----------
Fri Feb 26 23:45:00 2010 CLST | +1
Fri Feb 26 23:45:00 2010 CLST | +1:
Fri Feb 26 23:45:00 2010 CLST | +1:0
Fri Feb 26 23:45:00 2010 CLST | +100
Fri Feb 26 23:45:00 2010 CLST | +1:00
Fri Feb 26 23:45:00 2010 CLST | +01:00
Fri Feb 26 14:45:00 2010 CLST | +10
Fri Feb 26 14:45:00 2010 CLST | +1000
Fri Feb 26 14:45:00 2010 CLST | +10:
Fri Feb 26 14:45:00 2010 CLST | +10:0
Fri Feb 26 14:45:00 2010 CLST | +10:00
Fri Feb 26 14:45:00 2010 CLST | +10:00:
Fri Feb 26 14:44:59 2010 CLST | +10:00:1
Fri Feb 26 14:44:59 2010 CLST | +10:00:01
Fri Feb 26 14:44:50 2010 CLST | +10:00:10
(15 rows)
-- these should fail
SELECT make_timestamptz(1973, 07, 15, 08, 15, 55.33, '2');
ERROR: invalid input syntax for numeric time zone: "2"
HINT: Numeric time zones must have "-" or "+" as first character.
SELECT make_timestamptz(2014, 12, 10, 10, 10, 10, '+16');
ERROR: numeric time zone "+16" out of range
SELECT make_timestamptz(2014, 12, 10, 10, 10, 10, '-16');
ERROR: numeric time zone "-16" out of range
-- 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)
-- full timezone name
SELECT make_timestamptz(2014, 12, 10, 0, 0, 0, 'Europe/Prague') = timestamptz '2014-12-10 00:00:00 Europe/Prague';
?column?
----------
t
(1 row)
SELECT make_timestamptz(2014, 12, 10, 0, 0, 0, 'Europe/Prague') AT TIME ZONE 'UTC';
timezone
--------------------------
Tue Dec 09 23:00:00 2014
(1 row)
SELECT make_timestamptz(1846, 12, 10, 0, 0, 0, 'Asia/Manila') AT TIME ZONE 'UTC';
timezone
--------------------------
Wed Dec 09 15:56:00 1846
(1 row)
SELECT make_timestamptz(1866, 12, 10, 0, 0, 0, 'America/Metlakatla') AT TIME ZONE 'UTC';
timezone
--------------------------
Sun Dec 09 08:46:18 1866
(1 row)
SELECT make_timestamptz(1901, 12, 10, 0, 0, 0, 'America/Metlakatla') AT TIME ZONE 'UTC';
timezone
--------------------------
Tue Dec 10 08:00:00 1901
(1 row)
SELECT make_timestamptz(2014, 12, 10, 0, 0, 0, 'Mars/Mons_Olympus');
ERROR: time zone "Mars/Mons_Olympus" not recognized
-- abbreviations
SELECT make_timestamptz(2008, 12, 10, 10, 10, 10, 'CLST');
make_timestamptz
-------------------------------
Wed Dec 10 10:10:10 2008 CLST
(1 row)
SELECT make_timestamptz(2008, 12, 10, 10, 10, 10, 'CLT');
make_timestamptz
-------------------------------
Wed Dec 10 11:10:10 2008 CLST
(1 row)
SELECT make_timestamptz(2014, 12, 10, 10, 10, 10, 'PST8PDT');
make_timestamptz
-------------------------------
Wed Dec 10 15:10:10 2014 CLST
(1 row)
RESET TimeZone;

View File

@ -261,3 +261,17 @@ 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(years := 1, months := -1, weeks := 5, days := -7, hours := 25, mins := -180);
select make_interval() = make_interval(years := 0, months := 0, weeks := 0, days := 0, mins := 0, secs := 0.0);
select make_interval(hours := -2, mins := -10, secs := -25.3);
select make_interval(years := 'inf'::float::int);
select make_interval(months := 'NaN'::float::int);
select make_interval(secs := 'inf');
select make_interval(secs := 'NaN');
select make_interval(secs := 7e12);

View File

@ -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);

View File

@ -254,3 +254,40 @@ INSERT INTO TIMESTAMPTZ_TST VALUES(4, '1000000312 23:58:48 IST');
SELECT * FROM TIMESTAMPTZ_TST ORDER BY a;
--Cleanup
DROP TABLE TIMESTAMPTZ_TST;
-- test timestamptz constructors
set TimeZone to 'America/Santiago';
-- numeric timezone
SELECT make_timestamptz(1973, 07, 15, 08, 15, 55.33);
SELECT make_timestamptz(1973, 07, 15, 08, 15, 55.33, '+2');
SELECT make_timestamptz(1973, 07, 15, 08, 15, 55.33, '-2');
WITH tzs (tz) AS (VALUES
('+1'), ('+1:'), ('+1:0'), ('+100'), ('+1:00'), ('+01:00'),
('+10'), ('+1000'), ('+10:'), ('+10:0'), ('+10:00'), ('+10:00:'),
('+10:00:1'), ('+10:00:01'),
('+10:00:10'))
SELECT make_timestamptz(2010, 2, 27, 3, 45, 00, tz), tz FROM tzs;
-- these should fail
SELECT make_timestamptz(1973, 07, 15, 08, 15, 55.33, '2');
SELECT make_timestamptz(2014, 12, 10, 10, 10, 10, '+16');
SELECT make_timestamptz(2014, 12, 10, 10, 10, 10, '-16');
-- should be true
SELECT make_timestamptz(1973, 07, 15, 08, 15, 55.33, '+2') = '1973-07-15 08:15:55.33+02'::timestamptz;
-- full timezone name
SELECT make_timestamptz(2014, 12, 10, 0, 0, 0, 'Europe/Prague') = timestamptz '2014-12-10 00:00:00 Europe/Prague';
SELECT make_timestamptz(2014, 12, 10, 0, 0, 0, 'Europe/Prague') AT TIME ZONE 'UTC';
SELECT make_timestamptz(1846, 12, 10, 0, 0, 0, 'Asia/Manila') AT TIME ZONE 'UTC';
SELECT make_timestamptz(1866, 12, 10, 0, 0, 0, 'America/Metlakatla') AT TIME ZONE 'UTC';
SELECT make_timestamptz(1901, 12, 10, 0, 0, 0, 'America/Metlakatla') AT TIME ZONE 'UTC';
SELECT make_timestamptz(2014, 12, 10, 0, 0, 0, 'Mars/Mons_Olympus');
-- abbreviations
SELECT make_timestamptz(2008, 12, 10, 10, 10, 10, 'CLST');
SELECT make_timestamptz(2008, 12, 10, 10, 10, 10, 'CLT');
SELECT make_timestamptz(2014, 12, 10, 10, 10, 10, 'PST8PDT');
RESET TimeZone;