diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 19d357651786157e5b26e1f2f4c057704df0a7ba..139c81effc3727ab630bef56727ee9f6547601b2 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.196 2004/03/30 15:53:18 momjian Exp $
+$PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.197 2004/04/10 18:02:59 momjian Exp $
 PostgreSQL documentation
 -->
 
@@ -4948,18 +4948,31 @@ EXTRACT (<replaceable>field</replaceable> FROM <replaceable>source</replaceable>
       <term><literal>century</literal></term>
       <listitem>
        <para>
-        The year field divided by 100
+        The historical definition of a century.
        </para>
 
 <screen>
-SELECT EXTRACT(CENTURY FROM TIMESTAMP '2001-02-16 20:38:40');
+SELECT EXTRACT(CENTURY FROM TIMESTAMP '2000-12-16 12:21:13');
 <lineannotation>Result: </lineannotation><computeroutput>20</computeroutput>
+SELECT EXTRACT(CENTURY FROM TIMESTAMP '2001-02-16 20:38:40');
+<lineannotation>Result: </lineannotation><computeroutput>21</computeroutput>
 </screen>
 
        <para>
-        Note that the result for the century field is simply the year field
-        divided by 100, and not the conventional definition which puts most
-        years in the 1900's in the twentieth century.
+        An historical century is a period of 100 years.
+	The first century starts at 0001-01-01 00:00:00 AD, although
+	they did not know at the time. This definition applies to all
+	Gregorian calendar countries. There is no number 0 century, 
+	you go from -1 to 1.
+
+	If you disagree with this, please write your complaint to:
+	Pope, Cathedral Saint-Peter of Roma, Vatican.
+       </para>
+
+       <para>
+	Compatibility: if you want the previous postgres version of century,
+	just divide the year by 100. Note that with this definition, 
+	century number 0 lasts 200 years.
        </para>
       </listitem>
      </varlistentry>
@@ -5083,18 +5096,17 @@ SELECT EXTRACT(MICROSECONDS FROM TIME '17:12:28.5');
       <term><literal>millennium</literal></term>
       <listitem>
        <para>
-        The year field divided by 1000
+        The conventional historical millennium.
        </para>
 
 <screen>
 SELECT EXTRACT(MILLENNIUM FROM TIMESTAMP '2001-02-16 20:38:40');
-<lineannotation>Result: </lineannotation><computeroutput>2</computeroutput>
+<lineannotation>Result: </lineannotation><computeroutput>3</computeroutput>
 </screen>
 
        <para>
-        Note that the result for the millennium field is simply the year field
-        divided by 1000, and not the conventional definition which puts
-        years in the 1900's in the second millennium.
+        Years in the 1900's are in the second millennium.
+	The third millennium starts January 1, 2001.
        </para>
       </listitem>
      </varlistentry>
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index dafc8ae5bedace622f141063ac7d7a4b17b28f8f..b2628a3a6f6aa4ea8fea63951607cf6175c5191a 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.103 2004/03/30 15:53:18 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.104 2004/04/10 18:02:59 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -3273,11 +3273,23 @@ timestamp_part(PG_FUNCTION_ARGS)
 				break;
 
 			case DTK_CENTURY:
-				result = (tm->tm_year / 100);
+				/* centuries AD, c>0: year in [ (c-1)*100+1 :     c*100   ]
+				 * centuries BC, c<0: year in [     c*100   : (c+1)*100-1 ]
+				 * there is no number 0 century.
+				 */
+				if (tm->tm_year > 0)
+					result = ((tm->tm_year+99) / 100);
+				else
+					/* caution: C division may yave negative remainder */
+					result = - ((99 - (tm->tm_year-1))/100);
 				break;
 
 			case DTK_MILLENNIUM:
-				result = (tm->tm_year / 1000);
+				/* see comments above. */
+				if (tm->tm_year > 0)
+					result = ((tm->tm_year+999) / 1000);
+				else
+					result = - ((999 - (tm->tm_year-1))/1000);
 				break;
 
 			case DTK_JULIAN:
diff --git a/src/test/regress/expected/date.out b/src/test/regress/expected/date.out
index 20ffaf188defcab7fabf24b1aca855a38b59ab8e..77bbdb967624ef745babdb83f95250fed8822dd2 100644
--- a/src/test/regress/expected/date.out
+++ b/src/test/regress/expected/date.out
@@ -819,3 +819,114 @@ SELECT date 'tomorrow' - date 'yesterday' AS "Two days";
         2
 (1 row)
 
+--
+-- test extract!
+--
+-- century
+--
+SELECT EXTRACT(CENTURY FROM DATE '0101-12-31 BC'); -- -2
+ date_part 
+-----------
+        -2
+(1 row)
+
+SELECT EXTRACT(CENTURY FROM DATE '0100-12-31 BC'); -- -1
+ date_part 
+-----------
+        -1
+(1 row)
+
+SELECT EXTRACT(CENTURY FROM DATE '0001-12-31 BC'); -- -1
+ date_part 
+-----------
+        -1
+(1 row)
+
+SELECT EXTRACT(CENTURY FROM DATE '0001-01-01');    --  1
+ date_part 
+-----------
+         1
+(1 row)
+
+SELECT EXTRACT(CENTURY FROM DATE '0001-01-01 AD'); --  1
+ date_part 
+-----------
+         1
+(1 row)
+
+SELECT EXTRACT(CENTURY FROM DATE '1900-12-31');    -- 19
+ date_part 
+-----------
+        19
+(1 row)
+
+SELECT EXTRACT(CENTURY FROM DATE '1901-01-01');    -- 20
+ date_part 
+-----------
+        20
+(1 row)
+
+SELECT EXTRACT(CENTURY FROM DATE '2000-12-31');    -- 20
+ date_part 
+-----------
+        20
+(1 row)
+
+SELECT EXTRACT(CENTURY FROM DATE '2001-01-01');    -- 21
+ date_part 
+-----------
+        21
+(1 row)
+
+SELECT EXTRACT(CENTURY FROM CURRENT_DATE)>=21 AS True;     -- true
+ true 
+------
+ t
+(1 row)
+
+--
+-- millennium
+--
+SELECT EXTRACT(MILLENNIUM FROM DATE '0001-12-31 BC'); -- -1
+ date_part 
+-----------
+        -1
+(1 row)
+
+SELECT EXTRACT(MILLENNIUM FROM DATE '0001-01-01 AD'); --  1
+ date_part 
+-----------
+         1
+(1 row)
+
+SELECT EXTRACT(MILLENNIUM FROM DATE '1000-12-31');    --  1
+ date_part 
+-----------
+         1
+(1 row)
+
+SELECT EXTRACT(MILLENNIUM FROM DATE '1001-01-01');    --  2
+ date_part 
+-----------
+         2
+(1 row)
+
+SELECT EXTRACT(MILLENNIUM FROM DATE '2000-12-31');    --  2
+ date_part 
+-----------
+         2
+(1 row)
+
+SELECT EXTRACT(MILLENNIUM FROM DATE '2001-01-01');    --  3
+ date_part 
+-----------
+         3
+(1 row)
+
+-- next test to be fixed on the turn of the next millennium;-)
+SELECT EXTRACT(MILLENNIUM FROM CURRENT_DATE);         --  3
+ date_part 
+-----------
+         3
+(1 row)
+
diff --git a/src/test/regress/sql/date.sql b/src/test/regress/sql/date.sql
index 10bd87cadcf39a11f28d6503217112bdfbc0618b..a3cad66ed2e16d95f8ee41be25ff8fa383d8e8e6 100644
--- a/src/test/regress/sql/date.sql
+++ b/src/test/regress/sql/date.sql
@@ -208,3 +208,30 @@ SELECT date 'tomorrow' - date 'today' AS "One day";
 SELECT date 'today' - date 'yesterday' AS "One day";
 
 SELECT date 'tomorrow' - date 'yesterday' AS "Two days";
