diff --git a/admin.php b/admin.php
--- a/admin.php
+++ b/admin.php
@@ -56,27 +56,6 @@ require_once('inc/admin.inc');
     return false; 
   }
 
-  function emptySavedDir($todate = null) {
-    // Empty the saved_schedules directory
-    $dir = "saved_schedules";
-    if(!is_dir($dir)) {
-      echo "
{$dir} is not a valid directory! Please check your installation.";
-      return;
-    }
-   
-    // Do this the new fun php5 OO-way
-    foreach(new DirectoryIterator($dir) as $file) {
-      if(is_numeric($file->getFilename())){
-        $isBeforeDate = isBeforeDate($file->getCTime(), $todate);
-        if(!$todate || $isBeforeDate) {
-          // unlink($dir . '/' . $file->getFilename());
-          $date = date("Y-m-d",$file->getCTime());
-          echo "Erased file: " . $dir . '/' . $file->getFilename() . " ({$date})
";
-        } 
-      }
-    }
-  }
-
   function checkAction() {
     $result = '';
     if(isset($_GET['rehash'])) {
@@ -93,16 +72,33 @@ require_once('inc/admin.inc');
       if ($crawl_schools !== NULL)
 	$result .= ': ' . implode(', ', $crawl_schools);
     }
-    else if(isset($_GET['purgetodate'])) {
-      // Purge saved schedule cache up to date
-      emptySavedDir($_GET['purgetodate']);
-      $result = 'Purged all saved schedules up to ' . $_GET['purgetodate'];
-    }
-    else if(isset($_GET['purge'])) {
-      // Purge the saved schedule cache
-      emptySavedDir();
-      $result = 'Purge Complete';
-    }
+    else if(isset($_GET['purge']))
+      {
+	$purge_date = NULL;
+	if(isset($_GET['purgetodate']))
+	  {
+	    $t = strptime($_REQUEST['purgetodate'], '%Y-%m-%d');
+	    $purge_date = mktime($t['tm_hour'], $t['tm_min'], $t['tm_sec'], $t['tm_mon'], $t['tm_mday'], $t['tm_year'] + 1900);
+	  }
+
+	$schedule_store = schedule_store_init();
+	if (!$schedule_store)
+	  return 'Purging saved schedules failed: unable to initialize schedule_store handle.';
+
+	$num_purged = schedule_store_purge_range($schedule_store, 0, $purge_date);
+	if ($num_purged === FALSE)
+	  {
+	    $result = 'Purging saved scheduled failed.';
+	    if (!$admin_enable_purge)
+	      $result .= ' To enable purging saved schedules, since this is an irreversable operation, you must set $admin_enable_purge = TRUE in config.inc.';
+	  }
+	else
+	  {
+	    $result .= 'Purged ' . $num_purged . ' schedules';
+	    if ($purge_date !== NULL)
+	      $result .= ' up to ' . $purge_date;
+	  }
+      }
     return $result;
   }
 
@@ -174,7 +170,13 @@ require_once('inc/admin.inc');
     The highest saved_schedule id is .
 
 
 
