Index: java/org/apache/lucene/queryParser/QueryParser.java
===================================================================
--- java/org/apache/lucene/queryParser/QueryParser.java	(revision 480688)
+++ java/org/apache/lucene/queryParser/QueryParser.java	(working copy)
@@ -47,12 +47,17 @@
  *
  * <p>In {@link RangeQuery}s, QueryParser tries to detect date values, e.g. <tt>date:[6/1/2005 TO 6/4/2005]</tt>
  * produces a range query that searches for "date" fields between 2005-06-01 and 2005-06-04. Note
- * that the format of the accpeted input depends on {@link #setLocale(Locale) the locale}. This
- * feature also assumes that your index uses the {@link DateField} class to store dates.
- * If you use a different format (e.g. {@link DateTools}) and you still want QueryParser
+ * that the format of the accepted input depends on {@link #setLocale(Locale) the locale}. This
+ * feature also assumes that your index uses the {@link DateTools} class to store dates.
+ * If you use a different format and you still want QueryParser
  * to turn local dates in range queries into valid queries you need to create your own
  * query parser that inherits QueryParser and overwrites
- * {@link #getRangeQuery(String, String, String, boolean)}.</p>
+ * {@link #getRangeQuery(String, String, String, boolean)}.
+ * The {@link DateTools.Resolution} that shall be used for RangeQueries can be set using {@link #setDateResolution(DateTools.Resolution)}
+ * and {@link #setDateResolution(String, DateTools.Resolution)}. The former sets the default date resolution for all fields, whereas the latter can
+ * be used to set field specific date resolutions. Field specific date resolutions take, if set, precedence over the default date resolution.
+ * </p>
+
  *
  * <p>Note that QueryParser is <em>not</em> thread-safe.</p>
  *
@@ -92,6 +97,11 @@
   int fuzzyPrefixLength = FuzzyQuery.defaultPrefixLength;
   Locale locale = Locale.getDefault();
 
+  /** The default date resolution */
+  public final static DateTools.Resolution DEFAULT_DATE_RESOLUTION = DateTools.Resolution.DAY;
+  DateTools.Resolution dateResolution = DEFAULT_DATE_RESOLUTION;
+  Map fieldToDateResolution = null;
+
   /** The default operator for parsing queries. 
    * Use {@link QueryParser#setDefaultOperator} to change it.
    */
@@ -286,6 +296,67 @@
     return locale;
   }
 
+  /**
+   * Sets the default date resolution used by RangeQueries for fields for which no
+   * specific date resolutions has been set. Field specific resolutions can be set
+   * with {@link #setDateResolution(String, DateTools.Resolution)}.
+   *  
+   * @param dateResolution the default date resolution to set
+   */
+  public void setDateResolution(DateTools.Resolution dateResolution) {
+    this.dateResolution = dateResolution;
+  }
+
+  /**
+   * Sets the date resolution used by RangeQueries for a specific field.
+   *  
+   * @param field field for which the date resolution is to be set 
+   * @param dateResolution date resolution to set
+   */
+  public void setDateResolution(String fieldName, DateTools.Resolution dateResolution) {
+    if (fieldName == null) {
+      throw new IllegalArgumentException("Field cannot be null.");
+    }
+
+    if (fieldToDateResolution == null) {
+      // lazily initialize HashMap
+      fieldToDateResolution = new HashMap();
+    }
+
+    fieldToDateResolution.put(fieldName, dateResolution);
+  }
+
+  /**
+   * Returns the default date resolution used by RangeQueries for fields
+   * for which no specific date resolution is set.
+   */
+  public DateTools.Resolution getDateResolution() {
+    return this.dateResolution;
+  }
+
+  /**
+   * Returns the date resolution that is used by RangeQueries for the given field. 
+   *
+   */
+  public DateTools.Resolution getDateResolution(String fieldName) {
+    if (fieldName == null) {
+      throw new IllegalArgumentException("Field cannot be null.");
+    }
+
+    if (fieldToDateResolution == null) {
+      // no field specific date resolutions set; return default date resolution instead
+      return this.dateResolution;
+    }
+
+    DateTools.Resolution resolution = (DateTools.Resolution) fieldToDateResolution.get(fieldName);
+    if (resolution == null) {
+      // no date resolutions set for the given field; return default date resolution instead
+      resolution = this.dateResolution;
+    }
+
+    return resolution;
+  }
+
   protected void addClause(Vector clauses, int conj, int mods, Query q) {
     boolean required, prohibited;
 
@@ -472,8 +543,9 @@
         cal.set(Calendar.MILLISECOND, 999);
         d2 = cal.getTime();
       }
-      part1 = DateField.dateToString(d1);
-      part2 = DateField.dateToString(d2);
+      DateTools.Resolution resolution = getDateResolution(field);
+      part1 = DateTools.dateToString(d1, resolution);
+      part2 = DateTools.dateToString(d2, resolution);
     }
     catch (Exception e) { }
 
@@ -1158,6 +1230,12 @@
     finally { jj_save(0, xla); }
   }
 
+  final private boolean jj_3R_3() {
+    if (jj_scan_token(STAR)) return true;
+    if (jj_scan_token(COLON)) return true;
+    return false;
+  }
+
   final private boolean jj_3R_2() {
     if (jj_scan_token(TERM)) return true;
     if (jj_scan_token(COLON)) return true;
@@ -1174,12 +1252,6 @@
     return false;
   }
 
-  final private boolean jj_3R_3() {
-    if (jj_scan_token(STAR)) return true;
-    if (jj_scan_token(COLON)) return true;
-    return false;
-  }
-
   public QueryParserTokenManager token_source;
   public Token token, jj_nt;
   private int jj_ntk;
@@ -1394,6 +1466,7 @@
   final private void jj_rescan_token() {
     jj_rescan = true;
     for (int i = 0; i < 1; i++) {
+    try {
       JJCalls p = jj_2_rtns[i];
       do {
         if (p.gen > jj_gen) {
@@ -1404,6 +1477,7 @@
         }
         p = p.next;
       } while (p != null);
+      } catch(LookaheadSuccess ls) { }
     }
     jj_rescan = false;
   }
Index: java/org/apache/lucene/queryParser/QueryParser.jj
===================================================================
--- java/org/apache/lucene/queryParser/QueryParser.jj	(revision 480688)
+++ java/org/apache/lucene/queryParser/QueryParser.jj	(working copy)
@@ -71,12 +71,17 @@
  *
  * <p>In {@link RangeQuery}s, QueryParser tries to detect date values, e.g. <tt>date:[6/1/2005 TO 6/4/2005]</tt>
  * produces a range query that searches for "date" fields between 2005-06-01 and 2005-06-04. Note
- * that the format of the accpeted input depends on {@link #setLocale(Locale) the locale}. This
- * feature also assumes that your index uses the {@link DateField} class to store dates.
- * If you use a different format (e.g. {@link DateTools}) and you still want QueryParser
+ * that the format of the accepted input depends on {@link #setLocale(Locale) the locale}. This
+ * feature also assumes that your index uses the {@link DateTools} class to store dates.
+ * If you use a different format and you still want QueryParser
  * to turn local dates in range queries into valid queries you need to create your own
  * query parser that inherits QueryParser and overwrites
- * {@link #getRangeQuery(String, String, String, boolean)}.</p>
+ * {@link #getRangeQuery(String, String, String, boolean)}.
+ * The {@link DateTools.Resolution} that shall be used for RangeQueries can be set using {@link #setDateResolution(DateTools.Resolution)}
+ * and {@link #setDateResolution(String, DateTools.Resolution)}. The former sets the default date resolution for all fields, whereas the latter can
+ * be used to set field specific date resolutions. Field specific date resolutions take, if set, precedence over the default date resolution.
+ * </p>
+
  *
  * <p>Note that QueryParser is <em>not</em> thread-safe.</p>
  *
@@ -116,6 +121,11 @@
   int fuzzyPrefixLength = FuzzyQuery.defaultPrefixLength;
   Locale locale = Locale.getDefault();
 
+  /** The default date resolution */  
+  public final static DateTools.Resolution DEFAULT_DATE_RESOLUTION = DateTools.Resolution.DAY;
+  DateTools.Resolution dateResolution = DEFAULT_DATE_RESOLUTION;
+  Map fieldToDateResolution = null;
+
   /** The default operator for parsing queries. 
    * Use {@link QueryParser#setDefaultOperator} to change it.
    */
@@ -310,6 +320,67 @@
     return locale;
   }
 
+  /**
+   * Sets the default date resolution used by RangeQueries for fields for which no
+   * specific date resolutions has been set. Field specific resolutions can be set
+   * with {@link #setDateResolution(String, DateTools.Resolution)}.
+   *  
+   * @param dateResolution the default date resolution to set
+   */
+  public void setDateResolution(DateTools.Resolution dateResolution) {
+    this.dateResolution = dateResolution;
+  }
+  
+  /**
+   * Sets the date resolution used by RangeQueries for a specific field.
+   *  
+   * @param field field for which the date resolution is to be set 
+   * @param dateResolution date resolution to set
+   */
+  public void setDateResolution(String fieldName, DateTools.Resolution dateResolution) {
+    if (fieldName == null) {
+      throw new IllegalArgumentException("Field cannot be null.");
+    }
+    
+    if (fieldToDateResolution == null) {
+      // lazily initialize HashMap
+      fieldToDateResolution = new HashMap();
+    }
+    
+    fieldToDateResolution.put(fieldName, dateResolution);
+  }
+  
+  /**
+   * Returns the default date resolution used by RangeQueries for fields
+   * for which no specific date resolution is set.
+   */
+  public DateTools.Resolution getDateResolution() {
+    return this.dateResolution;
+  }
+
+  /**
+   * Returns the date resolution that is used by RangeQueries for the given field. 
+   *
+   */
+  public DateTools.Resolution getDateResolution(String fieldName) {
+    if (fieldName == null) {
+      throw new IllegalArgumentException("Field cannot be null.");
+    }
+    
+    if (fieldToDateResolution == null) {
+      // no field specific date resolutions set; return default date resolution instead
+      return this.dateResolution;
+    }
+    
+    DateTools.Resolution resolution = (DateTools.Resolution) fieldToDateResolution.get(fieldName);
+    if (resolution == null) {
+      // no date resolutions set for the given field; return default date resolution instead
+      resolution = this.dateResolution;
+    }
+    
+    return resolution;
+  }
+
   protected void addClause(Vector clauses, int conj, int mods, Query q) {
     boolean required, prohibited;
 
@@ -496,8 +567,9 @@
         cal.set(Calendar.MILLISECOND, 999);
         d2 = cal.getTime();
       }
-      part1 = DateField.dateToString(d1);
-      part2 = DateField.dateToString(d2);
+      DateTools.Resolution resolution = getDateResolution(field);
+      part1 = DateTools.dateToString(d1, resolution);
+      part2 = DateTools.dateToString(d2, resolution);
     }
     catch (Exception e) { }
 
Index: java/org/apache/lucene/queryParser/QueryParserTokenManager.java
===================================================================
--- java/org/apache/lucene/queryParser/QueryParserTokenManager.java	(revision 480688)
+++ java/org/apache/lucene/queryParser/QueryParserTokenManager.java	(working copy)
@@ -1028,12 +1028,10 @@
 private final int[] jjrounds = new int[37];
 private final int[] jjstateSet = new int[74];
 protected char curChar;
-public QueryParserTokenManager(CharStream stream)
-{
+public QueryParserTokenManager(CharStream stream){
    input_stream = stream;
 }
-public QueryParserTokenManager(CharStream stream, int lexState)
-{
+public QueryParserTokenManager(CharStream stream, int lexState){
    this(stream);
    SwitchTo(lexState);
 }
Index: test/org/apache/lucene/queryParser/TestQueryParser.java
===================================================================
--- test/org/apache/lucene/queryParser/TestQueryParser.java	(revision 480688)
+++ test/org/apache/lucene/queryParser/TestQueryParser.java	(working copy)
@@ -26,7 +26,7 @@
 import org.apache.lucene.analysis.TokenStream;
 import org.apache.lucene.analysis.WhitespaceAnalyzer;
 import org.apache.lucene.analysis.standard.StandardAnalyzer;
-import org.apache.lucene.document.DateField;
+import org.apache.lucene.document.DateTools;
 import org.apache.lucene.document.Document;
 import org.apache.lucene.document.Field;
 import org.apache.lucene.index.IndexWriter;
@@ -38,6 +38,7 @@
 import java.io.Reader;
 import java.text.DateFormat;
 import java.util.Calendar;
+import java.util.Date;
 import java.util.Locale;
 
 /**
@@ -127,6 +128,16 @@
     }
   }
 
+  public void assertQueryEquals(QueryParser qp, String field, String query, String result) 
+    throws Exception {
+    Query q = qp.parse(query);
+    String s = q.toString(field);
+    if (!s.equals(result)) {
+      fail("Query /" + query + "/ yielded /" + s
+           + "/, expecting /" + result + "/");
+    }
+  }
+  
   public void assertEscapedQueryEquals(String query, Analyzer a, String result)
     throws Exception {
     String escapedQuery = QueryParser.escape(query);
@@ -379,9 +390,9 @@
     assertQueryEquals("gack ( bar blar { a TO z}) ", null, "gack (bar blar {a TO z})");
   }
 
-  private String getDate(String s) throws Exception {
+  private String getDate(String s, DateTools.Resolution resolution) throws Exception {
     DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT);
-    return DateField.dateToString(df.parse(s));
+    return DateTools.dateToString(df.parse(s), resolution);
   }
 
   private String getLocalizedDate(int year, int month, int day, boolean extendLastDate) {
@@ -403,11 +414,42 @@
     Calendar endDateExpected = Calendar.getInstance();
     endDateExpected.set(2002, 1, 4, 23, 59, 59);
     endDateExpected.set(Calendar.MILLISECOND, 999);
-    assertQueryEquals("[ " + startDate + " TO " + endDate + "]", null,
-                      "[" + getDate(startDate) + " TO " + DateField.dateToString(endDateExpected.getTime()) + "]");
-    assertQueryEquals("{  " + startDate + "    " + endDate + "   }", null,
-                      "{" + getDate(startDate) + " TO " + getDate(endDate) + "}");
+    final String defaultField = "default";
+    final String monthField = "month";
+    final String hourField = "hour";
+    QueryParser qp = new QueryParser("field", new SimpleAnalyzer());
+    
+    // Don't set any date resolution and verify if default date resolution is used
+    assertDateRangeQueryEquals(qp, defaultField, startDate, endDate, 
+                               endDateExpected.getTime(), QueryParser.DEFAULT_DATE_RESOLUTION);
+    
+    // set default date resolution to MILLISECOND 
+    qp.setDateResolution(DateTools.Resolution.MILLISECOND);
+    
+    // set two field specific date resolutions
+    qp.setDateResolution(monthField, DateTools.Resolution.MONTH);
+    qp.setDateResolution(hourField, DateTools.Resolution.HOUR);
+
+    // for this field no field specific date resolution has been set,
+    // so verify if the default resolution is used
+    assertDateRangeQueryEquals(qp, defaultField, startDate, endDate, 
+            endDateExpected.getTime(), DateTools.Resolution.MILLISECOND);
+
+    // verify if field specific date resolutions are used for these two fields
+    assertDateRangeQueryEquals(qp, monthField, startDate, endDate, 
+            endDateExpected.getTime(), DateTools.Resolution.MONTH);
+
+    assertDateRangeQueryEquals(qp, hourField, startDate, endDate, 
+            endDateExpected.getTime(), DateTools.Resolution.HOUR);  
   }
+  
+  public void assertDateRangeQueryEquals(QueryParser qp, String field, String startDate, String endDate, 
+                                         Date endDateInclusive, DateTools.Resolution resolution) throws Exception {
+    assertQueryEquals(qp, field, field + ":[" + startDate + " TO " + endDate + "]",
+               "[" + getDate(startDate, resolution) + " TO " + DateTools.dateToString(endDateInclusive, resolution) + "]");
+    assertQueryEquals(qp, field, field + ":{" + startDate + " TO " + endDate + "}",
+               "{" + getDate(startDate, resolution) + " TO " + getDate(endDate, resolution) + "}");
+  }
 
   public void testEscaped() throws Exception {
     Analyzer a = new WhitespaceAnalyzer();
@@ -747,7 +789,7 @@
     d.add(new Field("f", content, Field.Store.YES, Field.Index.TOKENIZED));
     Calendar cal = Calendar.getInstance();
     cal.set(year, month-1, day, hour, minute, second);
-    d.add(new Field("date", DateField.dateToString(cal.getTime()), Field.Store.YES, Field.Index.UN_TOKENIZED));
+    d.add(new Field("date", DateTools.dateToString(cal.getTime(), QueryParser.DEFAULT_DATE_RESOLUTION), Field.Store.YES, Field.Index.UN_TOKENIZED));
     iw.addDocument(d);
   }
 
