diff --git a/inc/class.schedule.php b/inc/class.schedule.php
--- a/inc/class.schedule.php
+++ b/inc/class.schedule.php
@@ -189,7 +189,7 @@ class Schedule
    *   NULL on success, a string on error which is a message for the
    *   user and a valid XHTML fragment.
    */
-  function addSection($course_name, $letter, $time_start, $time_end, $days, $synonym = NULL, $instructor = NULL, $location = NULL, $type = 'lecture', $slot = 'default', $credit_hours = -1.0)
+  function addSection($course_name, $letter, $time_start, $time_end, $days, $synonym = NULL, $instructor = NULL, $location = NULL, $type = 'lecture', $slot = 'default', $credit_hours = -1.0, $date_start = NULL, $date_end = NULL)
   {
     if (empty($letter) && (empty($time_start) || !strcmp($time_start, 'none')) && (empty($time_end) || !strcmp($time_end, 'none')) && empty($days)
 	&& empty($synonym) && empty($instructor) && empty($location) && (empty($type) || !strcmp($type, 'lecture'))
@@ -209,6 +209,15 @@ class Schedule
         return 'Invalid credit-hour specification of ' . htmlentities($credit_hours) . ' for ' . htmlentities($course_name) . '-' . htmlentities($letter) . '. Please use a floating point number or do not enter anything if the number of credit hours is not known.';
       }
 
+    if (empty($date_start) != empty($date_end)
+        || !empty($date_start) && !is_numeric($date_start)
+        || !empty($date_end) && !is_numeric($date_end))
+      {
+        return 'Invalid date range specification of ' . htmlentities($date_start, ENT_QUOTES)
+          . ' through ' . htmlentities($date_end, ENT_QUOTES)
+          . '. Was expecting two valid unix timestamps or two empty values.';
+      }
+
     foreach ($this->courses as $course)
       if (!strcmp($course_name, $course->getName()))
 	{
@@ -218,7 +227,7 @@ class Schedule
               $section = new Section($letter, array(), $synonym, $credit_hours);
 	      $course->section_add($section, $slot);
 	    }
-	  $section->meeting_add(new SectionMeeting($days, $time_start, $time_end, $location, $type, $instructor));
+	  $section->meeting_add(new SectionMeeting($days, $time_start, $time_end, $location, $type, $instructor, $date_start, $date_end));
 
 	  return;
 	}
diff --git a/inc/class.section.php b/inc/class.section.php
--- a/inc/class.section.php
+++ b/inc/class.section.php
@@ -23,8 +23,10 @@ require_once dirname(__FILE__) . DIRECTO
 /**
  * \brief
  *   Represent a Section associated with a Course.
+ *
+ * Iterating over a Section yields section_SectionMeeting objects.
  */
-class Section
+class Section implements IteratorAggregate
 {
 
   private $letter;	// Section letter
@@ -70,6 +72,15 @@ class Section
     $this->credit_hours = (float)$credit_hours;
   }
 
