diff -ru postgresql-8.3.1-orig/src/backend/postmaster/bgwriter.c postgresql-8.3.1/src/backend/postmaster/bgwriter.c
--- postgresql-8.3.1-orig/src/backend/postmaster/bgwriter.c	2008-01-01 14:45:51.000000000 -0500
+++ postgresql-8.3.1/src/backend/postmaster/bgwriter.c	2008-04-03 17:29:21.705604181 -0400
@@ -123,6 +123,8 @@
 	slock_t		ckpt_lck;		/* protects all the ckpt_* fields */
 
 	int			ckpt_started;	/* advances when checkpoint starts */
+	time_t		last_ckpt_start_time;	/* set to "now" when skpt_started is advanced */
+	time_t		last_ckpt_done_time;	/* set to "now" when skpt_started is advanced */
 	int			ckpt_done;		/* advances when checkpoint done */
 	int			ckpt_failed;	/* advances when checkpoint fails */
 
@@ -309,11 +311,15 @@
 		{
 			/* use volatile pointer to prevent code rearrangement */
 			volatile BgWriterShmemStruct *bgs = BgWriterShmem;
+			TimestampTz endtime;
 
+			endtime = time_t_to_timestamptz(time(NULL));
 			SpinLockAcquire(&bgs->ckpt_lck);
 			bgs->ckpt_failed++;
 			bgs->ckpt_done = bgs->ckpt_started;
+			bgs->last_ckpt_done_time = endtime;
 			SpinLockRelease(&bgs->ckpt_lck);
+			BgWriterStats.m_last_checkpoint_done = endtime;
 
 			ckpt_active = false;
 		}
@@ -363,6 +369,7 @@
 		int			flags = 0;
 		time_t		now;
 		int			elapsed_secs;
+		TimestampTz	endtime;
 
 		/*
 		 * Emergency bailout if postmaster has died.  This is to avoid the
@@ -425,6 +432,7 @@
 		{
 			/* use volatile pointer to prevent code rearrangement */
 			volatile BgWriterShmemStruct *bgs = BgWriterShmem;
+			TimestampTz starttime = time_t_to_timestamptz(now);
 
 			/*
 			 * Atomically fetch the request flags to figure out what kind of a
@@ -435,7 +443,9 @@
 			flags |= bgs->ckpt_flags;
 			bgs->ckpt_flags = 0;
 			bgs->ckpt_started++;
+			bgs->last_ckpt_start_time = starttime;
 			SpinLockRelease(&bgs->ckpt_lck);
+			BgWriterStats.m_last_checkpoint_start = starttime;
 
 			/*
 			 * We will warn if (a) too soon since last checkpoint (whatever
@@ -472,10 +482,14 @@
 
 			/*
 			 * Indicate checkpoint completion to any waiting backends.
+			 * Set the endtime to now to hand to the stats writer.
 			 */
+			endtime = time_t_to_timestamptz(time(NULL));
 			SpinLockAcquire(&bgs->ckpt_lck);
 			bgs->ckpt_done = bgs->ckpt_started;
+			bgs->last_ckpt_done_time = endtime;
 			SpinLockRelease(&bgs->ckpt_lck);
+			BgWriterStats.m_last_checkpoint_done = endtime;
 
 			ckpt_active = false;
 
diff -ru postgresql-8.3.1-orig/src/backend/postmaster/pgstat.c postgresql-8.3.1/src/backend/postmaster/pgstat.c
--- postgresql-8.3.1-orig/src/backend/postmaster/pgstat.c	2008-01-01 14:45:51.000000000 -0500
+++ postgresql-8.3.1/src/backend/postmaster/pgstat.c	2008-04-03 17:30:07.211460576 -0400
@@ -3169,4 +3171,6 @@
 	globalStats.maxwritten_clean += msg->m_maxwritten_clean;
 	globalStats.buf_written_backend += msg->m_buf_written_backend;
 	globalStats.buf_alloc += msg->m_buf_alloc;
+	globalStats.last_checkpoint_start = msg->m_last_checkpoint_start;
+	globalStats.last_checkpoint_done = msg->m_last_checkpoint_done;
 }
diff -ru postgresql-8.3.1-orig/src/backend/utils/adt/pgstatfuncs.c postgresql-8.3.1/src/backend/utils/adt/pgstatfuncs.c
--- postgresql-8.3.1-orig/src/backend/utils/adt/pgstatfuncs.c	2008-01-01 14:45:52.000000000 -0500
+++ postgresql-8.3.1/src/backend/utils/adt/pgstatfuncs.c	2008-04-03 16:48:51.715709622 -0400
@@ -786,6 +786,30 @@
 }
 
 Datum
+pg_stat_get_bgwriter_last_checkpoint_start(PG_FUNCTION_ARGS)
+{
+	TimestampTz result;
+
+	result = pgstat_fetch_global()->last_checkpoint_start;
+	if(result == 0)
+		PG_RETURN_NULL();
+
+        PG_RETURN_TIMESTAMPTZ(result);
+}
+
+Datum
+pg_stat_get_bgwriter_last_checkpoint_done(PG_FUNCTION_ARGS)
+{
+	TimestampTz result;
+
+	result = pgstat_fetch_global()->last_checkpoint_done;
+	if(result == 0)
+		PG_RETURN_NULL();
+
+        PG_RETURN_TIMESTAMPTZ(result);
+}
+
+Datum
 pg_stat_get_bgwriter_timed_checkpoints(PG_FUNCTION_ARGS)
 {
 	PG_RETURN_INT64(pgstat_fetch_global()->timed_checkpoints);
diff -ru postgresql-8.3.1-orig/src/include/catalog/pg_proc.h postgresql-8.3.1/src/include/catalog/pg_proc.h
--- postgresql-8.3.1-orig/src/include/catalog/pg_proc.h	2008-01-01 14:45:57.000000000 -0500
+++ postgresql-8.3.1/src/include/catalog/pg_proc.h	2008-04-03 17:47:26.314929683 -0400
@@ -4392,6 +4392,10 @@
 DESCR("I/O");
 DATA(insert OID = 3774 (  regdictionarysend PGNSP PGUID 12 1 0 f f t f i 1 17 "3769" _null_ _null_ _null_ regdictionarysend - _null_ _null_ ));
 DESCR("I/O");
+DATA(insert OID = 3775 ( pg_stat_get_bgwriter_last_checkpoint_start PGNSP PGUID 12 1 0 f f t f s 0 1184 "" _null_ _null_ _null_ pg_stat_get_bgwriter_last_checkpoint_start - _null_ _null_ ));
+DESCR("statistics: timestamp when the most recent checkpoint was initiated");
+DATA(insert OID = 3776 ( pg_stat_get_bgwriter_last_checkpoint_done PGNSP PGUID 12 1 0 f f t f s 0 1184 "" _null_ _null_ _null_ pg_stat_get_bgwriter_last_checkpoint_done - _null_ _null_ ));
+DESCR("statistics: timestamp when the most recent checkpoint was completed");
 
 /* txid */
 DATA(insert OID = 2939 (  txid_snapshot_in			PGNSP PGUID 12 1  0 f f t f i 1 2970 "2275" _null_ _null_ _null_ txid_snapshot_in - _null_ _null_ ));
diff -ru postgresql-8.3.1-orig/src/include/pgstat.h postgresql-8.3.1/src/include/pgstat.h
--- postgresql-8.3.1-orig/src/include/pgstat.h	2008-01-01 14:45:56.000000000 -0500
+++ postgresql-8.3.1/src/include/pgstat.h	2008-04-03 17:28:37.288895715 -0400
@@ -296,6 +296,8 @@
 	PgStat_Counter m_maxwritten_clean;
 	PgStat_Counter m_buf_written_backend;
 	PgStat_Counter m_buf_alloc;
+	TimestampTz m_last_checkpoint_start;
+	TimestampTz m_last_checkpoint_done;
 } PgStat_MsgBgWriter;
 
 
@@ -398,6 +400,8 @@
 	PgStat_Counter maxwritten_clean;
 	PgStat_Counter buf_written_backend;
 	PgStat_Counter buf_alloc;
+	TimestampTz last_checkpoint_start;
+	TimestampTz last_checkpoint_done;
 } PgStat_GlobalStats;
 
 
