Index: src/backend/utils/adt/timestamp.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/timestamp.c,v
retrieving revision 1.160
diff --context -r1.160 timestamp.c
*** src/backend/utils/adt/timestamp.c	22 Nov 2005 22:30:33 -0000	1.160
--- src/backend/utils/adt/timestamp.c	3 Mar 2006 20:23:26 -0000
***************
*** 1975,1980 ****
--- 1975,2054 ----
  }
  
  /*
+  *  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 -= DAYS_PER_MONTH;
+ 		result->month++;
+ 	}
+ 	else if (result->month > 0 && result->day < 0)
+ 	{
+ 		result->day += DAYS_PER_MONTH;
+ 		result->month--;
+ 	}
+ 
+ 	if (result->time < 0 && result->day > 0)
+ 	{
+ #ifdef HAVE_INT64_TIMESTAMP
+ 		result->time += USECS_PER_DAY;
+ #else
+ 		result->time += (double) SECS_PER_DAY;
+ #endif
+ 		result->day--;
+ 	}
+ 	else if (result->time > 0 && result->day < 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()
   *
   *	Adjust interval so 'time' contains less than a whole day, adding
***************
*** 2006,2011 ****
--- 2080,2104 ----
  #endif
  	result->day += wholeday;	/* could overflow... */
  
+ 	if (result->time < 0 && result->day > 0)
+ 	{
+ #ifdef HAVE_INT64_TIMESTAMP
+ 		result->time += USECS_PER_DAY;
+ #else
+ 		result->time += (double) SECS_PER_DAY;
+ #endif
+ 		result->day--;
+ 	}
+ 	else if (result->time > 0 && result->day < 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);
  }
  
***************
*** 2031,2036 ****
--- 2124,2140 ----
  	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);
  }
  
Index: src/include/catalog/pg_proc.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/catalog/pg_proc.h,v
retrieving revision 1.399
diff --context -r1.399 pg_proc.h
*** src/include/catalog/pg_proc.h	28 Feb 2006 22:37:26 -0000	1.399
--- src/include/catalog/pg_proc.h	3 Mar 2006 20:23:27 -0000
***************
*** 1462,1467 ****
--- 1462,1469 ----
  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_ ));
Index: src/include/utils/timestamp.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/utils/timestamp.h,v
retrieving revision 1.57
diff --context -r1.57 timestamp.h
*** src/include/utils/timestamp.h	15 Oct 2005 02:49:46 -0000	1.57
--- src/include/utils/timestamp.h	3 Mar 2006 20:23:27 -0000
***************
*** 234,239 ****
--- 234,240 ----
  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);
  
