? apachesolr_custom_range_drilldown.patch
Index: apachesolr.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/apachesolr/apachesolr.module,v
retrieving revision 1.1.2.12.2.155.2.99
diff -u -p -r1.1.2.12.2.155.2.99 apachesolr.module
--- apachesolr.module	16 Jun 2010 20:36:48 -0000	1.1.2.12.2.155.2.99
+++ apachesolr.module	23 Jun 2010 17:05:19 -0000
@@ -1056,14 +1056,17 @@ function apachesolr_date_facet_block($re
     $options = array();
     // Iteratively remove the date facets.
     $new_query->remove_filter($facet_field, $filter['#value']);
-    if ($facet_callback && function_exists($facet_callback)) {
-      $facet_text = $facet_callback($filter['#start'], $options);
-    }
-    else {
-      $facet_text = apachesolr_date_format_iso_by_gap(apachesolr_date_find_query_gap($filter['#start'], $filter['#end']), $filter['#start']);
+    $gap = apachesolr_date_find_query_gap($filter['#start'], $filter['#end']);
+    if (apachesolr_date_exact_gap($gap, $filter['#start'], $filter['#end'])) {
+      if ($facet_callback && function_exists($facet_callback)) {
+        $facet_text = $facet_callback($filter['#start'], $options);
+      }
+      else {
+        $facet_text = apachesolr_date_format_iso_by_gap($gap, $filter['#start']);
+      }
+      $options['query'] = $new_query->get_url_queryvalues();
+      array_unshift($items, theme('apachesolr_unclick_link', $facet_text, $new_query->get_path(), $options));
     }
-    $options['query'] = $new_query->get_url_queryvalues();
-    array_unshift($items, theme('apachesolr_unclick_link', $facet_text, $new_query->get_path(), $options));
   }
   // Add links for additional date filters.
   if (!empty($response->facet_counts->facet_dates->$facet_field)) {
@@ -1135,15 +1138,31 @@ function apachesolr_date_facet_block($re
  */
 function apachesolr_date_find_query_gap($start_iso, $end_iso) {
   $gaps = array('SECOND' => 6, 'MINUTE' => 5, 'HOUR' => 4, 'DAY' => 3, 'MONTH' => 2, 'YEAR' => 1);
+
+  // Try to find an exact gap if there is one.
   $re = '@(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})@';
   if (preg_match($re, $start_iso, $start) && preg_match($re, $end_iso, $end)) {
     foreach ($gaps as $gap => $idx) {
       if ($start[$idx] != $end[$idx]) {
+        if (apachesolr_date_exact_gap($gap, $start_iso, $end_iso)) {
+          return $gap;
+        }
+      }
+    }
+  }
+
+  // If no exact gaps are found, we try again from the highest unit of time to
+  // the lowest, minusing 1 second from the end time to avoid incidental gaps.
+  $end_iso = date('c', strtotime($end_iso) - 1);
+  if (preg_match($re, $start_iso, $start) && preg_match($re, $end_iso, $end)) {
+    foreach (array_reverse($gaps) as $gap => $idx) {
+      if ($start[$idx] != $end[$idx]) {
         return $gap;
       }
     }
   }
-  // can't tell
+
+  // Can't tell.
   return 'YEAR';
 }
 
@@ -1242,21 +1261,94 @@ function apachesolr_date_determine_gap($
 }
 
 /**
- * Return the next smaller date gap.
+ * Determine whether the gap between start and end is exactly one unit of time.
  *
  * @param $gap
  *   A gap.
+ * @param $start
+ *   Start date as an ISO date string.
+ * @param $end
+ *   End date as an ISO date string.
+ * @return
+ *   TRUE if the difference between start and end represents exactly one unit
+ *   of time as determined by the gap.
+ */
+function apachesolr_date_exact_gap($gap, $start, $end) {
+  $diff = strtotime($end) - strtotime($start);
+  switch ($gap) {
+    case 'YEAR':
+      if (substr($start, 4) == '-01-01T00:00:00Z' && substr($start, 4) == substr($end, 4) && in_array($diff, array(86400*365, 86400*366))) {
+        return TRUE;
+      }
+    case 'MONTH':
+      if (substr($start, 7) == '-01T00:00:00Z' && substr($start, 7) == substr($end, 7) && in_array($diff, array(86400*28, 86400*29, 86400*30, 86400*31))) {
+        return TRUE;
+      }
+    case 'DAY':
+      if (substr($start, 10) == 'T00:00:00Z' && substr($start, 10) == substr($end, 10) && $diff == 86400) {
+        return TRUE;
+      }
+    case 'HOUR':
+      if (substr($start, 14) == '00:00Z' && substr($start, 14) == substr($end, 14) && $diff == 3600) {
+        return TRUE;
+      }
+    case 'MINUTE':
+      if (substr($start, 17) == '00Z' && substr($start, 17) == substr($end, 17) && $diff == 60) {
+        return TRUE;
+      }
+    case 'SECOND':
+      if ($diff == 1) {
+        return TRUE;
+      }
+  }
+  return FALSE;
+}
+
+/**
+ * Return the next smaller date gap if range within one unit of time.
+ *
+ * @param $start
+ *   Start date as an ISO date string.
+ * @param $end
+ *   End date as an ISO date string.
  * @return
  *   The next smaller gap, or NULL if there is no smaller gap.
  */
-function apachesolr_date_gap_drilldown($gap) {
-  $drill = array(
-    'YEAR' => 'MONTH',
-    'MONTH' => 'DAY',
-    'DAY' => 'HOUR',
-    'HOUR' => 'MINUTE',
-  );
-  return isset($drill[$gap]) ? $drill[$gap] : NULL;
+function apachesolr_date_gap_drilldown($start, $end) {
+  $gap = apachesolr_date_find_query_gap($start, $end);
+  $exact = apachesolr_date_exact_gap($gap, $start, $end);
+
+  switch ($gap) {
+    case 'YEAR':
+      if ($exact) {
+        return 'MONTH';
+      }
+      else {
+        return 'YEAR';
+      }
+    case 'MONTH':
+      if ($exact) {
+        return 'DAY';
+      }
+      else {
+        return 'MONTH';
+      }
+    case 'DAY':
+      if ($exact) {
+        return 'HOUR';
+      }
+      else {
+        return 'DAY';
+      }
+    case 'HOUR':
+      if ($exact) {
+        return 'MINUTE';
+      }
+      else {
+        return 'HOUR';
+      }
+  }
+  return NULL;
 }
 
 /**
Index: apachesolr_search.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/apachesolr/apachesolr_search.module,v
retrieving revision 1.1.2.6.2.111.2.80
diff -u -p -r1.1.2.6.2.111.2.80 apachesolr_search.module
--- apachesolr_search.module	16 Jun 2010 20:36:48 -0000	1.1.2.6.2.111.2.80
+++ apachesolr_search.module	23 Jun 2010 17:05:19 -0000
@@ -595,7 +595,7 @@ function apachesolr_search_date_range($q
         $start_iso = $filter['#start'];
         $end_iso = $filter['#end'];
       // Determine the drilldown gap for this range.
-      $gap = apachesolr_date_gap_drilldown(apachesolr_date_find_query_gap($start_iso, $end_iso));
+      $gap = apachesolr_date_gap_drilldown($start_iso, $end_iso);
     }
   }
   // If there is no $delta field in query object, get initial
Index: contrib/apachesolr_date/apachesolr_date.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/apachesolr/contrib/apachesolr_date/apachesolr_date.module,v
retrieving revision 1.1.2.5
diff -u -p -r1.1.2.5 apachesolr_date.module
--- contrib/apachesolr_date/apachesolr_date.module	2 Jun 2010 21:24:25 -0000	1.1.2.5
+++ contrib/apachesolr_date/apachesolr_date.module	23 Jun 2010 17:05:19 -0000
@@ -257,7 +257,7 @@ function apachesolr_date_search_date_ran
         $start_iso = $filter['#start'];
         $end_iso = $filter['#end'];
       // Determine the drilldown gap for this range.
-      $gap = apachesolr_date_gap_drilldown(apachesolr_date_find_query_gap($start_iso, $end_iso));
+      $gap = apachesolr_date_gap_drilldown($start_iso, $end_iso);
     }
   }
 
@@ -355,10 +355,12 @@ function apachesolr_date_date_facet_bloc
   foreach (array_reverse($new_query->get_filters($facet_field)) as $filter) {
     $new_query->remove_filter($facet_field, $filter['#value']);
     $gap = apachesolr_date_find_query_gap($filter['#start'], $filter['#end']);
-    $facet_text = apachesolr_date_format_iso_by_gap($gap, $filter['#start']);
-    $options['gap'] = $gap;
-    $options['query'] = $new_query->get_url_queryvalues();
-    array_unshift($items, theme('apachesolr_unclick_link', $facet_text, $new_query->get_path(), $options));
+    if (apachesolr_date_exact_gap($gap, $filter['#start'], $filter['#end'])) {
+      $facet_text = apachesolr_date_format_iso_by_gap($gap, $filter['#start']);
+      $options['gap'] = $gap;
+      $options['query'] = $new_query->get_url_queryvalues();
+      array_unshift($items, theme('apachesolr_unclick_link', $facet_text, $new_query->get_path(), $options));
+    }
   }
 
   // Add links for additional date filters.
