~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to external/ngit/NGit/NGit.Util/GitDateParser.cs

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
This code is derived from jgit (http://eclipse.org/jgit).
 
3
Copyright owners are documented in jgit's IP log.
 
4
 
 
5
This program and the accompanying materials are made available
 
6
under the terms of the Eclipse Distribution License v1.0 which
 
7
accompanies this distribution, is reproduced below, and is
 
8
available at http://www.eclipse.org/org/documents/edl-v10.php
 
9
 
 
10
All rights reserved.
 
11
 
 
12
Redistribution and use in source and binary forms, with or
 
13
without modification, are permitted provided that the following
 
14
conditions are met:
 
15
 
 
16
- Redistributions of source code must retain the above copyright
 
17
  notice, this list of conditions and the following disclaimer.
 
18
 
 
19
- Redistributions in binary form must reproduce the above
 
20
  copyright notice, this list of conditions and the following
 
21
  disclaimer in the documentation and/or other materials provided
 
22
  with the distribution.
 
23
 
 
24
- Neither the name of the Eclipse Foundation, Inc. nor the
 
25
  names of its contributors may be used to endorse or promote
 
26
  products derived from this software without specific prior
 
27
  written permission.
 
28
 
 
29
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 
30
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 
31
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 
32
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
33
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 
34
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 
35
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 
36
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 
37
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 
38
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 
39
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 
40
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 
41
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
42
*/
 
43
 
 
44
using System;
 
45
using System.Collections.Generic;
 
46
using System.Text;
 
47
using NGit.Internal;
 
48
using NGit.Util;
 
49
using Sharpen;
 
50
using System.Threading;
 
51
using System.Globalization;
 
52
 
 
53
namespace NGit.Util
 
54
{
 
55
        /// <summary>
 
56
        /// Parses strings with time and date specifications into
 
57
        /// <see cref="System.DateTime">System.DateTime</see>
 
58
        /// .
 
59
        /// When git needs to parse strings specified by the user this parser can be
 
60
        /// used. One example is the parsing of the config parameter gc.pruneexpire. The
 
61
        /// parser can handle only subset of what native gits approxidate parser
 
62
        /// understands.
 
63
        /// </summary>
 
64
        public class GitDateParser
 
65
        {
 
66
                /// <summary>The Date representing never.</summary>
 
67
                /// <remarks>
 
68
                /// The Date representing never. Though this is a concrete value, most
 
69
                /// callers are adviced to avoid depending on the actual value.
 
70
                /// </remarks>
 
71
                public static readonly DateTime NEVER = Sharpen.Extensions.CreateDate(long.MaxValue
 
72
                        );
 
73
 
 
74
                private sealed class _ThreadLocal_74 : ThreadLocal<IDictionary<GitDateParser.ParseableSimpleDateFormat
 
75
                        , SimpleDateFormat>>
 
76
                {
 
77
                        public _ThreadLocal_74()
 
78
                                : base (() => new Dictionary<GitDateParser.ParseableSimpleDateFormat, SimpleDateFormat>())
 
79
                        {
 
80
                        }
 
81
                }
 
82
 
 
83
                private static ThreadLocal<IDictionary<GitDateParser.ParseableSimpleDateFormat, SimpleDateFormat
 
84
                        >> formatCache = new _ThreadLocal_74();
 
85
 
 
86
                // Gets an instance of a SimpleDateFormat. If there is not already an
 
87
                // appropriate instance in the (ThreadLocal) cache the create one and put in
 
88
                // into the cache
 
89
                private static SimpleDateFormat GetDateFormat(GitDateParser.ParseableSimpleDateFormat
 
90
                         f)
 
91
                {
 
92
                        IDictionary<GitDateParser.ParseableSimpleDateFormat, SimpleDateFormat> map = formatCache
 
93
                                .Value;
 
94
                        SimpleDateFormat dateFormat = map.Get(f);
 
95
                        if (dateFormat != null)
 
96
                        {
 
97
                                return dateFormat;
 
98
                        }
 
99
                        SimpleDateFormat df = SystemReader.GetInstance().GetSimpleDateFormat(f.formatStr);
 
100
                        map.Put(f, df);
 
101
                        return df;
 
102
                }
 
103
 
 
104
                public class ParseableSimpleDateFormat
 
105
                {
 
106
                        public static GitDateParser.ParseableSimpleDateFormat ISO = new GitDateParser.ParseableSimpleDateFormat
 
107
                                ("yyyy-MM-dd HH:mm:ss Z");
 
108
 
 
109
                        public static GitDateParser.ParseableSimpleDateFormat RFC = new GitDateParser.ParseableSimpleDateFormat
 
110
                                ("EEE, dd MMM yyyy HH:mm:ss Z");
 
111
 
 
112
                        public static GitDateParser.ParseableSimpleDateFormat SHORT = new GitDateParser.ParseableSimpleDateFormat
 
113
                                ("yyyy-MM-dd");
 
114
 
 
115
                        public static GitDateParser.ParseableSimpleDateFormat SHORT_WITH_DOTS_REVERSE = new 
 
116
                                GitDateParser.ParseableSimpleDateFormat("dd.MM.yyyy");
 
117
 
 
118
                        public static GitDateParser.ParseableSimpleDateFormat SHORT_WITH_DOTS = new GitDateParser.ParseableSimpleDateFormat
 
119
                                ("yyyy.MM.dd");
 
120
 
 
121
                        public static GitDateParser.ParseableSimpleDateFormat SHORT_WITH_SLASH = new GitDateParser.ParseableSimpleDateFormat
 
122
                                ("MM/dd/yyyy");
 
123
 
 
124
                        public static GitDateParser.ParseableSimpleDateFormat DEFAULT = new GitDateParser.ParseableSimpleDateFormat
 
125
                                ("EEE MMM dd HH:mm:ss yyyy Z");
 
126
 
 
127
                        public static GitDateParser.ParseableSimpleDateFormat LOCAL = new GitDateParser.ParseableSimpleDateFormat
 
128
                                ("EEE MMM dd HH:mm:ss yyyy");
 
129
 
 
130
                        // An enum of all those formats which this parser can parse with the help of
 
131
                        // a SimpleDateFormat. There are other formats (e.g. the relative formats
 
132
                        // like "yesterday" or "1 week ago") which this parser can parse but which
 
133
                        // are not listed here because they are parsed without the help of a
 
134
                        // SimpleDateFormat.
 
135
                        //
 
136
                        //
 
137
                        //
 
138
                        //
 
139
                        //
 
140
                        //
 
141
                        //
 
142
                        public static GitDateParser.ParseableSimpleDateFormat[] Values()
 
143
                        {
 
144
                                return new GitDateParser.ParseableSimpleDateFormat[] { ISO, RFC, SHORT, SHORT_WITH_DOTS_REVERSE
 
145
                                        , SHORT_WITH_DOTS, SHORT_WITH_SLASH, DEFAULT, LOCAL };
 
146
                        }
 
147
 
 
148
                        public string formatStr;
 
149
 
 
150
                        private ParseableSimpleDateFormat(string formatStr)
 
151
                        {
 
152
                                this.formatStr = formatStr;
 
153
                        }
 
154
                }
 
155
 
 
156
                /// <summary>
 
157
                /// Parses a string into a
 
158
                /// <see cref="System.DateTime">System.DateTime</see>
 
159
                /// . Since this parser also supports
 
160
                /// relative formats (e.g. "yesterday") the caller can specify the reference
 
161
                /// date. These types of strings can be parsed:
 
162
                /// <ul>
 
163
                /// <li>"never"</li>
 
164
                /// <li>"now"</li>
 
165
                /// <li>"yesterday"</li>
 
166
                /// <li>"(x) years|months|weeks|days|hours|minutes|seconds ago"<br />
 
167
                /// Multiple specs can be combined like in "2 weeks 3 days ago". Instead of
 
168
                /// ' ' one can use '.' to seperate the words</li>
 
169
                /// <li>"yyyy-MM-dd HH:mm:ss Z" (ISO)</li>
 
170
                /// <li>"EEE, dd MMM yyyy HH:mm:ss Z" (RFC)</li>
 
171
                /// <li>"yyyy-MM-dd"</li>
 
172
                /// <li>"yyyy.MM.dd"</li>
 
173
                /// <li>"MM/dd/yyyy",</li>
 
174
                /// <li>"dd.MM.yyyy"</li>
 
175
                /// <li>"EEE MMM dd HH:mm:ss yyyy Z" (DEFAULT)</li>
 
176
                /// <li>"EEE MMM dd HH:mm:ss yyyy" (LOCAL)</li>
 
177
                /// </ul>
 
178
                /// </summary>
 
179
                /// <param name="dateStr">the string to be parsed</param>
 
180
                /// <param name="now">
 
181
                /// the base date which is used for the calculation of relative
 
182
                /// formats. E.g. if baseDate is "25.8.2012" then parsing of the
 
183
                /// string "1 week ago" would result in a date corresponding to
 
184
                /// "18.8.2012". This is used when a JGit command calls this
 
185
                /// parser often but wants a consistent starting point for calls.<br />
 
186
                /// If set to <code>null</code> then the current time will be used
 
187
                /// instead.
 
188
                /// </param>
 
189
                /// <returns>
 
190
                /// the parsed
 
191
                /// <see cref="System.DateTime">System.DateTime</see>
 
192
                /// </returns>
 
193
                /// <exception cref="Sharpen.ParseException">if the given dateStr was not recognized</exception>
 
194
                public static DateTime Parse(string dateStr, JavaCalendar now)
 
195
                {
 
196
                        dateStr = dateStr.Trim();
 
197
                        DateTime? ret;
 
198
                        if (Sharpen.Runtime.EqualsIgnoreCase("never", dateStr))
 
199
                        {
 
200
                                return NEVER;
 
201
                        }
 
202
                        ret = Parse_relative(dateStr, now);
 
203
                        if (ret != null)
 
204
                        {
 
205
                                return ret.Value;
 
206
                        }
 
207
                        foreach (GitDateParser.ParseableSimpleDateFormat f in GitDateParser.ParseableSimpleDateFormat
 
208
                                .Values())
 
209
                        {
 
210
                                try
 
211
                                {
 
212
                                        return Parse_simple(dateStr, f);
 
213
                                }
 
214
                                catch (ParseException)
 
215
                                {
 
216
                                }
 
217
                        }
 
218
                        // simply proceed with the next parser
 
219
                        GitDateParser.ParseableSimpleDateFormat[] values = GitDateParser.ParseableSimpleDateFormat
 
220
                                .Values();
 
221
                        StringBuilder allFormats = new StringBuilder("\"").Append(values[0].formatStr);
 
222
                        for (int i = 1; i < values.Length; i++)
 
223
                        {
 
224
                                allFormats.Append("\", \"").Append(values[i].formatStr);
 
225
                        }
 
226
                        allFormats.Append("\"");
 
227
                        throw new ParseException(MessageFormat.Format(JGitText.Get().cannotParseDate, dateStr
 
228
                                , allFormats.ToString()), 0);
 
229
                }
 
230
 
 
231
                // tries to parse a string with the formats supported by SimpleDateFormat
 
232
                /// <exception cref="Sharpen.ParseException"></exception>
 
233
                private static DateTime Parse_simple(string dateStr, GitDateParser.ParseableSimpleDateFormat
 
234
                         f)
 
235
                {
 
236
                        SimpleDateFormat dateFormat = GetDateFormat(f);
 
237
                        dateFormat.SetLenient(false);
 
238
                        return dateFormat.Parse(dateStr);
 
239
                }
 
240
 
 
241
                // tries to parse a string with a relative time specification
 
242
                private static DateTime? Parse_relative(string dateStr, JavaCalendar now)
 
243
                {
 
244
                        JavaCalendar cal;
 
245
                        SystemReader sysRead = SystemReader.GetInstance();
 
246
                        // check for the static words "yesterday" or "now"
 
247
                        if ("now".Equals(dateStr))
 
248
                        {
 
249
                                return ((now == null) ? Sharpen.Extensions.CreateDate(sysRead.GetCurrentTime()) : 
 
250
                                        now.GetTime());
 
251
                        }
 
252
                        if (now == null)
 
253
                        {
 
254
                                cal = new JavaGregorianCalendar(sysRead.GetTimeZone(), sysRead.GetLocale());
 
255
                                cal.SetTimeInMillis(sysRead.GetCurrentTime());
 
256
                        }
 
257
                        else
 
258
                        {
 
259
                                cal = (JavaCalendar)now.Clone();
 
260
                        }
 
261
                        if ("yesterday".Equals(dateStr))
 
262
                        {
 
263
                                cal.Add(JavaCalendar.DATE, -1);
 
264
                                cal.Set(JavaCalendar.HOUR_OF_DAY, 0);
 
265
                                cal.Set(JavaCalendar.MINUTE, 0);
 
266
                                cal.Set(JavaCalendar.SECOND, 0);
 
267
                                cal.Set(JavaCalendar.MILLISECOND, 0);
 
268
                                cal.Set(JavaCalendar.MILLISECOND, 0);
 
269
                                return cal.GetTime();
 
270
                        }
 
271
                        // parse constructs like "3 days ago", "5.week.2.day.ago"
 
272
                        string[] parts = dateStr.Split("\\.| ");
 
273
                        int partsLength = parts.Length;
 
274
                        // check we have an odd number of parts (at least 3) and that the last
 
275
                        // part is "ago"
 
276
                        if (partsLength < 3 || (partsLength & 1) == 0 || !"ago".Equals(parts[parts.Length
 
277
                                 - 1]))
 
278
                        {
 
279
                                return null;
 
280
                        }
 
281
                        int number;
 
282
                        for (int i = 0; i < parts.Length - 2; i += 2)
 
283
                        {
 
284
                                try
 
285
                                {
 
286
                                        number = System.Convert.ToInt32(parts[i]);
 
287
                                }
 
288
                                catch (FormatException)
 
289
                                {
 
290
                                        return null;
 
291
                                }
 
292
                                if ("year".Equals(parts[i + 1]) || "years".Equals(parts[i + 1]))
 
293
                                {
 
294
                                        cal.Add(JavaCalendar.YEAR, -number);
 
295
                                }
 
296
                                else
 
297
                                {
 
298
                                        if ("month".Equals(parts[i + 1]) || "months".Equals(parts[i + 1]))
 
299
                                        {
 
300
                                                cal.Add(JavaCalendar.MONTH, -number);
 
301
                                        }
 
302
                                        else
 
303
                                        {
 
304
                                                if ("week".Equals(parts[i + 1]) || "weeks".Equals(parts[i + 1]))
 
305
                                                {
 
306
                                                        cal.Add(JavaCalendar.WEEK_OF_YEAR, -number);
 
307
                                                }
 
308
                                                else
 
309
                                                {
 
310
                                                        if ("day".Equals(parts[i + 1]) || "days".Equals(parts[i + 1]))
 
311
                                                        {
 
312
                                                                cal.Add(JavaCalendar.DATE, -number);
 
313
                                                        }
 
314
                                                        else
 
315
                                                        {
 
316
                                                                if ("hour".Equals(parts[i + 1]) || "hours".Equals(parts[i + 1]))
 
317
                                                                {
 
318
                                                                        cal.Add(JavaCalendar.HOUR_OF_DAY, -number);
 
319
                                                                }
 
320
                                                                else
 
321
                                                                {
 
322
                                                                        if ("minute".Equals(parts[i + 1]) || "minutes".Equals(parts[i + 1]))
 
323
                                                                        {
 
324
                                                                                cal.Add(JavaCalendar.MINUTE, -number);
 
325
                                                                        }
 
326
                                                                        else
 
327
                                                                        {
 
328
                                                                                if ("second".Equals(parts[i + 1]) || "seconds".Equals(parts[i + 1]))
 
329
                                                                                {
 
330
                                                                                        cal.Add(JavaCalendar.SECOND, -number);
 
331
                                                                                }
 
332
                                                                                else
 
333
                                                                                {
 
334
                                                                                        return null;
 
335
                                                                                }
 
336
                                                                        }
 
337
                                                                }
 
338
                                                        }
 
339
                                                }
 
340
                                        }
 
341
                                }
 
342
                        }
 
343
                        return cal.GetTime();
 
344
                }
 
345
        }
 
346
}