diff --git a/src/java/org/apache/lucene/document/DateField.java b/src/java/org/apache/lucene/document/DateField.java index 5cecac44a95..20ef345cd18 100644 --- a/src/java/org/apache/lucene/document/DateField.java +++ b/src/java/org/apache/lucene/document/DateField.java @@ -18,26 +18,27 @@ package org.apache.lucene.document; 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. * - *
- * 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 yyyy-mm-dd hh:mm:ss
- * (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.
+ *
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. * *
* 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 diff --git a/src/java/org/apache/lucene/document/DateTools.java b/src/java/org/apache/lucene/document/DateTools.java new file mode 100644 index 00000000000..da1ae669ed9 --- /dev/null +++ b/src/java/org/apache/lucene/document/DateTools.java @@ -0,0 +1,224 @@ +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. + * + *
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. + * + *
Compared to {@link DateField} the strings generated by the methods
+ * in this class take slightly more space, unless your selected resolution
+ * is set to Resolution.DAY
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 yyyyMMddHHmmssSSS
or shorter,
+ * depeding on resolution
+ */
+ 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 yyyyMMddHHmmssSSS
or shorter,
+ * depeding on resolution
+ */
+ 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 timeToString
or
+ * dateToString
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 dateString
is not in the
+ * expected format
+ */
+ public static long stringToTime(String dateString) throws ParseException {
+ return stringToDate(dateString).getTime();
+ }
+
+ /**
+ * Converts a string produced by timeToString
or
+ * dateToString
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 dateString
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 2004-09-21 13:50:11
+ * will be changed to 2004-09-01 00:00:00
when using
+ * Resolution.MONTH
.
+ *
+ * @param resolution The desired resolution of the date to be returned
+ * @return the date with all values more precise than resolution
+ * 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 1095767411000
+ * (which represents 2004-09-21 13:50:11) will be changed to
+ * 1093989600000
(2004-09-01 00:00:00) when using
+ * Resolution.MONTH
.
+ *
+ * @param resolution The desired resolution of the date to be returned
+ * @return the date with all values more precise than resolution
+ * 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;
+ }
+
+ }
+
+}