1
2
3
4
5
6
7
8
9
10
11
12
13 package org.abstracthorizon.mercury.common.util;
14
15 import java.io.Serializable;
16 import java.text.SimpleDateFormat;
17 import java.util.Calendar;
18 import java.util.Date;
19 import java.util.GregorianCalendar;
20 import java.util.SimpleTimeZone;
21
22
23
24
25
26
27 public class RFCDate implements Serializable {
28
29
30 public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z");
31
32
33 protected transient String dateString;
34
35
36 protected int day;
37
38
39 protected int month;
40
41
42 protected int year;
43
44
45 protected int hour;
46
47
48 protected int minute;
49
50
51 protected int second;
52
53
54 protected int timezone;
55
56
57 protected String timezoneId;
58
59
60 protected boolean valid = false;
61
62 protected transient int p;
63 protected transient int l;
64
65
66
67
68
69 public RFCDate(String s) {
70 this.dateString = s;
71 p = 0;
72 l = s.length();
73 valid = parse();
74 }
75
76
77
78
79
80 public boolean isValid() {
81 return valid;
82 }
83
84
85
86
87
88 protected boolean trim() {
89 if (p < l) {
90 char c = dateString.charAt(p);
91 if (Character.isWhitespace(c)) {
92 p = p + 1;
93 if (p < l) {
94 c = dateString.charAt(p);
95 while ((p < l) && Character.isWhitespace(c)) {
96 p = p + 1;
97 if (p < l) {
98 c = dateString.charAt(p);
99 }
100 }
101 }
102
103 }
104 return true;
105 } else {
106 return false;
107 }
108 }
109
110
111
112
113
114 protected boolean parseDayOfWeek() {
115 if (p+3 <= l) {
116 String d = dateString.substring(p, p+3);
117 if ("Mon".equals(d) || "Tue".equals(d) || "Wed".equals(d)
118 || "Thu".equals(d) || "Fri".equals(d)
119 || "Sat".equals(d) || "Sun".equals(d)) {
120 p = p + 3;
121 return true;
122 }
123 }
124 return false;
125 }
126
127
128
129
130
131
132 protected boolean character(char ch) {
133 if (p < l) {
134 if (dateString.charAt(p) == ch) {
135 p = p + 1;
136 return true;
137 }
138 }
139 return false;
140 }
141
142
143
144
145
146 protected int digit() {
147 if (p < l) {
148 char c = dateString.charAt(p);
149 if (Character.isDigit(c)) {
150 p = p + 1;
151 return c - '0';
152 }
153 }
154 return -1;
155 }
156
157
158
159
160
161 protected boolean parseDay() {
162 day = digit();
163 if (day < 0) {
164 return false;
165 }
166 int d = digit();
167 if (d >= 0) {
168 day = day * 10 + d;
169 }
170 return true;
171 }
172
173
174
175
176
177 protected boolean parseMonth() {
178 if (p+3 <= l) {
179 String d = dateString.substring(p, p+3);
180 if (d.equals("Jan")) {
181 month = 1;
182 p = p + 3;
183 return true;
184 } else if (d.equals("Feb")) {
185 month = 2;
186 p = p + 3;
187 return true;
188 } else if (d.equals("Mar")) {
189 month = 3;
190 p = p + 3;
191 return true;
192 } else if (d.equals("Apr")) {
193 month = 4;
194 p = p + 3;
195 return true;
196 } else if (d.equals("May")) {
197 month = 5;
198 p = p + 3;
199 return true;
200 } else if (d.equals("Jun")) {
201 month = 6;
202 p = p + 3;
203 return true;
204 } else if (d.equals("Jul")) {
205 month = 7;
206 p = p + 3;
207 return true;
208 } else if (d.equals("Aug")) {
209 month = 8;
210 p = p + 3;
211 return true;
212 } else if (d.equals("Sep")) {
213 month = 9;
214 p = p + 3;
215 return true;
216 } else if (d.equals("Oct")) {
217 month = 10;
218 p = p + 3;
219 return true;
220 } else if (d.equals("Nov")) {
221 month = 11;
222 p = p + 3;
223 return true;
224 } else if (d.equals("Dec")) {
225 month = 12;
226 p = p + 3;
227 return true;
228 }
229 }
230 return false;
231 }
232
233
234
235
236
237 protected boolean parseYear() {
238 year = digit();
239 if (year < 0) {
240 return false;
241 }
242
243 int y = digit();
244 if (y < 0) {
245 return false;
246 }
247
248 year = year * 10 + y;
249
250 y = digit();
251 if (y >= 0) {
252 year = year * 10 + y;
253 y = digit();
254 if (y < 0) {
255 return false;
256 }
257 year = year * 10 + y;
258 } else {
259 if (year < 60) {
260 year = year + 2000;
261 } else {
262 year = year + 1900;
263 }
264 }
265
266 return true;
267 }
268
269
270
271
272
273 protected boolean parseHour() {
274 hour = digit();
275 if (hour < 0) {
276 return false;
277 }
278 int h = digit();
279 if (h < 0) {
280 return false;
281 }
282 hour = hour * 10 + h;
283 return true;
284 }
285
286
287
288
289
290 protected boolean parseMinute() {
291 minute = digit();
292 if (minute < 0) {
293 return false;
294 }
295 int m = digit();
296 if (m < 0) {
297 return false;
298 }
299 minute = minute * 10 + m;
300 return true;
301 }
302
303
304
305
306
307 protected boolean parseSecond() {
308 second = digit();
309 if (second < 0) {
310 return false;
311 }
312 int ss = digit();
313 if (ss < 0) {
314 return false;
315 }
316 second = second * 10 + ss;
317 return true;
318 }
319
320
321
322
323
324 protected boolean parseTimeZone() {
325 if (p < l) {
326 boolean negative = false;
327 char c = dateString.charAt(p);
328 if (c == '+') {
329 p = p + 1;
330 } else if (c == '-') {
331 negative = true;
332 p = p + 1;
333 } else {
334 if ((p + 2 <= l) && ("UT".equals(dateString.substring(p, p + 2)))) {
335 timezoneId = "UT";
336 } else if (p + 3 <= l) {
337 String tz = dateString.substring(p, p + 3);
338 if ("GMT".equals(tz)
339 || "EST".equals(tz) || "EDT".equals(tz)
340 || "CST".equals(tz) || "CDT".equals(tz)
341 || "MST".equals(tz) || "MDT".equals(tz)
342 || "PST".equals(tz) || "PDT".equals(tz)
343 ) {
344 timezoneId = tz;
345 }
346 }
347 if (timezoneId != null) {
348 return true;
349 }
350 return false;
351 }
352 if (p + 4 <= l) {
353
354 timezone = digit();
355 if (timezone < 0) {
356 return false;
357 }
358 int t = digit();
359 if (t < 0) {
360 return false;
361 }
362 timezone = timezone * 10 + t;
363 t = digit();
364 if (t < 0) {
365 return false;
366 }
367 timezone = timezone * 10 + t;
368 t = digit();
369 if (t < 0) {
370 return false;
371 }
372 timezone = timezone * 10 + t;
373 if (negative) {
374 timezone = -timezone;
375 }
376 return true;
377 } else {
378 return false;
379 }
380 }
381 return false;
382 }
383
384
385
386
387
388 protected boolean parse() {
389 trim();
390 if (parseDayOfWeek()) {
391 if (!character(',')) {
392 return false;
393 }
394 if (!trim()) {
395 return false;
396 }
397 }
398 if (!parseDay()) {
399 return false;
400 }
401 if (!trim()) {
402 return false;
403 }
404 if (!parseMonth()) {
405 return false;
406 }
407 if (!trim()) {
408 return false;
409 }
410 if (!parseYear()) {
411 return false;
412 }
413 if (!trim()) {
414 return false;
415 }
416 if (!parseHour()) {
417 return false;
418 }
419 if (!character(':')) {
420 return false;
421 }
422 if (!parseMinute()) {
423 return false;
424 }
425 if (character(':')) {
426 if (!parseSecond()) {
427 return false;
428 }
429 }
430 if (!trim()) {
431 return false;
432 }
433 if (!parseTimeZone()) {
434 return false;
435 }
436 return true;
437 }
438
439
440
441
442
443 public Date getDate() {
444 GregorianCalendar calendar = new GregorianCalendar(year, month-1, day, hour, minute, second);
445 int rawoffset = timezone/100*60*60*1000+(timezone % 100)*60*1000;
446 SimpleTimeZone zone = new SimpleTimeZone(rawoffset, "");
447 calendar.setTimeZone(zone);
448
449 return calendar.getTime();
450 }
451
452
453
454
455
456 public Calendar getCalendar() {
457 GregorianCalendar calendar = new GregorianCalendar(year, month-1, day, hour, minute, second);
458 int rawoffset = timezone/100*60*60*1000+(timezone % 100)*60*1000;
459 SimpleTimeZone zone = new SimpleTimeZone(rawoffset, "");
460 calendar.setTimeZone(zone);
461 return calendar;
462 }
463
464
465
466
467
468
469 public static boolean validate(String s) {
470 RFCDate pd = new RFCDate(s);
471 return pd.isValid();
472 }
473
474
475
476 public static void main(String[] args) throws Exception {
477 System.out.println(validate("Fri, 2 Apr 2004 00:10:10 +0300"));
478
479
480
481
482
483
484
485 }
486
487 public static void test(String d) {
488 if (validate(d)) {
489 RFCDate date = new RFCDate(d);
490 if (d.equals(date)) {
491 System.out.println(d + " is ok");
492 } else {
493 System.out.println(d + " is different to " + date);
494 }
495 } else {
496 System.out.println(d + " is not valid date");
497 }
498 }
499 }