+  /**
+   * \brief
+   *   Implements the IteratorAggregate interface.
+   */
+  public function getIterator()
+  {
+    return new ArrayIterator($this->meetings);
+  }
+
   public function getLetter()
   {
     return $this->letter;
diff --git a/inc/class.section_meeting.inc b/inc/class.section_meeting.inc
--- a/inc/class.section_meeting.inc
+++ b/inc/class.section_meeting.inc
@@ -35,7 +35,9 @@
  */
 class SectionMeeting
 {
+  private $date_start;
   private $time_start;
+  private $date_end;
   private $time_end;
   private $days;
   private $location;
@@ -64,12 +66,21 @@ class SectionMeeting
    *   school's notation.
    * \param $instructor
    *   The instructor for this section meeting.
+   * \param $date_start
+   *   A timestamp marking some time prior to the first occurence of
+   *   the section_meeting.
+   * \param $date_end
+   *   A timestamp marking some time after the end of the last
+   *   occurence of this section_meeting.
    */
-  public function __construct($days, $time_start, $time_end, $location = NULL, $type = 'lecture', $instructor = NULL)
+  public function __construct($days, $time_start, $time_end, $location = NULL, $type = 'lecture', $instructor = NULL, $date_start = NULL, $date_end = NULL)
   {
     $this->days_set($days);
 
+
+    $this->date_start = empty($date_start) ? NULL : (int)$date_start;
     $this->time_start = $time_start;
+    $this->date_end = empty($date_end) ? NULL : (int)$date_end;
     $this->time_end = $time_end;
 
     $this->location = $location;
@@ -197,6 +208,26 @@ class SectionMeeting
 
   /**
    * \brief
+   *   Return the unix timestamp of a time prior to the first section
+   *   meeting or NULL if unknown.
+   */
+  public function date_start_get()
+  {
+    return empty($this->date_start) ? NULL : $this->date_start;
+  }
+
+  /**
+   * \brief
+   *   Return the unix timestamp of a time after the last section
+   *   meeting or NULL if unknown.
+   */
+  public function date_end_get()
+  {
+    return empty($this->date_end) ? NULL : $this->date_end;
+  }
+
+  /**
+   * \brief
    *   Check if this section conflicts with the given section.
    *
    * \param $that
@@ -249,7 +280,9 @@ class SectionMeeting
     static $daymap = array(0 => 'm', 1 => 't', 2 => 'w', 3 => 'h', 4 => 'f', 5 => 's', 6 => 'u');
 
     $json_array = array(
-			'time_start' => $this->time_start,
+      'date_start' => empty($this->date_start) ? NULL : $this->date_start,
+      			'time_start' => $this->time_start,
+      'date_end' => empty($this->date_end) ? NULL : $this->date_end,
 			'time_end' => $this->time_end,
 			'days' => array(),
 			'location' => $this->location,
@@ -274,10 +307,13 @@ class SectionMeeting
    */
   public static function from_json_array(array $json_array)
   {
+    $json_array += array('date_start' => NULL, 'date_end' => NULL);
     $days = '';
     foreach ($json_array['days'] as $day => $meets)
       if ($meets)
 	$days .= $day;
-    return new SectionMeeting($days, $json_array['time_start'], $json_array['time_end'], $json_array['location'], $json_array['type'], $json_array['instructor']);
+    return new SectionMeeting($days, $json_array['time_start'], $json_array['time_end'],
+			      $json_array['location'], $json_array['type'], $json_array['instructor'],
+			      $json_array['date_start'], $json_array['date_end']);
   }
 }
diff --git a/inc/class.semester.inc b/inc/class.semester.inc
--- a/inc/class.semester.inc
+++ b/inc/class.semester.inc
@@ -95,6 +95,11 @@ class Semester
     if (!isset($class_parts['course']))
       throw new ErrorException('I was given a class with an invalid name: `' . $class->getName() . '\'');
 
+    foreach ($class as $course_slot)
+      foreach ($course_slot as $section)
+        foreach ($section as $meeting)
+          $this->time_set_section_meeting($meeting);
+
     if (!isset($this->departments[$class_parts['department']]))
       $this->departments[$class_parts['department']] = array();
     $department =& $this->departments[$class_parts['department']];
@@ -221,6 +226,9 @@ class Semester
    */
   public function section_add($dept, $class, Section $section, $title = NULL, $course_slot_id = 'default')
   {
+    foreach ($section as $meeting)
+      $this->time_set_section_meeting($meeting);
+
     $dept = strtoupper($dept);
     $class = strtoupper($class);
 
@@ -270,6 +278,8 @@ class Semester
    */
   public function section_meeting_add($dept, $course, $title, $section, $synonym, $section_meeting, $course_slot_id = 'default', $credit_hours = -1.0)
   {
+    $this->time_set_section_meeting($section_meeting);
+
     $dept = strtoupper($dept);
     $course = strtoupper($course);
 
@@ -402,6 +412,23 @@ class Semester
 
   /**
    * \brief
+   *   Consider a section_meeting's start and end dates and make
+   *   appropriate time_start_set_test() and time_end_set_test()
+   *   calls.
+   */
+  public function time_set_section_meeting(SectionMeeting $meeting)
+  {
+    $date_start = $meeting->date_start_get();
+    if (!empty($date_start))
+      $this->time_start_set_test($date_start);
+
+    $date_end = $meeting->date_end_get();
+    if (!empty($date_end))
+      $this->time_end_set_test($date_end);
+  }
+
+  /**
+   * \brief
    *   Get a semester's year.
    */
   public function year_get()
diff --git a/input.php b/input.php
--- a/input.php
+++ b/input.php
@@ -154,7 +154,9 @@ elseif ($errors_fix)
 		. json_encode($section['location']) . ', '
 		. json_encode($section['type']) . ', '
 		. json_encode($section['slot']) . ', '
-		. json_encode(isset($section['credit_hours']) ? $section['credit_hours'] : -1) . ');' . PHP_EOL;
+		. json_encode(isset($section['credit_hours']) ? $section['credit_hours'] : -1) . ', '
+		. json_encode(empty($section['date_start']) ? NULL : $section['date_start']) . ', '
+		. json_encode(empty($section['date_end']) ? NULL : $section['date_end']) . ');' . PHP_EOL;
 	  $my_hc .= PHP_EOL;
 	}
   }
diff --git a/process.php b/process.php
--- a/process.php
+++ b/process.php
@@ -218,10 +218,13 @@ if(!$DEBUG)
 				  /* Skip the section name, which isn't a section */
 					if(is_array($section))
 					  {
-					    if (empty($section['slot']))
-					      $section['slot'] = 'default';
+					    $section += array(
+					      'slot' => 'default',
+					      'date_start' => NULL,
+					      'date_end' => NULL,
+					    );
 
-					    $error_string = $allClasses->addSection($course['name'], $section['letter'], $section['start'], $section['end'], arrayToDays(empty($section['days']) ? array() : $section['days'], 'alpha'), $section['synonym'], $section['professor'], $section['location'], $section['type'], $section['slot'], $section['credit_hours']);
+					    $error_string = $allClasses->addSection($course['name'], $section['letter'], $section['start'], $section['end'], arrayToDays(empty($section['days']) ? array() : $section['days'], 'alpha'), $section['synonym'], $section['professor'], $section['location'], $section['type'], $section['slot'], $section['credit_hours'], $section['date_start'], $section['date_end']);
 					    if ($error_string !== NULL)
 					      $errors[] = $error_string;
 					  }
diff --git a/school.d/calvin.crawl.inc b/school.d/calvin.crawl.inc
--- a/school.d/calvin.crawl.inc
+++ b/school.d/calvin.crawl.inc
@@ -384,27 +384,21 @@ function calvin_crawl_semester(array $sc
 	  foreach (array('date_start', 'date_end', 'meeting_type', 'days', 'time_start', 'time_end', 'meeting_place', 'meeting_type') as $var)
 	    school_crawl_logf($school_crawl_log, 10, "%s:%s", $var, ${$var});
 
-	  $semester->section_meeting_add($section_id['department'], $section_id['course'], $title, $section_id['section'], $synonym,
-					 new SectionMeeting($days, $time_start, $time_end, $meeting_place, $meeting_type, $faculty_name), 'default', $credits);
-
-	  /*
-	   * Try to update semester's longetivity stats to help the
-	   * school_semester_guess() function:
-	   */
 	  $date_start_time = strptime($date_start, '%m/%d/%Y');
 	  $date_end_time = strptime($date_end, '%m/%d/%Y');
+	  if ($date_start_time !== FALSE)
+	    $date_start_time = school_crawl_gmmktime($date_start_time, -5 * 60*60);
+	  else
+	    $date_start_time = NULL;
+	  if ($date_end_time !== FALSE)
+	    $date_end_time = school_crawl_gmmktime($date_end_time, -5 * 60*60) + 24*60*60;
+	  else
+	    $date_end_time = NULL;
 
-	  if ($date_start_time !== FALSE)
-	    {
-	      $date_start_time = school_crawl_gmmktime($date_start_time, -5 * 60*60);
-	      $semester->time_start_pool_add($date_start_time);
+	  $semester->section_meeting_add($section_id['department'], $section_id['course'], $title, $section_id['section'], $synonym,
+					 new SectionMeeting($days, $time_start, $time_end, $meeting_place, $meeting_type, $faculty_name, $date_start_time, $date_end_time), 'default', $credits);
+
 	    }
-	  if ($date_end_time !== FALSE)
-	    {
-	      $date_end_time = school_crawl_gmmktime($date_end_time, -5 * 60*60);
-	      $semester->time_end_pool_add($date_end_time);
-	    }
-	}
 	}
 
       if (!preg_match(';Page ([0-9]+) of ([0-9]+)\$;m', $html, $pages))
diff --git a/school.d/ccbcmd.crawl.inc b/school.d/ccbcmd.crawl.inc
--- a/school.d/ccbcmd.crawl.inc
+++ b/school.d/ccbcmd.crawl.inc
@@ -292,18 +292,18 @@ function ccbcmd_crawl_semester($school, 
 
 	$days = school_crawl_days_str_format($school_crawl_log, $children->item($section_offsets['days'])->textContent);
 
+	$section_dates = $children->item($section_offsets['dates'])->textContent;
+	$date_start = $date_end = NULL;
+	if (preg_match(';^([0-9]+)/([0-9]+)-([0-9]+)/([0-9]+)$;', $section_dates, $section_dates_matches))
+	  {
+	    $date_start = gmmktime(0, 0, 0, $section_dates_matches[1], $section_dates_matches[2], $semester->year_get());
+	    $date_end = gmmktime(0, 0, 0, $section_dates_matches[3], $section_dates_matches[4], $semester->year_get());
+	  }
+
 	$section->meeting_add(new SectionMeeting($days, school_crawl_time_format($time_start), school_crawl_time_format($time_end),
 						 $children->item($section_offsets['location'])->textContent,
 						 'lecture',
-						 $instructor));
-
-	/* check if a semester's date range should be increased */
-	$section_dates = $children->item($section_offsets['dates'])->textContent;
-	if (preg_match(';^([0-9]+)/([0-9]+)-([0-9]+)/([0-9]+)$;', $section_dates, $section_dates_matches))
-	  {
-	    $semester->time_start_set_test(gmmktime(0, 0, 0, $section_dates_matches[1], $section_dates_matches[2], $semester->year_get()));
-	    $semester->time_end_set_test(gmmktime(0, 0, 0, $section_dates_matches[3], $section_dates_matches[4], $semester->year_get()));
-	  }
+						 $instructor, $date_start, $date_end));
       }
     }
 