+ *
+ * This file is a part of slate_permutate.
+ *
+ * slate_permutate is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * slate_permutate is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with slate_permutate.  If not, see .
+ */
+
+/**
+ * \file
+ *
+ * Provides a way to easily purge a number of saved schedules through
+ * a date range.
+ */
+
+$inc_base = dirname(__FILE__) . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'inc' . DIRECTORY_SEPARATOR;
+require_once($inc_base . 'admin.inc');
+
+return main($argc, $argv);
+
+function main($argc, $argv)
+{
+  global $admin_enable_purge;
+
+  $n = test();
+  if ($n)
+    {
+      fprintf(STDERR, "%d tests failed; exiting\n",
+	      $n);
+      return 1;
+    }
+
+  $opts = getopt('hV:', array('all', 'max-time:', 'min-time:', 'help', 'verbosity:'));
+
+  if (isset($opts['help']) || isset($opts['h']))
+    {
+      usage($argv[0]);
+      return 0;
+    }
+
+  $all = FALSE;
+  if (isset($opts['all']))
+    $crawl = TRUE;
+
+  foreach (array('min', 'max') as $time_var)
+    {
+      if (isset($opts[$time_var . '-time']))
+	{
+	  ${$time_var . '_time'} = strtotime($opts[$time_var . '-time']);
+	  /* two ways of saying the thing failed -- was -1 until PHP 5.1.0 */
+	  if (${$time_var . '_time'} === FALSE || ${$time_var . '_time'} == -1)
+	    {
+	      fprintf(STDERR, "%s-time: Invalid date/time format, can't understand string: ``%s''.\n",
+		      $time_var, $opts['min-time']);
+	      return 1;
+	    }
+	}
+    }
+
+  if ($all && (isset($min_time) || isset($max_time)))
+    {
+      fprintf(STDERR, "error: Both --all and one of --max-time or --min-time were specified. These options are mutually exclusive.\n");
+      return 1;
+    }
+
+  if (!$all && (!isset($min_time) || !isset($max_time)))
+    {
+      if (isset($min_time) || isset($max_time))
+	fprintf(STDERR, "error: If --min-time is set, --max-time must also be set and vice versa. This is to prevent accidents.\n");
+      else
+	fprintf(STDERR, "error: Either --all or both of --min-time and --max-time must be passed to purge saved schedules.\n");
+      return 1;
+    }
+
+  $verbosity = 1;
+  if (isset($opts['verbosity']))
+    $verbosity = (int)$opts['verbosity'];
+  if (isset($opts['V']))
+    $verbosity = (int)$opts['V'];
+  if ($verbosity < 0 || $verbosity > 10)
+    {
+      fprintf(STDERR, "error: Invalid verbosity level: %d\n", $verbosity);
+      fprintf(STDERR, "\n");
+      usage();
+      return 1;
+    }
+
+  if ($all)
+    {
+      fprintf(STDOUT, "Purging all schedules.\n");
+    }
+
+  if (!isset($min_time))
+    $min_time = 0;
+  if (!isset($max_time))
+    $max_time = NULL;
+  else
+    fprintf(STDOUT, "Purging from %s to %s.\n",
+	    strftime("%F %T", $min_time), strftime("%F %T", $max_time));
+
+  $schedule_store = schedule_store_init();
+  if (!$schedule_store)
+    {
+      fprintf(STDERR, "error: Unable to initialize schedule_store.\n");
+      return 1;
+    }
+  $ret = schedule_store_purge_range($schedule_store, $min_time, $max_time);
+  if ($ret === FALSE)
+    {
+      fprintf(STDERR, "error: Unable to purge schedule_store%s.\n",
+	      $all ? '' : ' range');
+      if (!$admin_enable_purge)
+	fprintf(STDERR, "error: You need to set " . '$admin_enable_purge' . " in config.inc to enable purging schedules through the administration utilities.\n");
+      return 1;
+    }
+
+  fprintf(STDOUT, "Schedules deleted: %s\n",
+	  $ret);
+  fprintf(STDOUT, "Purge successful.\n");
+
+  return 0;
+}
+
+
+/**
+ * \brief
+ *   Display CLI interface usage.
+ */
+function usage($progname)
+{
+  fprintf(STDERR, "Usage: %s [--all] [--min-time=] [--max-time=] [--help] [-h]\n"
+	  . "\n"
+	  . " -h, --help   Show this usage information and exit.\n"
+	  . "\n"
+	  . " --all        Purge all saved schedules.\n"
+	  . " --min-time   Takes a date/time string after which a schedule must\n"
+	  . "              have been created to be deleted.\n"
+	  . " --max-time   Takes a date/time string before which a schedule must\n"
+	  . "              be saved to be dleted.\n"
+	  . " -v, --verbosity Set the verbosity level. Valid range is from 0\n"
+	  . "              through 10.",
+	  $progname);
+}
+
diff --git a/inc/admin.inc b/inc/admin.inc
--- a/inc/admin.inc
+++ b/inc/admin.inc
@@ -318,6 +318,50 @@ function school_cache_recreate($crawl_on
   return 0;
 }
 
+/**
+ * \brief
+ *   Purge a range of saved_schedules.
+ *
+ * \param $schedule_store
+ *   The schedule_store handle for which a range of saved schedules
+ *   must be deleted.
+ * \param $time_min
+ *   The minimum unix timestamp for the range of schedules to be
+ *   purged.
+ * \param $time_max
+ *   The maximum unix timestamp for the range of schedules to be
+ *   purged or NULL for no limit.
+ * \return
+ *   FALSE on failure, an integer indicating the number of deleted
+ *   saved_schedules on success.
+ */
+function schedule_store_purge_range($schedule_store, $time_min = 0, $time_max = NULL)
+{
+  global $admin_enable_purge;
+
+  $schedule_id_max = schedule_store_getmaxid($schedule_store);
+  $num_deleted = 0;
+
+  if (!$admin_enable_purge)
+    return FALSE;
+
+  for ($schedule_id = 0; $schedule_id < $schedule_id_max; $schedule_id ++)
+    {
+      $filename = $schedule_store['dir'] . DIRECTORY_SEPARATOR . $schedule_id;
+      if (!file_exists($filename))
+	continue;
+
+      $statbuf = stat($filename);
+      if ($statbuf['ctime'] >= $time_min
+	  && ($time_max === NULL || $statbuf['ctime'] <= $time_max))
+	{
+	  unlink($filename);
+	  $num_deleted ++;
+	}
+    }
+
+  return $num_deleted;
+}
 
 /**
  * \brief
diff --git a/inc/class.page.php b/inc/class.page.php
--- a/inc/class.page.php
+++ b/inc/class.page.php
@@ -45,6 +45,7 @@ set_include_path(get_include_path() . PA
 $ga_trackers = array();
 $feedback_emails = array('ez@ethanzonca.com, ngelderloos7@gmail.com, ohnobinki@ohnopublishing.net');
 $use_captcha = FALSE;
+$admin_enable_purge = FALSE;
 
 $config_inc = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'config.inc';
 if (file_exists($config_inc)) {
diff --git a/inc/config.inc.example b/inc/config.inc.example
--- a/inc/config.inc.example
+++ b/inc/config.inc.example
@@ -78,8 +78,17 @@
 
 /**
  * \brief
- *    Setting this variable true enables the administration page
+ *   Setting this variable true enables the administration page
  *
  */
-/* $admin_enable = false; */
+/* $admin_enable = FALSE; */
 
+/**
+ * \brief
+ *   Enable purging saved schedules through the admin/rehash.php
+ *   script or web interface.
+ *
+ * Set to TRUE to enable this functionality. It is disabled by default
+ * because it causes irreparable information loss.
+ */
+/* $admin_enable_purge = FALSE; */