diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml
index 4f166e06bc73173232cc3a86f785996d938ab60b..093ce275af45e062c7766676dd836bdb51b11d8d 100644
--- a/doc/src/sgml/datatype.sgml
+++ b/doc/src/sgml/datatype.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/datatype.sgml,v 1.113 2003/01/31 01:08:07 tgl Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/datatype.sgml,v 1.114 2003/02/19 03:48:10 momjian Exp $
 -->
 
  <chapter id="datatype">
@@ -1243,7 +1243,7 @@ SELECT b, char_length(b) FROM test2;
         <entry>both date and time</entry>
         <entry>8 bytes</entry>
         <entry>4713 BC</entry>
-        <entry>AD 1465001</entry>
+        <entry>AD 5874897</entry>
         <entry>1 microsecond / 14 digits</entry>
        </row>
        <row>
@@ -1251,7 +1251,7 @@ SELECT b, char_length(b) FROM test2;
         <entry>both date and time</entry>
         <entry>8 bytes</entry>
         <entry>4713 BC</entry>
-        <entry>AD 1465001</entry>
+        <entry>AD 5874897</entry>
         <entry>1 microsecond / 14 digits</entry>
        </row>
        <row>
@@ -1309,7 +1309,8 @@ SELECT b, char_length(b) FROM test2;
     a few years of 2000-01-01, but the precision degrades for dates further
     away.  When timestamps are stored as eight-byte integers (a compile-time
     option), microsecond precision is available over the full range of
-    values.
+    values. However eight-byte integer timestamps have a reduced range of
+    dates from 4713 BC up to 294276 AD.
    </para>
    </note>
 
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index b73554bf2e6433474b6c23c563f6ddb4530c3101..994ab9fae084151a34d3253fc9aee9dca09c9d5e 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.99 2003/01/29 01:08:42 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.100 2003/02/19 03:48:10 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -587,66 +587,77 @@ static datetkn    *deltacache[MAXDATEFIELDS] = {NULL};
  *	since it is numerically accurate and computationally simple.
  * The algorithms here will accurately convert between Julian day
  *	and calendar date for all non-negative Julian days
- *	(i.e. from Nov 23, -4713 on).
- *
- * Ref: Explanatory Supplement to the Astronomical Almanac, 1992.
- *	University Science Books, 20 Edgehill Rd. Mill Valley CA 94941.
- *
- * Use the algorithm by Henry Fliegel, a former NASA/JPL colleague
- *	now at Aerospace Corp. (hi, Henry!)
+ *	(i.e. from Nov 24, -4713 on).
  *
  * These routines will be used by other date/time packages
  * - thomas 97/02/25
+ *
+ * Rewritten to eliminate overflow problems. This now allows the
+ * routines to work correctly for all Julian day counts from
+ * 0 to 2147483647  (Nov 24, -4713 to Jun 3, 5874898) assuming
+ * a 32-bit integer. Longer types should also work to the limits
+ * of their precision.
  */
 
 int
 date2j(int y, int m, int d)
 {
-	int			m12 = (m - 14) / 12;
+	int			julian;
+	int			century;
+
+	if (m > 2) {
+		m += 1;
+		y += 4800;
+	} else {
+		m += 13;
+		y += 4799;
+	}
+
+	century = y/100;
+	julian  = y*365 - 32167;
+	julian += y/4 - century + century/4;
+	julian += 7834*m/256 + d;
 
-	return ((1461 * (y + 4800 + m12)) / 4
-			+ (367 * (m - 2 - 12 * (m12))) / 12
-			- (3 * ((y + 4900 + m12) / 100)) / 4
-			+ d - 32075);
+	return julian;
 }	/* date2j() */
 
 void
 j2date(int jd, int *year, int *month, int *day)
 {
-	int			j,
-				y,
-				m,
-				d;
+	unsigned int		julian;
+	unsigned int		quad;
+	unsigned int		extra;
+	int			y;
+
+	julian = jd;
+	julian += 32044;
+	quad = julian/146097;
+	extra = (julian - quad*146097)*4 + 3;
+	julian += 60 + quad*3 + extra/146097;
+	quad = julian/1461;
+	julian -= quad*1461;
+	y = julian * 4 / 1461;
+	julian = ((y != 0) ? ((julian + 305) % 365) : ((julian + 306) % 366))
+		+ 123;
+	y += quad*4;
+	*year = y - 4800;
+	quad = julian * 2141 / 65536;
+	*day = julian - 7834*quad/256;
+	*month = (quad + 10) % 12 + 1;
 
-	int			i,
-				l,
-				n;
-
-	l = jd + 68569;
-	n = (4 * l) / 146097;
-	l -= (146097 * n + 3) / 4;
-	i = (4000 * (l + 1)) / 1461001;
-	l += 31 - (1461 * i) / 4;
-	j = (80 * l) / 2447;
-	d = l - (2447 * j) / 80;
-	l = j / 11;
-	m = (j + 2) - (12 * l);
-	y = 100 * (n - 49) + i + l;
-
-	*year = y;
-	*month = m;
-	*day = d;
 	return;
 }	/* j2date() */
 
 int
 j2day(int date)
 {
-	int			day;
+	unsigned int day;
 
-	day = (date + 1) % 7;
+	day = date;
+	day += 1;
+	day %= 7;
 
-	return day;
+	return (int) day;
 }	/* j2day() */
 
 
