diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 7d603ef97822848a61f278ca0331aabfe6e0e3cd..f3df61817981f7d455d268291d8fb9be4652b0c5 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.296 2005/11/28 23:18:48 momjian Exp $
+$PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.297 2005/12/03 16:45:05 momjian Exp $
 PostgreSQL documentation
 -->
 
@@ -4749,6 +4749,14 @@ SELECT SUBSTRING('XY1234Z', 'Y*?([0-9]{1,3})');
         <function>extract</function> function.
       </para>
      </listitem>
+
+     <listitem>
+      <para><function>to_char(interval)</function> formats <literal>HH</> and 
+        <literal>HH12</> as hours in a single day, while <literal>HH24</>
+        can output hours exceeding a single day, e.g. &gt;24.
+      </para>
+     </listitem>
+
     </itemizedlist>
    </para>
 
diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c
index 224f3e5b3db47cd5a61b325460d8e69638c9a274..ec910b5f33ad9da8d1d21b8e1b44ad88cf5c969a 100644
--- a/src/backend/utils/adt/formatting.c
+++ b/src/backend/utils/adt/formatting.c
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------
  * formatting.c
  *
- * $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.102 2005/11/22 18:17:22 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.103 2005/12/03 16:45:06 momjian Exp $
  *
  *
  *	 Portions Copyright (c) 1999-2005, PostgreSQL Global Development Group
@@ -434,6 +434,10 @@ do { \
 	tmtcTzn(_X) = NULL; \
 } while(0)
 
+/*
+ *	to_char(time) appears to to_char() as an interval, so this check
+ *	is really for interval and time data types.
+ */
 #define INVALID_FOR_INTERVAL  \
 do { \
 	if (is_interval) \
@@ -1722,11 +1726,10 @@ dch_time(int arg, char *inout, int suf, bool is_to_char, bool is_interval,
 	{
 		case DCH_A_M:
 		case DCH_P_M:
-			INVALID_FOR_INTERVAL;
 			if (is_to_char)
 			{
-				strcpy(inout, ((tm->tm_hour > 11
-					   && tm->tm_hour < HOURS_PER_DAY) ? P_M_STR : A_M_STR));
+				strcpy(inout, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
+					   ? P_M_STR : A_M_STR);
 				return strlen(p_inout);
 			}
 			else
@@ -1742,11 +1745,10 @@ dch_time(int arg, char *inout, int suf, bool is_to_char, bool is_interval,
 			break;
 		case DCH_AM:
 		case DCH_PM:
-			INVALID_FOR_INTERVAL;
 			if (is_to_char)
 			{
-				strcpy(inout, ((tm->tm_hour > 11
-						 && tm->tm_hour < HOURS_PER_DAY) ? PM_STR : AM_STR));
+				strcpy(inout, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
+					   ? PM_STR : AM_STR);
 				return strlen(p_inout);
 			}
 			else
@@ -1762,11 +1764,10 @@ dch_time(int arg, char *inout, int suf, bool is_to_char, bool is_interval,
 			break;
 		case DCH_a_m:
 		case DCH_p_m:
-			INVALID_FOR_INTERVAL;
 			if (is_to_char)
 			{
-				strcpy(inout, ((tm->tm_hour > 11
-					   && tm->tm_hour < HOURS_PER_DAY) ? p_m_STR : a_m_STR));
+				strcpy(inout, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
+					   ? p_m_STR : a_m_STR);
 				return strlen(p_inout);
 			}
 			else
@@ -1782,11 +1783,10 @@ dch_time(int arg, char *inout, int suf, bool is_to_char, bool is_interval,
 			break;
 		case DCH_am:
 		case DCH_pm:
-			INVALID_FOR_INTERVAL;
 			if (is_to_char)
 			{
-				strcpy(inout, ((tm->tm_hour > 11
-						 && tm->tm_hour < HOURS_PER_DAY) ? pm_STR : am_STR));
+				strcpy(inout, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
+					   ? pm_STR : am_STR);
 				return strlen(p_inout);
 			}
 			else
@@ -1804,12 +1804,9 @@ dch_time(int arg, char *inout, int suf, bool is_to_char, bool is_interval,
 		case DCH_HH12:
 			if (is_to_char)
 			{
-				if (is_interval)
-					sprintf(inout, "%0*d", S_FM(suf) ? 0 : 2, tm->tm_hour);
-				else
-					sprintf(inout, "%0*d", S_FM(suf) ? 0 : 2,
-							tm->tm_hour == 0 ? 12 :
-						  tm->tm_hour < 13 ? tm->tm_hour : tm->tm_hour - 12);
+				sprintf(inout, "%0*d", S_FM(suf) ? 0 : 2,
+						tm->tm_hour % (HOURS_PER_DAY / 2) == 0 ? 12 :
+					    tm->tm_hour % (HOURS_PER_DAY / 2));
 				if (S_THth(suf))
 					str_numth(p_inout, inout, 0);
 				return strlen(p_inout);
@@ -2312,7 +2309,6 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, bool is_interval,
 			}
 			break;
 		case DCH_D:
-			INVALID_FOR_INTERVAL;
 			if (is_to_char)
 			{
 				sprintf(inout, "%d", tm->tm_wday + 1);