-
Notifications
You must be signed in to change notification settings - Fork 624
/
DateTools.cs
312 lines (293 loc) · 14.5 KB
/
DateTools.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
using System;
using System.Globalization;
namespace Lucene.Net.Documents
{
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
/// <summary>
/// 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.
///
/// <para/>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
/// <see cref="Search.TermRangeQuery"/> and <see cref="Search.PrefixQuery"/> will require more memory and become slower.
///
/// <para/>
/// Another approach is <see cref="Util.NumericUtils"/>, which provides
/// a sortable binary representation (prefix encoded) of numeric values, which
/// date/time are.
///
/// For indexing a <see cref="DateTime"/>, just get the <see cref="DateTime.Ticks"/> and index
/// this as a numeric value with <see cref="Int64Field"/> and use <see cref="Search.NumericRangeQuery{T}"/>
/// to query it.
/// </summary>
public static class DateTools
{
private const string YEAR_FORMAT = "yyyy";
private const string MONTH_FORMAT = "yyyyMM";
private const string DAY_FORMAT = "yyyyMMdd";
private const string HOUR_FORMAT = "yyyyMMddHH";
private const string MINUTE_FORMAT = "yyyyMMddHHmm";
private const string SECOND_FORMAT = "yyyyMMddHHmmss";
private const string MILLISECOND_FORMAT = "yyyyMMddHHmmssfff";
// LUCENENET - not used
//private static readonly System.Globalization.Calendar calInstance = new System.Globalization.GregorianCalendar();
/// <summary>
/// Converts a <see cref="DateTime"/> to a string suitable for indexing.
/// </summary>
/// <param name="date"> the date to be converted </param>
/// <param name="resolution"> the desired resolution, see
/// <see cref="Round(DateTime, DateTools.Resolution)"/> </param>
/// <returns> a string in format <c>yyyyMMddHHmmssSSS</c> or shorter,
/// depending on <paramref name="resolution"/>; using GMT as timezone </returns>
public static string DateToString(DateTime date, Resolution resolution)
{
return TimeToString(date.Ticks / TimeSpan.TicksPerMillisecond, resolution);
}
/// <summary>
/// Converts a millisecond time to a string suitable for indexing.
/// </summary>
/// <param name="time"> the date expressed as milliseconds since January 1, 1970, 00:00:00 GMT (also known as the "epoch") </param>
/// <param name="resolution"> the desired resolution, see
/// <see cref="Round(long, DateTools.Resolution)"/> </param>
/// <returns> a string in format <c>yyyyMMddHHmmssSSS</c> or shorter,
/// depending on <paramref name="resolution"/>; using GMT as timezone </returns>
public static string TimeToString(long time, Resolution resolution)
{
DateTime date = new DateTime(Round(time, resolution));
if (resolution == Resolution.YEAR)
{
return date.ToString(YEAR_FORMAT, CultureInfo.InvariantCulture);
}
else if (resolution == Resolution.MONTH)
{
return date.ToString(MONTH_FORMAT, CultureInfo.InvariantCulture);
}
else if (resolution == Resolution.DAY)
{
return date.ToString(DAY_FORMAT, CultureInfo.InvariantCulture);
}
else if (resolution == Resolution.HOUR)
{
return date.ToString(HOUR_FORMAT, CultureInfo.InvariantCulture);
}
else if (resolution == Resolution.MINUTE)
{
return date.ToString(MINUTE_FORMAT, CultureInfo.InvariantCulture);
}
else if (resolution == Resolution.SECOND)
{
return date.ToString(SECOND_FORMAT, CultureInfo.InvariantCulture);
}
else if (resolution == Resolution.MILLISECOND)
{
return date.ToString(MILLISECOND_FORMAT, CultureInfo.InvariantCulture);
}
throw new ArgumentException("unknown resolution " + resolution);
}
/// <summary>
/// Converts a string produced by <see cref="TimeToString(long, Resolution)"/> or
/// <see cref="DateToString(DateTime, Resolution)"/> back to a time, represented as the
/// number of milliseconds since January 1, 1970, 00:00:00 GMT (also known as the "epoch").
/// </summary>
/// <param name="dateString"> the date string to be converted </param>
/// <returns> the number of milliseconds since January 1, 1970, 00:00:00 GMT (also known as the "epoch")</returns>
/// <exception cref="FormatException"> if <paramref name="dateString"/> is not in the
/// expected format </exception>
public static long StringToTime(string dateString)
{
return StringToDate(dateString).Ticks;
}
/// <summary>
/// Converts a string produced by <see cref="TimeToString(long, Resolution)"/> or
/// <see cref="DateToString(DateTime, Resolution)"/> back to a time, represented as a
/// <see cref="DateTime"/> object.
/// </summary>
/// <param name="dateString"> the date string to be converted </param>
/// <returns> the parsed time as a <see cref="DateTime"/> object </returns>
/// <exception cref="FormatException"> if <paramref name="dateString"/> is not in the
/// expected format </exception>
public static DateTime StringToDate(string dateString)
{
DateTime date;
if (dateString.Length == 4)
{
date = new DateTime(Convert.ToInt16(dateString.Substring(0, 4), CultureInfo.InvariantCulture),
1, 1, 0, 0, 0, 0);
}
else if (dateString.Length == 6)
{
date = new DateTime(Convert.ToInt16(dateString.Substring(0, 4), CultureInfo.InvariantCulture),
Convert.ToInt16(dateString.Substring(4, 2), CultureInfo.InvariantCulture),
1, 0, 0, 0, 0);
}
else if (dateString.Length == 8)
{
date = new DateTime(Convert.ToInt16(dateString.Substring(0, 4), CultureInfo.InvariantCulture),
Convert.ToInt16(dateString.Substring(4, 2), CultureInfo.InvariantCulture),
Convert.ToInt16(dateString.Substring(6, 2), CultureInfo.InvariantCulture),
0, 0, 0, 0);
}
else if (dateString.Length == 10)
{
date = new DateTime(Convert.ToInt16(dateString.Substring(0, 4), CultureInfo.InvariantCulture),
Convert.ToInt16(dateString.Substring(4, 2), CultureInfo.InvariantCulture),
Convert.ToInt16(dateString.Substring(6, 2), CultureInfo.InvariantCulture),
Convert.ToInt16(dateString.Substring(8, 2), CultureInfo.InvariantCulture),
0, 0, 0);
}
else if (dateString.Length == 12)
{
date = new DateTime(Convert.ToInt16(dateString.Substring(0, 4), CultureInfo.InvariantCulture),
Convert.ToInt16(dateString.Substring(4, 2), CultureInfo.InvariantCulture),
Convert.ToInt16(dateString.Substring(6, 2), CultureInfo.InvariantCulture),
Convert.ToInt16(dateString.Substring(8, 2), CultureInfo.InvariantCulture),
Convert.ToInt16(dateString.Substring(10, 2), CultureInfo.InvariantCulture),
0, 0);
}
else if (dateString.Length == 14)
{
date = new DateTime(Convert.ToInt16(dateString.Substring(0, 4), CultureInfo.InvariantCulture),
Convert.ToInt16(dateString.Substring(4, 2), CultureInfo.InvariantCulture),
Convert.ToInt16(dateString.Substring(6, 2), CultureInfo.InvariantCulture),
Convert.ToInt16(dateString.Substring(8, 2), CultureInfo.InvariantCulture),
Convert.ToInt16(dateString.Substring(10, 2), CultureInfo.InvariantCulture),
Convert.ToInt16(dateString.Substring(12, 2), CultureInfo.InvariantCulture),
0);
}
else if (dateString.Length == 17)
{
date = new DateTime(Convert.ToInt16(dateString.Substring(0, 4), CultureInfo.InvariantCulture),
Convert.ToInt16(dateString.Substring(4, 2), CultureInfo.InvariantCulture),
Convert.ToInt16(dateString.Substring(6, 2), CultureInfo.InvariantCulture),
Convert.ToInt16(dateString.Substring(8, 2), CultureInfo.InvariantCulture),
Convert.ToInt16(dateString.Substring(10, 2), CultureInfo.InvariantCulture),
Convert.ToInt16(dateString.Substring(12, 2), CultureInfo.InvariantCulture),
Convert.ToInt16(dateString.Substring(14, 3), CultureInfo.InvariantCulture));
}
else
{
throw new FormatException("Input is not valid date string: " + dateString);
}
return date;
}
/// <summary>
/// Limit a date's resolution. For example, the date <c>2004-09-21 13:50:11</c>
/// will be changed to <c>2004-09-01 00:00:00</c> when using
/// <see cref="Resolution.MONTH"/>.
/// </summary>
/// <param name="date"> the date to be rounded </param>
/// <param name="resolution"> The desired resolution of the date to be returned </param>
/// <returns> the date with all values more precise than <paramref name="resolution"/>
/// set to 0 or 1 </returns>
public static DateTime Round(DateTime date, Resolution resolution)
{
return new DateTime(Round(date.Ticks / TimeSpan.TicksPerMillisecond, resolution));
}
/// <summary>
/// Limit a date's resolution. For example, the date <c>1095767411000</c>
/// (which represents 2004-09-21 13:50:11) will be changed to
/// <c>1093989600000</c> (2004-09-01 00:00:00) when using
/// <see cref="Resolution.MONTH"/>.
/// </summary>
/// <param name="time"> the time to be rounded </param>
/// <param name="resolution"> The desired resolution of the date to be returned </param>
/// <returns> the date with all values more precise than <paramref name="resolution"/>
/// set to 0 or 1, expressed as milliseconds since January 1, 1970, 00:00:00 GMT
/// (also known as the "epoch")</returns>
public static long Round(long time, Resolution resolution)
{
DateTime dt = new DateTime(time * TimeSpan.TicksPerMillisecond);
if (resolution == Resolution.YEAR)
{
dt = dt.AddMonths(1 - dt.Month);
dt = dt.AddDays(1 - dt.Day);
dt = dt.AddHours(0 - dt.Hour);
dt = dt.AddMinutes(0 - dt.Minute);
dt = dt.AddSeconds(0 - dt.Second);
dt = dt.AddMilliseconds(0 - dt.Millisecond);
}
else if (resolution == Resolution.MONTH)
{
dt = dt.AddDays(1 - dt.Day);
dt = dt.AddHours(0 - dt.Hour);
dt = dt.AddMinutes(0 - dt.Minute);
dt = dt.AddSeconds(0 - dt.Second);
dt = dt.AddMilliseconds(0 - dt.Millisecond);
}
else if (resolution == Resolution.DAY)
{
dt = dt.AddHours(0 - dt.Hour);
dt = dt.AddMinutes(0 - dt.Minute);
dt = dt.AddSeconds(0 - dt.Second);
dt = dt.AddMilliseconds(0 - dt.Millisecond);
}
else if (resolution == Resolution.HOUR)
{
dt = dt.AddMinutes(0 - dt.Minute);
dt = dt.AddSeconds(0 - dt.Second);
dt = dt.AddMilliseconds(0 - dt.Millisecond);
}
else if (resolution == Resolution.MINUTE)
{
dt = dt.AddSeconds(0 - dt.Second);
dt = dt.AddMilliseconds(0 - dt.Millisecond);
}
else if (resolution == Resolution.SECOND)
{
dt = dt.AddMilliseconds(0 - dt.Millisecond);
}
else if (resolution == Resolution.MILLISECOND)
{
// don't cut off anything
}
else
{
throw new ArgumentException("unknown resolution " + resolution);
}
return dt.Ticks;
}
/// <summary>
/// Specifies the time granularity. </summary>
public enum Resolution
{
/// <summary>
/// Limit a date's resolution to year granularity. </summary>
YEAR = 4,
/// <summary>
/// Limit a date's resolution to month granularity. </summary>
MONTH = 6,
/// <summary>
/// Limit a date's resolution to day granularity. </summary>
DAY = 8,
/// <summary>
/// Limit a date's resolution to hour granularity. </summary>
HOUR = 10,
/// <summary>
/// Limit a date's resolution to minute granularity. </summary>
MINUTE = 12,
/// <summary>
/// Limit a date's resolution to second granularity. </summary>
SECOND = 14,
/// <summary>
/// Limit a date's resolution to millisecond granularity. </summary>
MILLISECOND = 17
}
}
}