diff --git a/school.d/cedarville.crawl.inc b/school.d/cedarville.crawl.inc
--- a/school.d/cedarville.crawl.inc
+++ b/school.d/cedarville.crawl.inc
@@ -291,15 +291,11 @@ function cedarville_crawl_semester(array
 	      $type = school_crawl_meeting_type($meeting_matches[1]);
 
 	      /* check for daterange information -- i.e., if the first regex successfully matched: */
+	      $date_start = $date_end = NULL;
 	      if (count($meeting_matches) > 7)
 		{
 		  $date_start = school_crawl_gmmktime(strptime($meeting_matches[6], '%m/%d/%y'), CEDARVILLE_TIMEZONE_OFFSET);
 		  $date_end = school_crawl_gmmktime(strptime($meeting_matches[7], '%m/%d/%y'), CEDARVILLE_TIMEZONE_OFFSET);
-		  if (!empty($date_start) && !empty($date_end))
-		    {
-		      $semester->time_start_set_test($date_start);
-		      $semester->time_end_set_test($date_end);
-		    }
 		}
 
 	      /*
@@ -312,7 +308,8 @@ function cedarville_crawl_semester(array
 		$instructors[$meeting_i] = $instructors[0];
 
 	      $meetings[] = new SectionMeeting($days, $time_start, $time_end,
-					       $room, $type, $instructors[$meeting_i]);
+					       $room, $type, $instructors[$meeting_i],
+					       $date_start, $date_end);
 
 	      $meeting_i ++;
 	    }
diff --git a/school.d/hope.crawl.inc b/school.d/hope.crawl.inc
--- a/school.d/hope.crawl.inc
+++ b/school.d/hope.crawl.inc
@@ -278,6 +278,7 @@ function hope_crawl_semester(array $scho
 	  continue;
 	}
 
+      $date_start = $date_end = NULL;
       if (preg_match(',(\\d\\d)/(\\d\\d)-(\\d\\d)/(\\d\\d),', $section_csv[$fields['Date']], $matches))
 	{
 	  list(, $m_start, $d_start, $m_end, $d_end) = $matches;
@@ -286,8 +287,8 @@ function hope_crawl_semester(array $scho
 	      $y_start = $y_end = $semester->year_get();
 	      if ($m_end < $m_start)
 		$y_end ++;
-	      $semester->time_start_set_test(gmmktime(0, 0, 0, $m_start, $d_start, $y_start));
-	      $semester->time_end_set_test(gmmktime(0, 0, 0, $m_end, $d_end, $y_end));
+	      $date_start = gmmktime(0, 0, 0, $m_start, $d_start, $y_start);
+	      $date_end = gmmktime(0, 0, 0, $m_end, $d_end, $y_end);
 	    }
 	}
 
@@ -314,7 +315,8 @@ function hope_crawl_semester(array $scho
       $section_meeting = new SectionMeeting($days, $time_start, $time_end,
 					    $location,
 					    $type,
-					    $instructor);
+					    $instructor,
+					    $date_start, $date_end);
       $semester->section_meeting_add($subject_id,
 				     $course_id,
 				     $title,
diff --git a/school.d/umich.crawl.inc b/school.d/umich.crawl.inc
--- a/school.d/umich.crawl.inc
+++ b/school.d/umich.crawl.inc
@@ -274,32 +274,31 @@ function umich_crawl_semester(array $sch
 	if (strlen($curr_value = trim($row[$fields[$key]])))
 	  $row_accumulation[$key] = $curr_value;
 
-      $semester->section_meeting_add($dept, $course_id, trim($row[$fields['Course Title']]),
-				     trim($row[$fields['Section']]), $synonym,
-				     new SectionMeeting($days, $time_start, $time_end,
-							trim($row[$fields['Location']]),
-							$meeting_type,
-							$row_accumulation['Instructor']),
-				     $meeting_type,
-				     $credit_hours);
-
       /*
-       * If the section so far passed as being a normal section, use
-       * its start and end dates to help determine the semester's
-       * respective start and end dates.
+       * Grab start/stop dates.
        */
+      $date_start = $date_end = NULL;
       $date_start_tm = strptime(trim($row[$fields['Start Date']]), '%m/%d/%Y');
       $date_end_tm = strptime(trim($row[$fields['End Date']]), '%m/%d/%Y');
       if (!empty($date_start_tm) && !empty($date_end_tm))
 	{
 	  $date_start = school_crawl_gmmktime($date_start_tm);
 	  $date_end = school_crawl_gmmktime($date_end_tm);
-	  if ($date_start > 1000000 && $date_end > 1000000)
+	  if ($date_start < 1000000 || $date_end < 1000000)
 	    {
-	      $semester->time_start_set_test($date_start);
-	      $semester->time_end_set_test($date_end);
+	      $date_start = $date_end = NULL;
 	    }
 	}
+
+      $semester->section_meeting_add($dept, $course_id, trim($row[$fields['Course Title']]),
+				     trim($row[$fields['Section']]), $synonym,
+				     new SectionMeeting($days, $time_start, $time_end,
+							trim($row[$fields['Location']]),
+							$meeting_type,
+							$row_accumulation['Instructor'],
+							$date_start, $date_end),
+				     $meeting_type,
+				     $credit_hours);
     }
 }
 