diff --git a/src/include/utils/datetime.h b/src/include/utils/datetime.h
index 3b81770152d7eec4b3e6ddbe8733136f22200636..251691325a571a52793c4dfb559a354e1eba5bdf 100644
--- a/src/include/utils/datetime.h
+++ b/src/include/utils/datetime.h
@@ -9,7 +9,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: datetime.h,v 1.34 2003/01/16 00:26:49 tgl Exp $
+ * $Id: datetime.h,v 1.35 2003/02/19 03:48:10 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -239,7 +239,7 @@ extern int	day_tab[2][13];
 
 #define JULIAN_MINYEAR (-4713)
 #define JULIAN_MINMONTH (11)
-#define JULIAN_MINDAY (23)
+#define JULIAN_MINDAY (24)
 
 #define IS_VALID_JULIAN(y,m,d) (((y) > JULIAN_MINYEAR) \
  || (((y) == JULIAN_MINYEAR) && (((m) > JULIAN_MINMONTH) \
diff --git a/src/test/regress/expected/horology-no-DST-before-1970.out b/src/test/regress/expected/horology-no-DST-before-1970.out
index ab40a6404ca182129bc576f50dffa244693aa6ee..5a191c9370c2b6e21d2c1d8dfcee0f6322a5c644 100644
--- a/src/test/regress/expected/horology-no-DST-before-1970.out
+++ b/src/test/regress/expected/horology-no-DST-before-1970.out
@@ -328,6 +328,30 @@ SELECT timestamp without time zone '1999-12-01' + interval '1 month - 1 second'
  Fri Dec 31 23:59:59 1999
 (1 row)
 
+SELECT timestamp without time zone 'Nov 24, 4714 BC' + interval '1000000000 days' AS "Nov 27, 2733194";
+       Nov 27, 2733194       
+-----------------------------
+ Sun Nov 27 00:00:00 2733194
+(1 row)
+
+SELECT timestamp without time zone 'Nov 24, 4714 BC' + interval '2000000000 days' AS "Nov 30, 5471101";
+       Nov 30, 5471101       
+-----------------------------
+ Sat Nov 30 00:00:00 5471101
+(1 row)
+
+SELECT timestamp without time zone 'Nov 25, 4714 BC' + interval '2147483492 days' AS "Dec 31, 5874897";
+       Dec 31, 5874897       
+-----------------------------
+ Tue Dec 31 00:00:00 5874897
+(1 row)
+
+SELECT timestamp without time zone '12/31/5874897' - timestamp without time zone 'Nov 24, 4714 BC' AS "2147483493 Days";
+  2147483493 Days  
+-------------------
+ @ 2147483493 days
+(1 row)
+
 -- Shorthand values
 -- Not directly usable for regression testing since these are not constants.
 -- So, just try to test parser and hope for the best - thomas 97/04/26
diff --git a/src/test/regress/expected/horology-solaris-1947.out b/src/test/regress/expected/horology-solaris-1947.out
index 222ee3036793d9d4de89f8ac549362de25c21088..784900531d74b5a85be78328453fa72dbc3ab4dd 100644
--- a/src/test/regress/expected/horology-solaris-1947.out
+++ b/src/test/regress/expected/horology-solaris-1947.out
@@ -328,6 +328,30 @@ SELECT timestamp without time zone '1999-12-01' + interval '1 month - 1 second'
  Fri Dec 31 23:59:59 1999
 (1 row)
 
+SELECT timestamp without time zone 'Nov 24, 4714 BC' + interval '1000000000 days' AS "Nov 27, 2733194";
+       Nov 27, 2733194       
+-----------------------------
+ Sun Nov 27 00:00:00 2733194
+(1 row)
+
+SELECT timestamp without time zone 'Nov 24, 4714 BC' + interval '2000000000 days' AS "Nov 30, 5471101";
+       Nov 30, 5471101       
+-----------------------------
+ Sat Nov 30 00:00:00 5471101
+(1 row)
+
+SELECT timestamp without time zone 'Nov 25, 4714 BC' + interval '2147483492 days' AS "Dec 31, 5874897";
+       Dec 31, 5874897       
+-----------------------------
+ Tue Dec 31 00:00:00 5874897
+(1 row)
+
+SELECT timestamp without time zone '12/31/5874897' - timestamp without time zone 'Nov 24, 4714 BC' AS "2147483493 Days";
+  2147483493 Days  
+-------------------
+ @ 2147483493 days
+(1 row)
+
 -- Shorthand values
 -- Not directly usable for regression testing since these are not constants.
 -- So, just try to test parser and hope for the best - thomas 97/04/26
diff --git a/src/test/regress/expected/horology.out b/src/test/regress/expected/horology.out
index 2735641e396b922fded794abc4a7a9ef240fe94a..d91df1bd8292aaf062260d5b06fee57b0cfc11a7 100644
--- a/src/test/regress/expected/horology.out
+++ b/src/test/regress/expected/horology.out
@@ -328,6 +328,30 @@ SELECT timestamp without time zone '1999-12-01' + interval '1 month - 1 second'
  Fri Dec 31 23:59:59 1999
 (1 row)
 
+SELECT timestamp without time zone 'Nov 24, 4714 BC' + interval '1000000000 days' AS "Nov 27, 2733194";
+       Nov 27, 2733194       
+-----------------------------
+ Sun Nov 27 00:00:00 2733194
+(1 row)
+
+SELECT timestamp without time zone 'Nov 24, 4714 BC' + interval '2000000000 days' AS "Nov 30, 5471101";
+       Nov 30, 5471101       
+-----------------------------
+ Sat Nov 30 00:00:00 5471101
+(1 row)
+
+SELECT timestamp without time zone 'Nov 25, 4714 BC' + interval '2147483492 days' AS "Dec 31, 5874897";
+       Dec 31, 5874897       
+-----------------------------
+ Tue Dec 31 00:00:00 5874897
+(1 row)
+
+SELECT timestamp without time zone '12/31/5874897' - timestamp without time zone 'Nov 24, 4714 BC' AS "2147483493 Days";
+  2147483493 Days  
+-------------------
+ @ 2147483493 days
+(1 row)
+
 -- Shorthand values
 -- Not directly usable for regression testing since these are not constants.
 -- So, just try to test parser and hope for the best - thomas 97/04/26
diff --git a/src/test/regress/sql/horology.sql b/src/test/regress/sql/horology.sql
index 0af769a8b2ca62ce65ed69f393ff39c6653131db..0ff15e9711fcbaeb6b7b7d9d2d112983dff17b7a 100644
--- a/src/test/regress/sql/horology.sql
+++ b/src/test/regress/sql/horology.sql
@@ -76,6 +76,10 @@ SELECT timestamp without time zone '1996-03-01' - interval '1 second' AS "Feb 29
 SELECT timestamp without time zone '1999-03-01' - interval '1 second' AS "Feb 28";
 SELECT timestamp without time zone '2000-03-01' - interval '1 second' AS "Feb 29";
 SELECT timestamp without time zone '1999-12-01' + interval '1 month - 1 second' AS "Dec 31";
+SELECT timestamp without time zone 'Nov 24, 4714 BC' + interval '1000000000 days' AS "Nov 27, 2733194";
+SELECT timestamp without time zone 'Nov 24, 4714 BC' + interval '2000000000 days' AS "Nov 30, 5471101";
+SELECT timestamp without time zone 'Nov 25, 4714 BC' + interval '2147483492 days' AS "Dec 31, 5874897";
+SELECT timestamp without time zone '12/31/5874897' - timestamp without time zone 'Nov 24, 4714 BC' AS "2147483493 Days";
 
 -- Shorthand values
 -- Not directly usable for regression testing since these are not constants.