View Javadoc

1   /*
2    * Copyright (c) 2004-2007 Creative Sphere Limited.
3    * All rights reserved. This program and the accompanying materials
4    * are made available under the terms of the Eclipse Public License v1.0
5    * which accompanies this distribution, and is available at
6    * http://www.eclipse.org/legal/epl-v10.html
7    *
8    * Contributors:
9    *
10   *   Creative Sphere - initial API and implementation
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   * Class that represents RFC's date
24   *
25   * @author Daniel Sendula
26   */
27  public class RFCDate implements Serializable {
28  
29      /** Date format */
30      public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z");
31  
32      /** Date string */
33      protected transient String dateString;
34  
35      /** Day */
36      protected int day;
37  
38      /** Month */
39      protected int month;
40  
41      /** Year */
42      protected int year;
43  
44      /** Hour */
45      protected int hour;
46  
47      /** Minute\*/
48      protected int minute;
49  
50      /** Second */
51      protected int second;
52  
53      /** Timezone */
54      protected int timezone;
55  
56      /** Timezone Id */
57      protected String timezoneId;
58  
59      /** Is valid date or not */
60      protected boolean valid = false;
61  
62      protected transient int p;
63      protected transient int l;
64  
65      /**
66       * Constructor
67       * @param s date
68       */
69      public RFCDate(String s) {
70          this.dateString = s;
71          p = 0;
72          l = s.length();
73          valid = parse();
74      }
75  
76      /**
77       * Returns is date valid
78       * @return is date valid
79       */
80      public boolean isValid() {
81          return valid;
82      }
83  
84      /**
85       * Trims date string
86       * @return trims date string
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      * Parses day of week
112      * @return <code>true</code>  if valid
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      * Checks next character is given character
129      * @param ch character to be checked with
130      * @return <code>true</code> if next character is given character
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      * Returns digit (oc next character) or -1
144      * @return digit (oc next character) or -1
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      * Parses day
159      * @return <code>true</code> if valid
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      * Parses month
175      * @return <code>true</code> if valid
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      * Parses year
235      * @return <code>true</code> if valid
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      * Parses hour
271      * @return <code>true</code> if valid
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      * Parses minute
288      * @return <code>true</code> if valid
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      * Parses second
305      * @return <code>true</code> if valid
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      * Parses timezone
322      * @return <code>true</code> if valid
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      * Parses date
386      * @return <code>true</code> if valid
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      * Returns date
441      * @return date
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         //calendar.set(Calendar.ZONE_OFFSET, timezone);
449         return calendar.getTime();
450     }
451 
452     /**
453      * Returns calendar
454      * @return calendar
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      * Validates given date string
466      * @param s date string
467      * @return <code>true</code> if valid
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         //test("Mon, 6 Jun 2005 10:24:01 +0000");
479         //test("5 Jun 2005 10:24:01 +0200");
480         //test("25 Jun 05 10:24:01 +0930");
481         //test("25 Jun 2005 10:24 -1000");
482         //test("25 Jun 05 10:24:01 +0300");
483         //test("Sat, 25 Jun 2005 10:24 +0200");
484         //test("Sat,  25  Jun  2005  10:24:01  +0100");
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 }