+
+--
+-- test extract!
+--
+-- century
+--
+SELECT EXTRACT(CENTURY FROM DATE '0101-12-31 BC'); -- -2
+SELECT EXTRACT(CENTURY FROM DATE '0100-12-31 BC'); -- -1
+SELECT EXTRACT(CENTURY FROM DATE '0001-12-31 BC'); -- -1
+SELECT EXTRACT(CENTURY FROM DATE '0001-01-01');    --  1
+SELECT EXTRACT(CENTURY FROM DATE '0001-01-01 AD'); --  1
+SELECT EXTRACT(CENTURY FROM DATE '1900-12-31');    -- 19
+SELECT EXTRACT(CENTURY FROM DATE '1901-01-01');    -- 20
+SELECT EXTRACT(CENTURY FROM DATE '2000-12-31');    -- 20
+SELECT EXTRACT(CENTURY FROM DATE '2001-01-01');    -- 21
+SELECT EXTRACT(CENTURY FROM CURRENT_DATE)>=21 AS True;     -- true
+--
+-- millennium
+--
+SELECT EXTRACT(MILLENNIUM FROM DATE '0001-12-31 BC'); -- -1
+SELECT EXTRACT(MILLENNIUM FROM DATE '0001-01-01 AD'); --  1
+SELECT EXTRACT(MILLENNIUM FROM DATE '1000-12-31');    --  1
+SELECT EXTRACT(MILLENNIUM FROM DATE '1001-01-01');    --  2
+SELECT EXTRACT(MILLENNIUM FROM DATE '2000-12-31');    --  2
+SELECT EXTRACT(MILLENNIUM FROM DATE '2001-01-01');    --  3
+-- next test to be fixed on the turn of the next millennium;-)
+SELECT EXTRACT(MILLENNIUM FROM CURRENT_DATE);         --  3