Lucene.Net  3.0.3
Lucene.Net is a port of the Lucene search engine library, written in C# and targeted at .NET runtime users.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Pages
DateTools.cs
Go to the documentation of this file.
1 /*
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
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  */
17 
18 using System;
19 using Lucene.Net.Search;
20 using NumericUtils = Lucene.Net.Util.NumericUtils;
21 
22 namespace Lucene.Net.Documents
23 {
24 
25  /// <summary> Provides support for converting dates to strings and vice-versa.
26  /// The strings are structured so that lexicographic sorting orders
27  /// them by date, which makes them suitable for use as field values
28  /// and search terms.
29  ///
30  /// <p/>This class also helps you to limit the resolution of your dates. Do not
31  /// save dates with a finer resolution than you really need, as then
32  /// RangeQuery and PrefixQuery will require more memory and become slower.
33  ///
34  /// <p/>Compared to <see cref="DateField" /> the strings generated by the methods
35  /// in this class take slightly more space, unless your selected resolution
36  /// is set to <c>Resolution.DAY</c> or lower.
37  ///
38  /// <p/>
39  /// Another approach is <see cref="NumericUtils" />, which provides
40  /// a sortable binary representation (prefix encoded) of numeric values, which
41  /// date/time are.
42  /// For indexing a <see cref="DateTime" />, convert it to unix timestamp as
43  /// <c>long</c> and
44  /// index this as a numeric value with <see cref="NumericField" />
45  /// and use <see cref="NumericRangeQuery{T}" /> to query it.
46  /// </summary>
47  public class DateTools
48  {
49 
50  private static readonly System.String YEAR_FORMAT = "yyyy";
51  private static readonly System.String MONTH_FORMAT = "yyyyMM";
52  private static readonly System.String DAY_FORMAT = "yyyyMMdd";
53  private static readonly System.String HOUR_FORMAT = "yyyyMMddHH";
54  private static readonly System.String MINUTE_FORMAT = "yyyyMMddHHmm";
55  private static readonly System.String SECOND_FORMAT = "yyyyMMddHHmmss";
56  private static readonly System.String MILLISECOND_FORMAT = "yyyyMMddHHmmssfff";
57 
58  private static readonly System.Globalization.Calendar calInstance = new System.Globalization.GregorianCalendar();
59 
60  // cannot create, the class has static methods only
61  private DateTools()
62  {
63  }
64 
65  /// <summary> Converts a Date to a string suitable for indexing.
66  ///
67  /// </summary>
68  /// <param name="date">the date to be converted
69  /// </param>
70  /// <param name="resolution">the desired resolution, see
71  /// <see cref="Round(DateTime, DateTools.Resolution)" />
72  /// </param>
73  /// <returns> a string in format <c>yyyyMMddHHmmssSSS</c> or shorter,
74  /// depending on <c>resolution</c>; using GMT as timezone
75  /// </returns>
76  public static System.String DateToString(System.DateTime date, Resolution resolution)
77  {
78  return TimeToString(date.Ticks / TimeSpan.TicksPerMillisecond, resolution);
79  }
80 
81  /// <summary> Converts a millisecond time to a string suitable for indexing.
82  ///
83  /// </summary>
84  /// <param name="time">the date expressed as milliseconds since January 1, 1970, 00:00:00 GMT
85  /// </param>
86  /// <param name="resolution">the desired resolution, see
87  /// <see cref="Round(long, DateTools.Resolution)" />
88  /// </param>
89  /// <returns> a string in format <c>yyyyMMddHHmmssSSS</c> or shorter,
90  /// depending on <c>resolution</c>; using GMT as timezone
91  /// </returns>
92  public static System.String TimeToString(long time, Resolution resolution)
93  {
94  System.DateTime date = new System.DateTime(Round(time, resolution));
95 
96  if (resolution == Resolution.YEAR)
97  {
98  return date.ToString(YEAR_FORMAT, System.Globalization.CultureInfo.InvariantCulture);
99  }
100  else if (resolution == Resolution.MONTH)
101  {
102  return date.ToString(MONTH_FORMAT, System.Globalization.CultureInfo.InvariantCulture);
103  }
104  else if (resolution == Resolution.DAY)
105  {
106  return date.ToString(DAY_FORMAT, System.Globalization.CultureInfo.InvariantCulture);
107  }
108  else if (resolution == Resolution.HOUR)
109  {
110  return date.ToString(HOUR_FORMAT, System.Globalization.CultureInfo.InvariantCulture);
111  }
112  else if (resolution == Resolution.MINUTE)
113  {
114  return date.ToString(MINUTE_FORMAT, System.Globalization.CultureInfo.InvariantCulture);
115  }
116  else if (resolution == Resolution.SECOND)
117  {
118  return date.ToString(SECOND_FORMAT, System.Globalization.CultureInfo.InvariantCulture);
119  }
120  else if (resolution == Resolution.MILLISECOND)
121  {
122  return date.ToString(MILLISECOND_FORMAT, System.Globalization.CultureInfo.InvariantCulture);
123  }
124 
125  throw new System.ArgumentException("unknown resolution " + resolution);
126  }
127 
128  /// <summary> Converts a string produced by <c>timeToString</c> or
129  /// <c>DateToString</c> back to a time, represented as the
130  /// number of milliseconds since January 1, 1970, 00:00:00 GMT.
131  ///
132  /// </summary>
133  /// <param name="dateString">the date string to be converted
134  /// </param>
135  /// <returns> the number of milliseconds since January 1, 1970, 00:00:00 GMT
136  /// </returns>
137  /// <throws> ParseException if <c>dateString</c> is not in the </throws>
138  /// <summary> expected format
139  /// </summary>
140  public static long StringToTime(System.String dateString)
141  {
142  return StringToDate(dateString).Ticks;
143  }
144 
145  /// <summary> Converts a string produced by <c>timeToString</c> or
146  /// <c>DateToString</c> back to a time, represented as a
147  /// Date object.
148  ///
149  /// </summary>
150  /// <param name="dateString">the date string to be converted
151  /// </param>
152  /// <returns> the parsed time as a Date object
153  /// </returns>
154  /// <throws> ParseException if <c>dateString</c> is not in the </throws>
155  /// <summary> expected format
156  /// </summary>
157  public static System.DateTime StringToDate(System.String dateString)
158  {
159  System.DateTime date;
160  if (dateString.Length == 4)
161  {
162  date = new System.DateTime(Convert.ToInt16(dateString.Substring(0, 4)),
163  1, 1, 0, 0, 0, 0);
164  }
165  else if (dateString.Length == 6)
166  {
167  date = new System.DateTime(Convert.ToInt16(dateString.Substring(0, 4)),
168  Convert.ToInt16(dateString.Substring(4, 2)),
169  1, 0, 0, 0, 0);
170  }
171  else if (dateString.Length == 8)
172  {
173  date = new System.DateTime(Convert.ToInt16(dateString.Substring(0, 4)),
174  Convert.ToInt16(dateString.Substring(4, 2)),
175  Convert.ToInt16(dateString.Substring(6, 2)),
176  0, 0, 0, 0);
177  }
178  else if (dateString.Length == 10)
179  {
180  date = new System.DateTime(Convert.ToInt16(dateString.Substring(0, 4)),
181  Convert.ToInt16(dateString.Substring(4, 2)),
182  Convert.ToInt16(dateString.Substring(6, 2)),
183  Convert.ToInt16(dateString.Substring(8, 2)),
184  0, 0, 0);
185  }
186  else if (dateString.Length == 12)
187  {
188  date = new System.DateTime(Convert.ToInt16(dateString.Substring(0, 4)),
189  Convert.ToInt16(dateString.Substring(4, 2)),
190  Convert.ToInt16(dateString.Substring(6, 2)),
191  Convert.ToInt16(dateString.Substring(8, 2)),
192  Convert.ToInt16(dateString.Substring(10, 2)),
193  0, 0);
194  }
195  else if (dateString.Length == 14)
196  {
197  date = new System.DateTime(Convert.ToInt16(dateString.Substring(0, 4)),
198  Convert.ToInt16(dateString.Substring(4, 2)),
199  Convert.ToInt16(dateString.Substring(6, 2)),
200  Convert.ToInt16(dateString.Substring(8, 2)),
201  Convert.ToInt16(dateString.Substring(10, 2)),
202  Convert.ToInt16(dateString.Substring(12, 2)),
203  0);
204  }
205  else if (dateString.Length == 17)
206  {
207  date = new System.DateTime(Convert.ToInt16(dateString.Substring(0, 4)),
208  Convert.ToInt16(dateString.Substring(4, 2)),
209  Convert.ToInt16(dateString.Substring(6, 2)),
210  Convert.ToInt16(dateString.Substring(8, 2)),
211  Convert.ToInt16(dateString.Substring(10, 2)),
212  Convert.ToInt16(dateString.Substring(12, 2)),
213  Convert.ToInt16(dateString.Substring(14, 3)));
214  }
215  else
216  {
217  throw new System.FormatException("Input is not valid date string: " + dateString);
218  }
219  return date;
220  }
221 
222  /// <summary> Limit a date's resolution. For example, the date <c>2004-09-21 13:50:11</c>
223  /// will be changed to <c>2004-09-01 00:00:00</c> when using
224  /// <c>Resolution.MONTH</c>.
225  ///
226  /// </summary>
227  /// <param name="date"></param>
228  /// <param name="resolution">The desired resolution of the date to be returned
229  /// </param>
230  /// <returns> the date with all values more precise than <c>resolution</c>
231  /// set to 0 or 1
232  /// </returns>
233  public static System.DateTime Round(System.DateTime date, Resolution resolution)
234  {
235  return new System.DateTime(Round(date.Ticks / TimeSpan.TicksPerMillisecond, resolution));
236  }
237 
238  /// <summary> Limit a date's resolution. For example, the date <c>1095767411000</c>
239  /// (which represents 2004-09-21 13:50:11) will be changed to
240  /// <c>1093989600000</c> (2004-09-01 00:00:00) when using
241  /// <c>Resolution.MONTH</c>.
242  ///
243  /// </summary>
244  /// <param name="time">The time in milliseconds (not ticks).</param>
245  /// <param name="resolution">The desired resolution of the date to be returned
246  /// </param>
247  /// <returns> the date with all values more precise than <c>resolution</c>
248  /// set to 0 or 1, expressed as milliseconds since January 1, 1970, 00:00:00 GMT
249  /// </returns>
250  public static long Round(long time, Resolution resolution)
251  {
252  System.DateTime dt = new System.DateTime(time * TimeSpan.TicksPerMillisecond);
253 
254  if (resolution == Resolution.YEAR)
255  {
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);
262  }
263  else if (resolution == Resolution.MONTH)
264  {
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);
270  }
271  else if (resolution == Resolution.DAY)
272  {
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);
277  }
278  else if (resolution == Resolution.HOUR)
279  {
280  dt = dt.AddMinutes(0 - dt.Minute);
281  dt = dt.AddSeconds(0 - dt.Second);
282  dt = dt.AddMilliseconds(0 - dt.Millisecond);
283  }
284  else if (resolution == Resolution.MINUTE)
285  {
286  dt = dt.AddSeconds(0 - dt.Second);
287  dt = dt.AddMilliseconds(0 - dt.Millisecond);
288  }
289  else if (resolution == Resolution.SECOND)
290  {
291  dt = dt.AddMilliseconds(0 - dt.Millisecond);
292  }
293  else if (resolution == Resolution.MILLISECOND)
294  {
295  // don't cut off anything
296  }
297  else
298  {
299  throw new System.ArgumentException("unknown resolution " + resolution);
300  }
301  return dt.Ticks;
302  }
303 
304  /// <summary>Specifies the time granularity. </summary>
305  public class Resolution
306  {
307 
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");
315 
316  private System.String resolution;
317 
318  internal Resolution()
319  {
320  }
321 
322  internal Resolution(System.String resolution)
323  {
324  this.resolution = resolution;
325  }
326 
327  public override System.String ToString()
328  {
329  return resolution;
330  }
331  }
332  static DateTools()
333  {
334  {
335  // times need to be normalized so the value doesn't depend on the
336  // location the index is created/used:
337  // {{Aroush-2.1}}
338  /*
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);
346  */
347  }
348  }
349  }
350 }