diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml
index 453115f942..bd938a675a 100644
--- a/doc/src/sgml/datatype.sgml
+++ b/doc/src/sgml/datatype.sgml
@@ -2840,15 +2840,17 @@ P <optional> <replaceable>years</replaceable>-<replaceable>months</replaceable>-
     </para>
 
     <para>
-     In the verbose input format, and in some fields of the more compact
-     input formats, field values can have fractional parts; for example
-     <literal>'1.5 week'</literal> or <literal>'01:02:03.45'</literal>.  Such input is
-     converted to the appropriate number of months, days, and seconds
-     for storage.  When this would result in a fractional number of
-     months or days, the fraction is added to the lower-order fields
-     using the conversion factors 1 month = 30 days and 1 day = 24 hours.
-     For example, <literal>'1.5 month'</literal> becomes 1 month and 15 days.
-     Only seconds will ever be shown as fractional on output.
+     Field values can have fractional parts;  for example, <literal>'1.5
+     weeks'</literal> or <literal>'01:02:03.45'</literal>.  However,
+     because interval internally stores only three integer units (months,
+     days, seconds), fractional units must be spilled to smaller units.
+     For example, because months are approximated to equal 30 days,
+     fractional values of units greater than months is rounded to be the
+     nearest integer number of months.  Fractional units of months or less
+     are computed to be an integer number of days and seconds, assuming
+     24 hours per day.  For example, <literal>'1.5 months'</literal>
+     becomes <literal>1 month 15 days</literal>.  Only seconds will ever
+     be shown as fractional on output.
     </para>
 
     <para>
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 54ae632de2..cb3fa85892 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -3306,29 +3306,25 @@ DecodeInterval(char **field, int *ftype, int nf, int range,
 
 					case DTK_YEAR:
 						tm->tm_year += val;
-						if (fval != 0)
-							tm->tm_mon += fval * MONTHS_PER_YEAR;
+						tm->tm_mon += rint(fval * MONTHS_PER_YEAR);
 						tmask = DTK_M(YEAR);
 						break;
 
 					case DTK_DECADE:
 						tm->tm_year += val * 10;
-						if (fval != 0)
-							tm->tm_mon += fval * MONTHS_PER_YEAR * 10;
+						tm->tm_mon += rint(fval * MONTHS_PER_YEAR * 10);
 						tmask = DTK_M(DECADE);
 						break;
 
 					case DTK_CENTURY:
 						tm->tm_year += val * 100;
-						if (fval != 0)
-							tm->tm_mon += fval * MONTHS_PER_YEAR * 100;
+						tm->tm_mon += rint(fval * MONTHS_PER_YEAR * 100);
 						tmask = DTK_M(CENTURY);
 						break;
 
 					case DTK_MILLENNIUM:
 						tm->tm_year += val * 1000;
-						if (fval != 0)
-							tm->tm_mon += fval * MONTHS_PER_YEAR * 1000;
+						tm->tm_mon += rint(fval * MONTHS_PER_YEAR * 1000);
 						tmask = DTK_M(MILLENNIUM);
 						break;
 
@@ -3565,7 +3561,7 @@ DecodeISO8601Interval(char *str,
 			{
 				case 'Y':
 					tm->tm_year += val;
-					tm->tm_mon += (fval * MONTHS_PER_YEAR);
+					tm->tm_mon += rint(fval * MONTHS_PER_YEAR);
 					break;
 				case 'M':
 					tm->tm_mon += val;
@@ -3601,7 +3597,7 @@ DecodeISO8601Interval(char *str,
 						return DTERR_BAD_FORMAT;
 
 					tm->tm_year += val;
-					tm->tm_mon += (fval * MONTHS_PER_YEAR);
+					tm->tm_mon += rint(fval * MONTHS_PER_YEAR);
 					if (unit == '\0')
 						return 0;
 					if (unit == 'T')
diff --git a/src/interfaces/ecpg/pgtypeslib/interval.c b/src/interfaces/ecpg/pgtypeslib/interval.c
index 02b3c47223..a7e530cb5d 100644
--- a/src/interfaces/ecpg/pgtypeslib/interval.c
+++ b/src/interfaces/ecpg/pgtypeslib/interval.c
@@ -155,7 +155,7 @@ DecodeISO8601Interval(char *str,
 			{
 				case 'Y':
 					tm->tm_year += val;
-					tm->tm_mon += (fval * MONTHS_PER_YEAR);
+					tm->tm_mon += rint(fval * MONTHS_PER_YEAR);
 					break;
 				case 'M':
 					tm->tm_mon += val;
@@ -191,7 +191,7 @@ DecodeISO8601Interval(char *str,
 						return DTERR_BAD_FORMAT;
 
 					tm->tm_year += val;
-					tm->tm_mon += (fval * MONTHS_PER_YEAR);
+					tm->tm_mon += rint(fval * MONTHS_PER_YEAR);
 					if (unit == '\0')
 						return 0;
 					if (unit == 'T')
@@ -528,29 +528,25 @@ DecodeInterval(char **field, int *ftype, int nf,	/* int range, */
 
 					case DTK_YEAR:
 						tm->tm_year += val;
-						if (fval != 0)
-							tm->tm_mon += fval * MONTHS_PER_YEAR;
+						tm->tm_mon += rint(fval * MONTHS_PER_YEAR);
 						tmask = (fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR);
 						break;
 
 					case DTK_DECADE:
 						tm->tm_year += val * 10;
-						if (fval != 0)
-							tm->tm_mon += fval * MONTHS_PER_YEAR * 10;
+						tm->tm_mon += rint(fval * MONTHS_PER_YEAR * 10);
 						tmask = (fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR);
 						break;
 
 					case DTK_CENTURY:
 						tm->tm_year += val * 100;
-						if (fval != 0)
-							tm->tm_mon += fval * MONTHS_PER_YEAR * 100;
+						tm->tm_mon += rint(fval * MONTHS_PER_YEAR * 100);
 						tmask = (fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR);
 						break;
 
 					case DTK_MILLENNIUM:
 						tm->tm_year += val * 1000;
-						if (fval != 0)
-							tm->tm_mon += fval * MONTHS_PER_YEAR * 1000;
+						tm->tm_mon += rint(fval * MONTHS_PER_YEAR * 1000);
 						tmask = (fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR);
 						break;
 
