<!--
-$PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.309 2006/03/06 04:53:50 momjian Exp $
+$PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.310 2006/03/06 22:49:15 momjian Exp $
PostgreSQL documentation
-->
<indexterm>
<primary>isfinite</primary>
</indexterm>
+ <indexterm>
+ <primary>justify_days</primary>
+ </indexterm>
<indexterm>
<primary>justify_hours</primary>
</indexterm>
<indexterm>
- <primary>justify_days</primary>
+ <primary>justify_interval</primary>
</indexterm>
<indexterm>
<primary>localtime</primary>
<entry><literal>true</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>justify_hours</function>(<type>interval</type>)</literal></entry>
<entry><type>interval</type></entry>
</row>
<row>
- <entry><literal><function>justify_days</function>(<type>interval</type>)</literal></entry>
+ <entry><literal><function>justify_interval</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>
+ <entry>Adjust interval using <function>justify_days</> and <function>justify_hours</>, with additional sign adjustments</></entry>
+ <entry><literal>justify_interval(interval '1 mon -1 hour')</literal></entry>
+ <entry><literal>29 days 23:00:00</literal></entry>
</row>
<row>
</tgroup>
</table>
- <para>
- If you are using both <function>justify_hours</> and
- <function>justify_days</>, it is best to use <function>justify_hours</>
- first so any additional days will be included in the
- <function>justify_days</> calculation.
- </para>
-
<para>
In addition to these functions, the SQL <literal>OVERLAPS</> operator is
supported:
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.161 2006/03/05 15:58:44 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.162 2006/03/06 22:49:16 momjian Exp $
*
*-------------------------------------------------------------------------
*/
PG_RETURN_INTERVAL_P(result);
}
+/*
+ * interval_justify_interval()
+ *
+ * Adjust interval so 'month', 'day', and 'time' portions are within
+ * customary bounds. Specifically:
+ *
+ * 0 <= abs(time) < 24 hours
+ * 0 <= abs(day) < 30 days
+ *
+ * Also, the sign bit on all three fields is made equal, so either
+ * all three fields are negative or all are positive.
+ */
+Datum
+interval_justify_interval(PG_FUNCTION_ARGS)
+{
+ Interval *span = PG_GETARG_INTERVAL_P(0);
+ Interval *result;
+
+#ifdef HAVE_INT64_TIMESTAMP
+ int64 wholeday;
+#else
+ double wholeday;
+#endif
+ int32 wholemonth;
+
+ result = (Interval *) palloc(sizeof(Interval));
+ result->month = span->month;
+ result->day = span->day;
+ result->time = span->time;
+
+#ifdef HAVE_INT64_TIMESTAMP
+ TMODULO(result->time, wholeday, USECS_PER_DAY);
+#else
+ TMODULO(result->time, wholeday, (double) SECS_PER_DAY);
+#endif
+ result->day += wholeday; /* could overflow... */
+
+ wholemonth = result->day / DAYS_PER_MONTH;
+ result->day -= wholemonth * DAYS_PER_MONTH;
+ result->month += wholemonth;
+
+ if (result->month > 0 &&
+ (result->day < 0 || (result->day == 0 && result->time < 0)))
+ {
+ result->day += DAYS_PER_MONTH;
+ result->month--;
+ }
+ else if (result->month < 0 &&
+ (result->day > 0 || (result->day == 0 && result->time > 0)))
+ {
+ result->day -= DAYS_PER_MONTH;
+ result->month++;
+ }
+
+ if (result->day > 0 && result->time < 0)
+ {
+#ifdef HAVE_INT64_TIMESTAMP
+ result->time += USECS_PER_DAY;
+#else
+ result->time += (double) SECS_PER_DAY;
+#endif
+ result->day--;
+ }
+ else if (result->day < 0 && result->time > 0)
+ {
+#ifdef HAVE_INT64_TIMESTAMP
+ result->time -= USECS_PER_DAY;
+#else
+ result->time -= (double) SECS_PER_DAY;
+#endif
+ result->day++;
+ }
+
+ PG_RETURN_INTERVAL_P(result);
+}
+
/*
* interval_justify_hours()
*
#endif
result->day += wholeday; /* could overflow... */
+ if (result->day > 0 && result->time < 0)
+ {
+#ifdef HAVE_INT64_TIMESTAMP
+ result->time += USECS_PER_DAY;
+#else
+ result->time += (double) SECS_PER_DAY;
+#endif
+ result->day--;
+ }
+ else if (result->day < 0 && result->time > 0)
+ {
+#ifdef HAVE_INT64_TIMESTAMP
+ result->time -= USECS_PER_DAY;
+#else
+ result->time -= (double) SECS_PER_DAY;
+#endif
+ result->day++;
+ }
+
PG_RETURN_INTERVAL_P(result);
}
result->day -= wholemonth * DAYS_PER_MONTH;
result->month += wholemonth;
+ if (result->month > 0 && result->day < 0)
+ {
+ result->day += DAYS_PER_MONTH;
+ result->month--;
+ }
+ else if (result->month < 0 && result->day > 0)
+ {
+ result->day -= DAYS_PER_MONTH;
+ result->month++;
+ }
+
PG_RETURN_INTERVAL_P(result);
}
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.318 2006/03/05 15:58:54 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.319 2006/03/06 22:49:16 momjian Exp $
*
*-------------------------------------------------------------------------
*/
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 200602281
+#define CATALOG_VERSION_NO 200603061
#endif
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.400 2006/03/05 15:58:54 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.401 2006/03/06 22:49:16 momjian Exp $
*
* NOTES
* The script catalog/genbki.sh reads this file and generates .bki
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 = 2711 ( justify_interval PGNSP PGUID 12 f f t f i 1 1186 "1186" _null_ _null_ _null_ interval_justify_interval - _null_ ));
+DESCR("promote groups of 24 hours to numbers of days and promote groups of 30 days to numbers of months");
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_ ));
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/utils/timestamp.h,v 1.58 2006/03/05 15:59:08 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/utils/timestamp.h,v 1.59 2006/03/06 22:49:17 momjian Exp $
*
*-------------------------------------------------------------------------
*/
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_interval(PG_FUNCTION_ARGS);
extern Datum interval_justify_hours(PG_FUNCTION_ARGS);
extern Datum interval_justify_days(PG_FUNCTION_ARGS);
@ 7 mons 6 days 5 hours 4 mins 3 secs
(1 row)
+-- test justify_interval()
+SELECT justify_interval(interval '1 month -1 hour') as "1 month -1 hour";
+ 1 month -1 hour
+--------------------
+ @ 29 days 23 hours
+(1 row)
+
SELECT justify_hours(interval '6 months 3 days 52 hours 3 minutes 2 seconds') as "6 mons 5 days 4 hours 3 mins 2 seconds";
SELECT justify_days(interval '6 months 36 days 5 hours 4 minutes 3 seconds') as "7 mons 6 days 5 hours 4 mins 3 seconds";
+-- test justify_interval()
+
+SELECT justify_interval(interval '1 month -1 hour') as "1 month -1 hour";