You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@lucene.apache.org by dn...@apache.org on 2004/09/05 23:27:29 UTC

cvs commit: jakarta-lucene/src/java/org/apache/lucene/document DateTools.java DateField.java

dnaber      2004/09/05 14:27:29

  Modified:    src/java/org/apache/lucene/document DateField.java
  Added:       src/java/org/apache/lucene/document DateTools.java
  Log:
  Add a new class that supports converting dates to readable strings, with limited resolution. Other public methods let people limit the resolution of their dates.
  DateField is not deprecated because it still has the advantage of slightly shorter fields in some cases.
  
  Revision  Changes    Path
  1.8       +11 -10    jakarta-lucene/src/java/org/apache/lucene/document/DateField.java
  
  Index: DateField.java
  ===================================================================
  RCS file: /home/cvs/jakarta-lucene/src/java/org/apache/lucene/document/DateField.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- DateField.java	14 May 2004 12:36:26 -0000	1.7
  +++ DateField.java	5 Sep 2004 21:27:29 -0000	1.8
  @@ -18,26 +18,27 @@
   
   import java.util.Date;
   
  +import org.apache.lucene.search.PrefixQuery;  // for javadoc
  +import org.apache.lucene.search.RangeQuery;   // for javadoc
  +
   /**
    * Provides support for converting dates to strings and vice-versa.
    * The strings are structured so that lexicographic sorting orders by date,
    * which makes them suitable for use as field values and search terms.
    * 
  - * <P>
  - * Note that you do not have to use this class, you can just save your
  - * dates as strings if lexicographic sorting orders them by date. This is
  - * the case for example for dates like <code>yyyy-mm-dd hh:mm:ss</code>
  - * (of course you can leave out the delimiter characters to save some space).
  - * The advantage with using such a format is that you can easily save dates
  - * with the required granularity, e.g. leaving out seconds. This saves memory
  - * when searching with a RangeQuery or PrefixQuery, as Lucene
  - * expands these queries to a BooleanQuery with potentially very many terms. 
  + * <P>Note that this class saves dates with millisecond granularity,
  + * which is bad for {@link RangeQuery} and {@link PrefixQuery}, as those
  + * queries are expanded to a BooleanQuery with a potentially large number 
  + * of terms when searching. Thus you might want to use
  + * {@link DateTools} instead.
    * 
    * <P>
    * Note: dates before 1970 cannot be used, and therefore cannot be
  - * indexed when using this class.
  + * indexed when using this class. See {@link DateTools} for an
  + * alternative without such a limitation.
    */
   public class DateField {
  +  
     private DateField() {}
   
     // make date strings long enough to last a millenium
  
  
  
  1.1                  jakarta-lucene/src/java/org/apache/lucene/document/DateTools.java
  
  Index: DateTools.java
  ===================================================================
  package org.apache.lucene.document;
  
  /**
   * Copyright 2004 The Apache Software Foundation
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  import java.text.ParseException;
  import java.text.SimpleDateFormat;
  import java.util.Calendar;
  import java.util.Date;
  
  /**
   * Provides support for converting dates to strings and vice-versa.
   * The strings are structured so that lexicographic sorting orders 
   * them by date, which makes them suitable for use as field values 
   * and search terms.
   * 
   * <P>This class also helps you to limit the resolution of your dates. Do not
   * save dates with a finer resolution than you really need, as then
   * RangeQuery and PrefixQuery will require more memory and become slower.
   * 
   * <P>Compared to {@link DateField} the strings generated by the methods
   * in this class take slightly more space, unless your selected resolution
   * is set to <code>Resolution.DAY</code> or lower.
   */
  public class DateTools {
  
    private DateTools() {}
  
    /**
     * Converts a Date to a string suitable for indexing.
     * 
     * @param date the date to be converted
     * @param resolution the desired resolution, see
     *  {@link #round(Date, DateTools.Resolution)}
     * @return a string in format <code>yyyyMMddHHmmssSSS</code> or shorter,
     *  depeding on <code>resolution</code>
     */
    public static String dateToString(Date date, Resolution resolution) {
      return timeToString(date.getTime(), resolution);
    }
    
    /**
     * Converts a millisecond time to a string suitable for indexing.
     * 
     * @param time the date expressed as milliseconds since January 1, 1970, 00:00:00 GMT
     * @param resolution the desired resolution, see
     *  {@link #round(long, DateTools.Resolution)}
     * @return a string in format <code>yyyyMMddHHmmssSSS</code> or shorter,
     *  depeding on <code>resolution</code>
     */
    public static String timeToString(long time, Resolution resolution) {
      Calendar cal = Calendar.getInstance();
      cal.setTimeInMillis(round(time, resolution));
  
      SimpleDateFormat sdf = new SimpleDateFormat();
      String pattern = null;
      if (resolution == Resolution.YEAR) {
        pattern = "yyyy";
      } else if (resolution == Resolution.MONTH) {
        pattern = "yyyyMM";
      } else if (resolution == Resolution.DAY) {
        pattern = "yyyyMMdd";
      } else if (resolution == Resolution.HOUR) {
        pattern = "yyyyMMddHH";
      } else if (resolution == Resolution.MINUTE) {
        pattern = "yyyyMMddHHmm";
      } else if (resolution == Resolution.SECOND) {
        pattern = "yyyyMMddHHmmss";
      } else if (resolution == Resolution.MILLISECOND) {
        pattern = "yyyyMMddHHmmssSSS";
      } else {
        throw new IllegalArgumentException("unknown resolution " + resolution);
      }
      sdf.applyPattern(pattern);
      return sdf.format(cal.getTime());
    }
  
    /**
     * Converts a string produced by <code>timeToString</code> or
     * <code>dateToString</code> back to a time, represented as the
     * number of milliseconds since January 1, 1970, 00:00:00 GMT.
     * 
     * @param dateString the date string to be converted
     * @return the number of milliseconds since January 1, 1970, 00:00:00 GMT
     * @throws ParseException if <code>dateString</code> is not in the 
     *  expected format 
     */
    public static long stringToTime(String dateString) throws ParseException {
      return stringToDate(dateString).getTime();
    }
  
    /**
     * Converts a string produced by <code>timeToString</code> or
     * <code>dateToString</code> back to a time, represented as a
     * Date object.
     * 
     * @param dateString the date string to be converted
     * @return the parsed time as a Date object 
     * @throws ParseException if <code>dateString</code> is not in the 
     *  expected format 
     */
    public static Date stringToDate(String dateString) throws ParseException {
      String pattern = null;
      if (dateString.length() == 4 )
        pattern = "yyyy";
      else if (dateString.length() == 6 )
        pattern = "yyyyMM";
      else if (dateString.length() == 8 )
        pattern = "yyyyMMdd";
      else if (dateString.length() == 10 )
        pattern = "yyyyMMddHH";
      else if (dateString.length() == 12 )
        pattern = "yyyyMMddHHmm";
      else if (dateString.length() == 14 )
        pattern = "yyyyMMddHHmmss";
      else if (dateString.length() == 17 )
        pattern = "yyyyMMddHHmmssSSS";
      else
        throw new ParseException("Input is not valid date string: " + dateString, 0);
      SimpleDateFormat sdf = new SimpleDateFormat(pattern);
      Date date = sdf.parse(dateString);
      return date;
    }
    
    /**
     * Limit a date's resolution. For example, the date <code>2004-09-21 13:50:11</code>
     * will be changed to <code>2004-09-01 00:00:00</code> when using
     * <code>Resolution.MONTH</code>. 
     * 
     * @param resolution The desired resolution of the date to be returned
     * @return the date with all values more precise than <code>resolution</code>
     *  set to 0 or 1
     */
    public static Date round(Date date, Resolution resolution) {
      return new Date(round(date.getTime(), resolution));
    }
    
    /**
     * Limit a date's resolution. For example, the date <code>1095767411000</code>
     * (which represents 2004-09-21 13:50:11) will be changed to 
     * <code>1093989600000</code> (2004-09-01 00:00:00) when using
     * <code>Resolution.MONTH</code>.
     * 
     * @param resolution The desired resolution of the date to be returned
     * @return the date with all values more precise than <code>resolution</code>
     *  set to 0 or 1, expressed as milliseconds since January 1, 1970, 00:00:00 GMT
     */
    public static long round(long time, Resolution resolution) {
      Calendar cal = Calendar.getInstance();
      cal.setTimeInMillis(time);
      if (resolution == Resolution.YEAR) {
        cal.set(Calendar.MONTH, 0);
        cal.set(Calendar.DAY_OF_MONTH, 1);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
      } else if (resolution == Resolution.MONTH) {
        cal.set(Calendar.DAY_OF_MONTH, 1);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
      } else if (resolution == Resolution.DAY) {
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
      } else if (resolution == Resolution.HOUR) {
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
      } else if (resolution == Resolution.MINUTE) {
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
      } else if (resolution == Resolution.SECOND) {
        cal.set(Calendar.MILLISECOND, 0);
      } else if (resolution == Resolution.MILLISECOND) {
        // don't cut off anything
      } else {
        throw new IllegalArgumentException("unknown resolution " + resolution);
      }
      return cal.getTime().getTime();
    }
  
    public static class Resolution {
      
      public static final Resolution YEAR = new Resolution("year");
      public static final Resolution MONTH = new Resolution("month");
      public static final Resolution DAY = new Resolution("day");
      public static final Resolution HOUR = new Resolution("hour");
      public static final Resolution MINUTE = new Resolution("minute");
      public static final Resolution SECOND = new Resolution("second");
      public static final Resolution MILLISECOND = new Resolution("millisecond");
  
      private String resolution;
  
      private Resolution() {
      }
      
      private Resolution(String resolution) {
        this.resolution = resolution;
      }
      
      public String toString() {
        return resolution;
      }
  
    }
  
  }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: lucene-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: lucene-dev-help@jakarta.apache.org