Commit db05f4a7 authored by Bruce Momjian's avatar Bruce Momjian

Add 'day' field to INTERVAL so 1 day interval can be distinguished from

24 hours. This is very helpful for daylight savings time:

	select '2005-05-03 00:00:00 EST'::timestamp with time zone + '24 hours';
	      ?column?
	----------------------
	2005-05-04 01:00:00-04

	select '2005-05-03 00:00:00 EST'::timestamp with time zone + '1 day';
	      ?column?
	----------------------
	2005-05-04 01:00:00-04

Michael Glaesemann
parent 826604f9
<!--
$PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.267 2005/07/18 22:34:14 tgl Exp $
$PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.268 2005/07/20 16:42:29 momjian Exp $
PostgreSQL documentation
-->
......@@ -5144,6 +5144,22 @@ SELECT SUBSTRING('XY1234Z', 'Y*?([0-9]{1,3})');
<entry><literal>true</literal></entry>
</row>
<row>
<entry><literal><function>justify_hours</function>(<type>interval</type>)</literal></entry>
<entry><type>interval</type></entry>
<entry>Adjust interval so 24-hour time periods are represented as days</entry>
<entry><literal>justify_hours(interval '24 hours')</literal></entry>
<entry><literal>1 day</literal></entry>
</row>
<row>
<entry><literal><function>justify_days</function>(<type>interval</type>)</literal></entry>
<entry><type>interval</type></entry>
<entry>Adjust interval so 30-day time periods are represented as months</entry>
<entry><literal>justify_days(interval '30 days')</literal></entry>
<entry><literal>1 month</literal></entry>
</row>
<row>
<entry><literal><function>localtime</function></literal></entry>
<entry><type>time</type></entry>
......
......@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/variable.c,v 1.109 2005/06/28 05:08:55 tgl Exp $
* $PostgreSQL: pgsql/src/backend/commands/variable.c,v 1.110 2005/07/20 16:42:30 momjian Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -292,6 +292,15 @@ assign_timezone(const char *value, bool doit, GucSource source)
pfree(interval);
return NULL;
}
if (interval->day != 0)
{
if (source >= PGC_S_INTERACTIVE)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid interval value for time zone: day not allowed")));
pfree(interval);
return NULL;
}
if (doit)
{
/* Here we change from SQL to Unix sign convention */
......@@ -414,6 +423,7 @@ show_timezone(void)
Interval interval;
interval.month = 0;
interval.day = 0;
#ifdef HAVE_INT64_TIMESTAMP
interval.time = -(CTimeZone * USECS_PER_SEC);
#else
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.112 2005/07/12 15:17:44 momjian Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.113 2005/07/20 16:42:30 momjian Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -1423,6 +1423,7 @@ time_interval(PG_FUNCTION_ARGS)
result = (Interval *) palloc(sizeof(Interval));
result->time = time;
result->day = 0;
result->month = 0;
PG_RETURN_INTERVAL_P(result);
......@@ -1477,8 +1478,9 @@ time_mi_time(PG_FUNCTION_ARGS)
result = (Interval *) palloc(sizeof(Interval));
result->time = (time1 - time2);
result->month = 0;
result->day = 0;
result->time = time1 - time2;
PG_RETURN_INTERVAL_P(result);
}
......
/* -----------------------------------------------------------------------
* formatting.c
*
* $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.90 2005/06/24 01:10:11 neilc Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.91 2005/07/20 16:42:30 momjian Exp $
*
*
* Portions Copyright (c) 1999-2005, PostgreSQL Global Development Group
......@@ -899,7 +899,7 @@ static char *str_tolower(char *buff);
/* static int is_acdc(char *str, int *len); */
static int seq_search(char *name, char **array, int type, int max, int *len);
static void do_to_timestamp(text *date_txt, text *fmt,
struct pg_tm * tm, fsec_t *fsec);
struct pg_tm *tm, fsec_t *fsec);
static char *fill_str(char *str, int c, int max);
static FormatNode *NUM_cache(int len, NUMDesc *Num, char *pars_str, bool *shouldFree);
static char *int_to_roman(int number);
......@@ -3028,7 +3028,7 @@ to_date(PG_FUNCTION_ARGS)
*/
static void
do_to_timestamp(text *date_txt, text *fmt,
struct pg_tm * tm, fsec_t *fsec)
struct pg_tm *tm, fsec_t *fsec)
{
FormatNode *format;
TmFromChar tmfc;
......
......@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/nabstime.c,v 1.135 2005/07/12 16:04:56 momjian Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/nabstime.c,v 1.136 2005/07/20 16:42:30 momjian Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -829,7 +829,8 @@ interval_reltime(PG_FUNCTION_ARGS)
Interval *interval = PG_GETARG_INTERVAL_P(0);
RelativeTime time;
int year,
month;
month,
day;
#ifdef HAVE_INT64_TIMESTAMP
int64 span;
......@@ -837,28 +838,17 @@ interval_reltime(PG_FUNCTION_ARGS)
double span;
#endif
if (interval->month == 0)
{
year = 0;
month = 0;
}
else if (abs(interval->month) >=12)
{
year = (interval->month / 12);
month = (interval->month % 12);
}
else
{
year = 0;
month = interval->month;
}
year = interval->month / 12;
month = interval->month % 12;
day = interval->day;
#ifdef HAVE_INT64_TIMESTAMP
span = ((INT64CONST(365250000) * year + INT64CONST(30000000) * month) *
INT64CONST(86400)) + interval->time;
span = ((INT64CONST(365250000) * year + INT64CONST(30000000) * month +
INT64CONST(1000000) * day) * INT64CONST(86400)) +
interval->time;
span /= USECS_PER_SEC;
#else
span = (365.25 * year + 30.0 * month) * SECS_PER_DAY + interval->time;
span = (365.25 * year + 30.0 * month + day) * SECS_PER_DAY + interval->time;
#endif
if (span < INT_MIN || span > INT_MAX)
......@@ -876,7 +866,8 @@ reltime_interval(PG_FUNCTION_ARGS)
RelativeTime reltime = PG_GETARG_RELATIVETIME(0);
Interval *result;
int year,
month;
month,
day;
result = (Interval *) palloc(sizeof(Interval));
......@@ -887,6 +878,7 @@ reltime_interval(PG_FUNCTION_ARGS)
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot convert reltime \"invalid\" to interval")));
result->time = 0;
result->day = 0;
result->month = 0;
break;
......@@ -896,15 +888,19 @@ reltime_interval(PG_FUNCTION_ARGS)
reltime -= (year * (36525 * 864));
month = (reltime / (30 * SECS_PER_DAY));
reltime -= (month * (30 * SECS_PER_DAY));
day = reltime / SECS_PER_DAY;
reltime -= day * SECS_PER_DAY;
result->time = (reltime * USECS_PER_SEC);
#else
TMODULO(reltime, year, 36525 * 864);
TMODULO(reltime, month, 30 * SECS_PER_DAY);
TMODULO(reltime, day, SECS_PER_DAY);
result->time = reltime;
#endif
result->month = 12 * year + month;
result->day = day;
break;
}
......
......@@ -15,7 +15,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.184 2005/07/12 16:04:57 momjian Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.185 2005/07/20 16:42:30 momjian Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -2784,10 +2784,11 @@ convert_timevalue_to_scalar(Datum value, Oid typid)
* too accurate, but plenty good enough for our purposes.
*/
#ifdef HAVE_INT64_TIMESTAMP
return (interval->time + (interval->month * ((365.25 / 12.0) * 86400000000.0)));
return interval->time + interval->day * (double)USECS_PER_DAY +
interval->month * ((365.25 / 12.0) * USECS_PER_DAY);
#else
return interval->time +
interval ->month * (365.25 / 12.0 * 24.0 * 60.0 * 60.0);
return interval->time + interval->day * SECS_PER_DAY +
interval->month * ((365.25 / 12.0) * (double)SECS_PER_DAY);
#endif
}
case RELTIMEOID:
......
This diff is collapsed.
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.376 2005/07/10 21:13:59 tgl Exp $
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.377 2005/07/20 16:42:31 momjian Exp $
*
* NOTES
* The script catalog/genbki.sh reads this file and generates .bki
......@@ -1497,6 +1497,10 @@ DATA(insert OID = 1173 ( timestamptz PGNSP PGUID 12 f f t f i 1 1184 "702" _
DESCR("convert abstime to timestamp with time zone");
DATA(insert OID = 1174 ( timestamptz PGNSP PGUID 12 f f t f s 1 1184 "1082" _null_ _null_ _null_ date_timestamptz - _null_ ));
DESCR("convert date to timestamp with time zone");
DATA(insert OID = 1175 ( justify_hours PGNSP PGUID 12 f f t f i 1 1186 "1186" _null_ _null_ _null_ interval_justify_hours - _null_ ));
DESCR("promote groups of 24 hours to numbers of days");
DATA(insert OID = 1295 ( justify_days PGNSP PGUID 12 f f t f i 1 1186 "1186" _null_ _null_ _null_ interval_justify_days - _null_ ));
DESCR("promote groups of 30 days to numbers of months");
DATA(insert OID = 1176 ( timestamptz PGNSP PGUID 14 f f t f s 2 1184 "1082 1083" _null_ _null_ _null_ "select cast(($1 + $2) as timestamp with time zone)" - _null_ ));
DESCR("convert date and time to timestamp with time zone");
DATA(insert OID = 1177 ( interval PGNSP PGUID 12 f f t f i 1 1186 "703" _null_ _null_ _null_ reltime_interval - _null_ ));
......
......@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/pg_type.h,v 1.163 2005/07/07 20:39:59 tgl Exp $
* $PostgreSQL: pgsql/src/include/catalog/pg_type.h,v 1.164 2005/07/20 16:42:32 momjian Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
......@@ -457,7 +457,7 @@ DATA(insert OID = 1184 ( timestamptz PGNSP PGUID 8 f b t \054 0 0 timestamptz_in
DESCR("date and time with time zone");
#define TIMESTAMPTZOID 1184
DATA(insert OID = 1185 ( _timestamptz PGNSP PGUID -1 f b t \054 0 1184 array_in array_out array_recv array_send - d x f 0 -1 0 _null_ _null_ ));
DATA(insert OID = 1186 ( interval PGNSP PGUID 12 f b t \054 0 0 interval_in interval_out interval_recv interval_send - d p f 0 -1 0 _null_ _null_ ));
DATA(insert OID = 1186 ( interval PGNSP PGUID 16 f b t \054 0 0 interval_in interval_out interval_recv interval_send - d p f 0 -1 0 _null_ _null_ ));
DESCR("@ <number> <units>, time interval");
#define INTERVALOID 1186
DATA(insert OID = 1187 ( _interval PGNSP PGUID -1 f b t \054 0 1186 array_in array_out array_recv array_send - d x f 0 -1 0 _null_ _null_ ));
......
......@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/utils/timestamp.h,v 1.46 2005/06/29 22:51:57 tgl Exp $
* $PostgreSQL: pgsql/src/include/utils/timestamp.h,v 1.47 2005/07/20 16:42:32 momjian Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -25,9 +25,9 @@
/*
* Timestamp represents absolute time.
* Interval represents delta time. Keep track of months (and years)
* separately since the elapsed time spanned is unknown until instantiated
* relative to an absolute time.
* Interval represents delta time. Keep track of months (and years), days,
* and time separately since the elapsed time spanned is unknown until
* instantiated relative to an absolute time.
*
* Note that Postgres uses "time interval" to mean a bounded interval,
* consisting of a beginning and ending time, not a time span - thomas 97/03/20
......@@ -45,12 +45,13 @@ typedef double TimestampTz;
typedef struct
{
#ifdef HAVE_INT64_TIMESTAMP
int64 time; /* all time units other than months and
* years */
int64 time; /* all time units other than days,
* months and years */
#else
double time; /* all time units other than months and
* years */
double time; /* all time units other than days,
* months and years */
#endif
int32 day; /* days, after time for alignment */
int32 month; /* months and years, after time for
* alignment */
} Interval;
......@@ -60,6 +61,7 @@ typedef struct
#define MAX_INTERVAL_PRECISION 6
#define SECS_PER_DAY 86400
#define SECS_PER_HOUR 3600
#ifdef HAVE_INT64_TIMESTAMP
#define USECS_PER_DAY INT64CONST(86400000000)
#define USECS_PER_HOUR INT64CONST(3600000000)
......@@ -212,6 +214,8 @@ extern Datum interval_cmp(PG_FUNCTION_ARGS);
extern Datum interval_hash(PG_FUNCTION_ARGS);
extern Datum interval_smaller(PG_FUNCTION_ARGS);
extern Datum interval_larger(PG_FUNCTION_ARGS);
extern Datum interval_justify_hours(PG_FUNCTION_ARGS);
extern Datum interval_justify_days(PG_FUNCTION_ARGS);
extern Datum timestamp_text(PG_FUNCTION_ARGS);
extern Datum text_timestamp(PG_FUNCTION_ARGS);
......@@ -266,16 +270,16 @@ extern Datum pgsql_postmaster_start_time(PG_FUNCTION_ARGS);
extern TimestampTz GetCurrentTimestamp(void);
extern int tm2timestamp(struct pg_tm * tm, fsec_t fsec, int *tzp, Timestamp *dt);
extern int timestamp2tm(Timestamp dt, int *tzp, struct pg_tm * tm,
extern int tm2timestamp(struct pg_tm *tm, fsec_t fsec, int *tzp, Timestamp *dt);
extern int timestamp2tm(Timestamp dt, int *tzp, struct pg_tm *tm,
fsec_t *fsec, char **tzn, pg_tz *attimezone);
extern void dt2time(Timestamp dt, int *hour, int *min, int *sec, fsec_t *fsec);
extern int interval2tm(Interval span, struct pg_tm * tm, fsec_t *fsec);
extern int tm2interval(struct pg_tm * tm, fsec_t fsec, Interval *span);
extern int interval2tm(Interval span, struct pg_tm *tm, fsec_t *fsec);
extern int tm2interval(struct pg_tm *tm, fsec_t fsec, Interval *span);
extern Timestamp SetEpochTimestamp(void);
extern void GetEpochTime(struct pg_tm * tm);
extern void GetEpochTime(struct pg_tm *tm);
extern int timestamp_cmp_internal(Timestamp dt1, Timestamp dt2);
......
......@@ -33,7 +33,7 @@ TrimTrailingZeros(char *str)
* can be used to represent time spans.
*/
static int
DecodeTime(char *str, int fmask, int *tmask, struct tm * tm, fsec_t *fsec)
DecodeTime(char *str, int fmask, int *tmask, struct tm *tm, fsec_t *fsec)
{
char *cp;
......@@ -107,7 +107,7 @@ DecodeTime(char *str, int fmask, int *tmask, struct tm * tm, fsec_t *fsec)
* preceding an hh:mm:ss field. - thomas 1998-04-30
*/
int
DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm * tm, fsec_t *fsec)
DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm *tm, fsec_t *fsec)
{
int is_before = FALSE;
......@@ -445,7 +445,7 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm * tm, fse
* - thomas 1998-04-30
*/
int
EncodeInterval(struct tm * tm, fsec_t fsec, int style, char *str)
EncodeInterval(struct tm *tm, fsec_t fsec, int style, char *str)
{
int is_before = FALSE;
int is_nonzero = FALSE;
......@@ -670,7 +670,7 @@ EncodeInterval(struct tm * tm, fsec_t fsec, int style, char *str)
* Convert a interval data type to a tm structure.
*/
static int
interval2tm(interval span, struct tm * tm, fsec_t *fsec)
interval2tm(interval span, struct tm *tm, fsec_t *fsec)
{
#ifdef HAVE_INT64_TIMESTAMP
int64 time;
......@@ -713,7 +713,7 @@ interval2tm(interval span, struct tm * tm, fsec_t *fsec)
} /* interval2tm() */
static int
tm2interval(struct tm * tm, fsec_t fsec, interval *span)
tm2interval(struct tm *tm, fsec_t fsec, interval *span)
{
span->month = tm->tm_year * 12 + tm->tm_mon;
#ifdef HAVE_INT64_TIMESTAMP
......
......@@ -29,20 +29,20 @@ SELECT INTERVAL '-05' AS "Five hours";
SELECT INTERVAL '-1 +02:03' AS "22 hours ago...";
22 hours ago...
-----------------
-21:57:00
-------------------
-1 days +02:03:00
(1 row)
SELECT INTERVAL '-1 days +02:03' AS "22 hours ago...";
22 hours ago...
-----------------
-21:57:00
-------------------
-1 days +02:03:00
(1 row)
SELECT INTERVAL '10 years -11 month -12 days +13:14' AS "9 years...";
9 years...
----------------------------------
9 years 1 mon -11 days -10:46:00
9 years 1 mon -12 days +13:14:00
(1 row)
CREATE TABLE INTERVAL_TBL (f1 interval);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment