Index: branches/release-33/lib/MT/CMS/Blog.pm
===================================================================
--- branches/release-33/lib/MT/CMS/Blog.pm (revision 1776)
+++ branches/release-33/lib/MT/CMS/Blog.pm (revision 1778)
@@ -531,4 +531,5 @@
         }
     }
+    $app->run_callbacks('post_build');
     $app->call_return;
 }
@@ -541,5 +542,15 @@
     require MT::Blog;
     my $q             = $app->param;
-    my $blog_id       = $q->param('blog_id');
+    my $start_time    = $q->param('start_time');
+
+    if ( ! $start_time ) {
+        # start of build; invoke callback
+        $app->run_callbacks('pre_build');
+        $start_time = time;
+    }
+
+    my $blog_id       = int($q->param('blog_id'));
+    return $app->errtrans("Invalid request.") unless $blog_id;
+
     my $blog          = MT::Blog->load($blog_id);
     my $order         = $q->param('type');
@@ -550,4 +561,5 @@
     my $archiver      = $app->publisher->archiver($type);
     my $archive_label = $archiver ? $archiver->archive_label : '';
+
     $archive_label = $app->translate($type) unless $archive_label;
     $archive_label = $archive_label->() if ( ref $archive_label ) eq 'CODE';
@@ -556,8 +568,4 @@
     my $offset = 0;
     my ($total) = $q->param('total');
-
-    ## Tells MT::_rebuild_entry_archive_type to cache loaded templates so
-    ## that each template is only loaded once.
-    $app->{cache_templates} = 1;
 
     my ($tmpl_saved);
@@ -774,4 +782,5 @@
             offset          => $offset,
             complete        => $complete,
+            start_time      => $start_time,
             incomplete      => 100 - $complete,
             entry_id        => scalar $q->param('entry_id'),
@@ -783,4 +792,5 @@
     }
     else {
+        $app->run_callbacks( 'post_build' );
         if ( $q->param('entry_id') ) {
             require MT::Entry;
@@ -809,9 +819,11 @@
             }
             my %param = (
-                all          => $all,
-                type         => $archive_label,
-                is_one_index => $is_one_index,
-                is_entry     => $is_entry,
-                archives     => $type ne 'index',
+                all             => $all,
+                type            => $archive_label,
+                is_one_index    => $is_one_index,
+                is_entry        => $is_entry,
+                archives        => $type ne 'index',
+                start_timestamp => MT::Util::epoch2ts($blog, $start_time),
+                total_time      => time - $start_time,
             );
             if ($is_one_index) {
@@ -838,5 +850,4 @@
             }
             else {    # popup--just go to cnfrmn. page
-                $app->run_callbacks( 'rebuild', $blog );
                 return $app->load_tmpl( 'popup/rebuilt.tmpl', \%param );
             }
@@ -854,4 +865,12 @@
     my $app           = shift;
     my $q             = $app->param;
+    my $start_time    = $q->param('start_time');
+
+    if ( ! $start_time ) {
+        # start of build; invoke callback
+        $app->run_callbacks('pre_build');
+        $start_time = time;
+    }
+
     my $type          = $q->param('type');
     my $next          = $q->param('next') || 0;
@@ -906,4 +925,5 @@
         build_next      => $next,
         total           => $total,
+        start_time      => $start_time,
         complete        => 0,
         incomplete      => 100,
Index: branches/release-33/lib/MT/CMS/Entry.pm
===================================================================
--- branches/release-33/lib/MT/CMS/Entry.pm (revision 1746)
+++ branches/release-33/lib/MT/CMS/Entry.pm (revision 1778)
@@ -1388,4 +1388,5 @@
             my $res = MT::Util::start_background_task(
                 sub {
+                    $app->run_callbacks('pre_build');
                     $app->rebuild_entry(
                         Entry             => $obj,
@@ -1398,4 +1399,5 @@
                     ) or return $app->publish_error();
                     $app->run_callbacks( 'rebuild', $blog );
+                    $app->run_callbacks( 'post_build' );
                     1;
                 }
Index: branches/release-33/lib/MT/App.pm
===================================================================
--- branches/release-33/lib/MT/App.pm (revision 1769)
+++ branches/release-33/lib/MT/App.pm (revision 1778)
@@ -664,4 +664,5 @@
     MT->add_callback('post_save', 0, $app, \&_cb_mark_blog );
     MT->add_callback('MT::Blog::post_remove', 0, $app, \&_cb_unmark_blog );
+    MT->add_callback('pre_build', 9, $app, sub { $app->touch_blogs() } );
     MT->add_callback('new_user_provisioning', 5, $app, \&_cb_user_provisioning);
 }
Index: branches/release-33/lib/MT/App/CMS.pm
===================================================================
--- branches/release-33/lib/MT/App/CMS.pm (revision 1770)
+++ branches/release-33/lib/MT/App/CMS.pm (revision 1778)
@@ -3076,19 +3076,27 @@
         # now, rebuild indexes for affected blogs
         my @blogs = $app->param('blog_ids');
-        foreach my $blog_id (@blogs) {
-            my $blog = MT::Blog->load($blog_id) or next;
-            $app->rebuild_indexes( Blog => $blog )
-                or return $app->publish_error();
-        }
-        my $this_blog = MT::Blog->load( $app->param('blog_id') );
-        $app->run_callbacks( 'rebuild', $this_blog );
+        if (@blogs) {
+            $app->run_callbacks( 'pre_build' ) if @blogs;
+            foreach my $blog_id (@blogs) {
+                my $blog = MT::Blog->load($blog_id) or next;
+                $app->rebuild_indexes( Blog => $blog )
+                    or return $app->publish_error();
+            }
+            my $blog_id = int($app->param('blog_id'));
+            my $this_blog = MT::Blog->load( $blog_id ) if $blog_id;
+            $app->run_callbacks( 'rebuild', $this_blog );
+            $app->run_callbacks( 'post_build' );
+        }
         return $app->call_return;
     }
 
     if ( exists $options{how} && ( $options{how} eq NEW_PHASE ) ) {
+        my $start_time = time;
+        $app->run_callbacks( 'pre_build' );
         my $params = {
             return_args => $app->return_args,
             blog_id     => $app->param('blog_id') || 0,
-            id          => [ keys %$rebuild_set ]
+            id          => [ keys %$rebuild_set ],
+            start_time  => $start_time,
         };
         my %param = (
@@ -3103,4 +3111,5 @@
     else {
         my @blogs = $app->param('blog_ids');
+        my $start_time = $app->param('start_time');
         my %blogs = map { $_ => () } @blogs;
         my @set   = keys %$rebuild_set;
@@ -3118,4 +3127,5 @@
             # Rebuilding something that isn't an entry, rebless as required
             if ( $type ne MT::Entry->class_type ) {
+                die "had to rebless? $e";
                 my $pkg = MT->model($type) or next;
                 bless $e, $pkg;
@@ -3139,4 +3149,5 @@
             blog_ids        => [ keys %blogs ],
             id              => \@rest,
+            start_time      => $start_time,
         };
         my %param = (
Index: branches/release-33/lib/MT/Util.pm
===================================================================
--- branches/release-33/lib/MT/Util.pm (revision 1744)
+++ branches/release-33/lib/MT/Util.pm (revision 1778)
@@ -208,4 +208,47 @@
             } elsif ($hours) {
                 $result = $future ? MT->translate("[quant,_1,hour,hours] from now", $hours) : MT->translate("[quant,_1,hour,hours] ago", $hours);
+            }
+            return $result;
+        }
+    } elsif ($style == 3) {
+        if ($delta < 60) {
+            return $future ? MT->translate("[quant,_1,second,seconds] from now", $delta) : MT->translate("[quant,_1,second,seconds]", $delta);
+        } elsif ($delta <= 3600) {
+            # less than 1 hour
+            my $min = int(($delta % 3600) / 60);
+            my $sec = $delta % 60;
+            my $result;
+            if ($sec && $min) {
+                $result = $future ? MT->translate("[quant,_1,minute,minutes], [quant,_2,second,seconds] from now", $min, $sec) : MT->translate("[quant,_1,minute,minutes], [quant,_2,second,seconds]", $min, $sec);
+            } elsif ($min) {
+                $result = $future ? MT->translate("[quant,_1,minute,minutes] from now", $min) : MT->translate("[quant,_1,minute,minutes]", $min);
+            } elsif ($sec) {
+                $result = $future ? MT->translate("[quant,_1,second,seconds] from now", $sec) : MT->translate("[quant,_1,second,seconds]", $sec);
+            }
+            return $result;
+        } elsif ($delta <= 86400) {
+            # less than 1 day
+            my $hours = int($delta / 3600);
+            my $min = int(($delta % 3600) / 60);
+            my $result;
+            if ($hours && $min) {
+                $result = $future ? MT->translate("[quant,_1,hour,hours], [quant,_2,minute,minutes] from now", $hours, $min) : MT->translate("[quant,_1,hour,hours], [quant,_2,minute,minutes]", $hours, $min);
+            } elsif ($hours) {
+                $result = $future ? MT->translate("[quant,_1,hour,hours] from now", $hours) : MT->translate("[quant,_1,hour,hours]", $hours);
+            } elsif ($min) {
+                $result = $future ? MT->translate("[quant,_1,minute,minutes] from now", $min) : MT->translate("[quant,_1,minute,minutes]", $min);
+            }
+            return $result;
+        } elsif ($delta <= 604800) {
+            # less than 1 week
+            my $days = int($delta / 86400);
+            my $hours = int(($delta % 86400) / 3600);
+            my $result;
+            if ($days && $hours) {
+                $result = $future ? MT->translate("[quant,_1,day,days], [quant,_2,hour,hours] from now", $days, $hours) : MT->translate("[quant,_1,day,days], [quant,_2,hour,hours]", $days, $hours);
+            } elsif ($days) {
+                $result = $future ? MT->translate("[quant,_1,day,days] from now", $days) : MT->translate("[quant,_1,day,days]", $days);
+            } elsif ($hours) {
+                $result = $future ? MT->translate("[quant,_1,hour,hours] from now", $hours) : MT->translate("[quant,_1,hour,hours]", $hours);
             }
             return $result;