diff --git a/scripts/scheduleInput.js b/scripts/scheduleInput.js
--- a/scripts/scheduleInput.js
+++ b/scripts/scheduleInput.js
@@ -17,9 +17,12 @@
  * along with SlatePermutate.  If not, see .
  */
 
-    //--------------------------------------------------
-    // General Notes
-    //--------------------------------------------------
+/**
+ * \file
+ *
+ * If you are reading this file, you may be interested in contributing
+ * to slate_permutate. Please see http://ohnopub.net/w/SlatePermutate .
+ */
 
 /**
  * \brief
@@ -127,7 +130,7 @@ function addTips()
  * \brief
  *   Add a section to a class.
  */
-function add_section_n(cnum, name, synonym, stime, etime, days, instructor, location, type, slot, credit_hours)
+function add_section_n(cnum, name, synonym, stime, etime, days, instructor, location, type, slot, credit_hours, date_start, date_end)
 {
     var snum = last_section_i ++;
     var cssclasses = 'section class' + cnum + ' ' + safe_css_class('slot-' + slot);
@@ -212,6 +215,8 @@ function add_section_n(cnum, name, synon
 	'' +
 	'' +
 		'' +
+		'' +
+		'' +
 	'';
 
     /*
@@ -244,6 +249,8 @@ function add_section_n(cnum, name, synon
     section_tr.find('.section-location-entry').val(location);
     section_tr.find('.section-type-entry').val(type);
 	section_tr.find('.section-credit-hours-entry').val(credit_hours);
+	section_tr.find('.section-date-start-entry').val(date_start);
+	section_tr.find('.section-date-end-entry').val(date_end);
 
     /* unhide the saturday and sunday columns if they're used by autocomplete data */
 	if (days.u)
@@ -257,7 +264,7 @@ function add_section_n(cnum, name, synon
 }
 function add_section(cnum)
 {
-    var section_i = add_section_n(cnum, '', '', '', '', {}, '', '', '', 'default', -1);
+    var section_i = add_section_n(cnum, '', '', '', '', {}, '', '', '', 'default', -1, null, null);
     if (cnum == slate_permutate_course_free)
 	course_free_check(cnum);
     return section_i;
@@ -292,8 +299,15 @@ function add_sections(cnum, data)
 			section.slot = 'default';
 			if (section.credit_hours === undefined)
 				section.credit_hours = -1;
+			if (section.date_start === undefined)
+			{
+				section.date_start = null;
+				section.date_end = null;
+			}
 
-		    add_section_n(cnum, section.section, section.synonym, section.time_start, section.time_end, section.days, section.instructor, section.location, section.type, section.slot, section.credit_hours);
+		    add_section_n(cnum, section.section, section.synonym, section.time_start, section.time_end,
+						  section.days, section.instructor, section.location, section.type, section.slot,
+						  section.credit_hours, section.date_start, section.date_end);
 		});
 
     /*