2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
20 using NumericUtils = Mono.Lucene.Net.Util.NumericUtils;
21 using NumericRangeQuery = Mono.Lucene.Net.Search.NumericRangeQuery;
23 namespace Mono.Lucene.Net.Documents
26 /// <summary> Provides support for converting dates to strings and vice-versa.
27 /// The strings are structured so that lexicographic sorting orders
28 /// them by date, which makes them suitable for use as field values
31 /// <p/>This class also helps you to limit the resolution of your dates. Do not
32 /// save dates with a finer resolution than you really need, as then
33 /// RangeQuery and PrefixQuery will require more memory and become slower.
35 /// <p/>Compared to {@link DateField} the strings generated by the methods
36 /// in this class take slightly more space, unless your selected resolution
37 /// is set to <code>Resolution.DAY</code> or lower.
40 /// Another approach is {@link NumericUtils}, which provides
41 /// a sortable binary representation (prefix encoded) of numeric values, which
43 /// For indexing a {@link Date} or {@link Calendar}, just get the unix timestamp as
44 /// <code>long</code> using {@link Date#getTime} or {@link Calendar#getTimeInMillis} and
45 /// index this as a numeric value with {@link NumericField}
46 /// and use {@link NumericRangeQuery} to query it.
48 public class DateTools
51 private static readonly System.String YEAR_FORMAT = "yyyy";
52 private static readonly System.String MONTH_FORMAT = "yyyyMM";
53 private static readonly System.String DAY_FORMAT = "yyyyMMdd";
54 private static readonly System.String HOUR_FORMAT = "yyyyMMddHH";
55 private static readonly System.String MINUTE_FORMAT = "yyyyMMddHHmm";
56 private static readonly System.String SECOND_FORMAT = "yyyyMMddHHmmss";
57 private static readonly System.String MILLISECOND_FORMAT = "yyyyMMddHHmmssfff";
59 private static readonly System.Globalization.Calendar calInstance = new System.Globalization.GregorianCalendar();
61 // cannot create, the class has static methods only
66 /// <summary> Converts a Date to a string suitable for indexing.
69 /// <param name="date">the date to be converted
71 /// <param name="resolution">the desired resolution, see
72 /// {@link #Round(Date, DateTools.Resolution)}
74 /// <returns> a string in format <code>yyyyMMddHHmmssSSS</code> or shorter,
75 /// depending on <code>resolution</code>; using GMT as timezone
77 public static System.String DateToString(System.DateTime date, Resolution resolution)
79 return TimeToString(date.Ticks / TimeSpan.TicksPerMillisecond, resolution);
82 /// <summary> Converts a millisecond time to a string suitable for indexing.
85 /// <param name="time">the date expressed as milliseconds since January 1, 1970, 00:00:00 GMT
87 /// <param name="resolution">the desired resolution, see
88 /// {@link #Round(long, DateTools.Resolution)}
90 /// <returns> a string in format <code>yyyyMMddHHmmssSSS</code> or shorter,
91 /// depending on <code>resolution</code>; using GMT as timezone
93 public static System.String TimeToString(long time, Resolution resolution)
95 System.DateTime date = new System.DateTime(Round(time, resolution));
97 if (resolution == Resolution.YEAR)
99 return date.ToString(YEAR_FORMAT);
101 else if (resolution == Resolution.MONTH)
103 return date.ToString(MONTH_FORMAT);
105 else if (resolution == Resolution.DAY)
107 return date.ToString(DAY_FORMAT);
109 else if (resolution == Resolution.HOUR)
111 return date.ToString(HOUR_FORMAT);
113 else if (resolution == Resolution.MINUTE)
115 return date.ToString(MINUTE_FORMAT);
117 else if (resolution == Resolution.SECOND)
119 return date.ToString(SECOND_FORMAT);
121 else if (resolution == Resolution.MILLISECOND)
123 return date.ToString(MILLISECOND_FORMAT);
126 throw new System.ArgumentException("unknown resolution " + resolution);
129 /// <summary> Converts a string produced by <code>timeToString</code> or
130 /// <code>DateToString</code> back to a time, represented as the
131 /// number of milliseconds since January 1, 1970, 00:00:00 GMT.
134 /// <param name="dateString">the date string to be converted
136 /// <returns> the number of milliseconds since January 1, 1970, 00:00:00 GMT
138 /// <throws> ParseException if <code>dateString</code> is not in the </throws>
139 /// <summary> expected format
141 public static long StringToTime(System.String dateString)
143 return StringToDate(dateString).Ticks;
146 /// <summary> Converts a string produced by <code>timeToString</code> or
147 /// <code>DateToString</code> back to a time, represented as a
151 /// <param name="dateString">the date string to be converted
153 /// <returns> the parsed time as a Date object
155 /// <throws> ParseException if <code>dateString</code> is not in the </throws>
156 /// <summary> expected format
158 public static System.DateTime StringToDate(System.String dateString)
160 System.DateTime date;
161 if (dateString.Length == 4)
163 date = new System.DateTime(Convert.ToInt16(dateString.Substring(0, 4)),
166 else if (dateString.Length == 6)
168 date = new System.DateTime(Convert.ToInt16(dateString.Substring(0, 4)),
169 Convert.ToInt16(dateString.Substring(4, 2)),
172 else if (dateString.Length == 8)
174 date = new System.DateTime(Convert.ToInt16(dateString.Substring(0, 4)),
175 Convert.ToInt16(dateString.Substring(4, 2)),
176 Convert.ToInt16(dateString.Substring(6, 2)),
179 else if (dateString.Length == 10)
181 date = new System.DateTime(Convert.ToInt16(dateString.Substring(0, 4)),
182 Convert.ToInt16(dateString.Substring(4, 2)),
183 Convert.ToInt16(dateString.Substring(6, 2)),
184 Convert.ToInt16(dateString.Substring(8, 2)),
187 else if (dateString.Length == 12)
189 date = new System.DateTime(Convert.ToInt16(dateString.Substring(0, 4)),
190 Convert.ToInt16(dateString.Substring(4, 2)),
191 Convert.ToInt16(dateString.Substring(6, 2)),
192 Convert.ToInt16(dateString.Substring(8, 2)),
193 Convert.ToInt16(dateString.Substring(10, 2)),
196 else if (dateString.Length == 14)
198 date = new System.DateTime(Convert.ToInt16(dateString.Substring(0, 4)),
199 Convert.ToInt16(dateString.Substring(4, 2)),
200 Convert.ToInt16(dateString.Substring(6, 2)),
201 Convert.ToInt16(dateString.Substring(8, 2)),
202 Convert.ToInt16(dateString.Substring(10, 2)),
203 Convert.ToInt16(dateString.Substring(12, 2)),
206 else if (dateString.Length == 17)
208 date = new System.DateTime(Convert.ToInt16(dateString.Substring(0, 4)),
209 Convert.ToInt16(dateString.Substring(4, 2)),
210 Convert.ToInt16(dateString.Substring(6, 2)),
211 Convert.ToInt16(dateString.Substring(8, 2)),
212 Convert.ToInt16(dateString.Substring(10, 2)),
213 Convert.ToInt16(dateString.Substring(12, 2)),
214 Convert.ToInt16(dateString.Substring(14, 3)));
218 throw new System.FormatException("Input is not valid date string: " + dateString);
223 /// <summary> Limit a date's resolution. For example, the date <code>2004-09-21 13:50:11</code>
224 /// will be changed to <code>2004-09-01 00:00:00</code> when using
225 /// <code>Resolution.MONTH</code>.
228 /// <param name="resolution">The desired resolution of the date to be returned
230 /// <returns> the date with all values more precise than <code>resolution</code>
233 public static System.DateTime Round(System.DateTime date, Resolution resolution)
235 return new System.DateTime(Round(date.Ticks / TimeSpan.TicksPerMillisecond, resolution));
238 /// <summary> Limit a date's resolution. For example, the date <code>1095767411000</code>
239 /// (which represents 2004-09-21 13:50:11) will be changed to
240 /// <code>1093989600000</code> (2004-09-01 00:00:00) when using
241 /// <code>Resolution.MONTH</code>.
244 /// <param name="time">The time in milliseconds (not ticks).</param>
245 /// <param name="resolution">The desired resolution of the date to be returned
247 /// <returns> the date with all values more precise than <code>resolution</code>
248 /// set to 0 or 1, expressed as milliseconds since January 1, 1970, 00:00:00 GMT
250 public static long Round(long time, Resolution resolution)
252 System.DateTime dt = new System.DateTime(time * TimeSpan.TicksPerMillisecond);
254 if (resolution == Resolution.YEAR)
256 dt = dt.AddMonths(1 - dt.Month);
257 dt = dt.AddDays(1 - dt.Day);
258 dt = dt.AddHours(0 - dt.Hour);
259 dt = dt.AddMinutes(0 - dt.Minute);
260 dt = dt.AddSeconds(0 - dt.Second);
261 dt = dt.AddMilliseconds(0 - dt.Millisecond);
263 else if (resolution == Resolution.MONTH)
265 dt = dt.AddDays(1 - dt.Day);
266 dt = dt.AddHours(0 - dt.Hour);
267 dt = dt.AddMinutes(0 - dt.Minute);
268 dt = dt.AddSeconds(0 - dt.Second);
269 dt = dt.AddMilliseconds(0 - dt.Millisecond);
271 else if (resolution == Resolution.DAY)
273 dt = dt.AddHours(0 - dt.Hour);
274 dt = dt.AddMinutes(0 - dt.Minute);
275 dt = dt.AddSeconds(0 - dt.Second);
276 dt = dt.AddMilliseconds(0 - dt.Millisecond);
278 else if (resolution == Resolution.HOUR)
280 dt = dt.AddMinutes(0 - dt.Minute);
281 dt = dt.AddSeconds(0 - dt.Second);
282 dt = dt.AddMilliseconds(0 - dt.Millisecond);
284 else if (resolution == Resolution.MINUTE)
286 dt = dt.AddSeconds(0 - dt.Second);
287 dt = dt.AddMilliseconds(0 - dt.Millisecond);
289 else if (resolution == Resolution.SECOND)
291 dt = dt.AddMilliseconds(0 - dt.Millisecond);
293 else if (resolution == Resolution.MILLISECOND)
295 // don't cut off anything
299 throw new System.ArgumentException("unknown resolution " + resolution);
304 /// <summary>Specifies the time granularity. </summary>
305 public class Resolution
308 public static readonly Resolution YEAR = new Resolution("year");
309 public static readonly Resolution MONTH = new Resolution("month");
310 public static readonly Resolution DAY = new Resolution("day");
311 public static readonly Resolution HOUR = new Resolution("hour");
312 public static readonly Resolution MINUTE = new Resolution("minute");
313 public static readonly Resolution SECOND = new Resolution("second");
314 public static readonly Resolution MILLISECOND = new Resolution("millisecond");
316 private System.String resolution;
318 internal Resolution()
322 internal Resolution(System.String resolution)
324 this.resolution = resolution;
327 public override System.String ToString()
335 // times need to be normalized so the value doesn't depend on the
336 // location the index is created/used:
339 YEAR_FORMAT.setTimeZone(GMT);
340 MONTH_FORMAT.setTimeZone(GMT);
341 DAY_FORMAT.setTimeZone(GMT);
342 HOUR_FORMAT.setTimeZone(GMT);
343 MINUTE_FORMAT.setTimeZone(GMT);
344 SECOND_FORMAT.setTimeZone(GMT);
345 MILLISECOND_FORMAT.setTimeZone(GMT);