5 // FEATURE: cope with stuff like "next tuesday" or "in three hours"
7 /** prototype parser for free-form dates; mostly needs to handle RFC2822 Date field */
8 public class RobustDateParser {
10 private static final int CHARCLASS_OTHER = 0;
11 private static final int CHARCLASS_WS = 1;
12 private static final int CHARCLASS_ALPHA = 2;
13 private static final int CHARCLASS_NUM = 3;
14 private static final int CHARCLASS_SYM = 4;
16 public static int charClass(char c) {
17 if (Character.isWhitespace(c)) return CHARCLASS_WS;
18 if (Character.isLetter(c)) return CHARCLASS_ALPHA;
19 if (Character.isDigit(c)) return CHARCLASS_NUM;
23 public static int parseMonth(String s) {
24 s = s.trim().substring(0, 3).toLowerCase();
25 if (s.equals("jan")) return 1;
26 if (s.equals("feb")) return 2;
27 if (s.equals("mar")) return 3;
28 if (s.equals("apr")) return 4;
29 if (s.equals("may")) return 5;
30 if (s.equals("jun")) return 6;
31 if (s.equals("jul")) return 7;
32 if (s.equals("aug")) return 8;
33 if (s.equals("sep")) return 9;
34 if (s.equals("oct")) return 10;
35 if (s.equals("nov")) return 11;
36 if (s.equals("dec")) return 12;
40 public static String[] tokenize(String s) {
41 Vec components = new Vec();
43 for(int i=0; i<s.length(); i++) {
45 if (tok.length() > 0 && charClass(c) != charClass(tok.charAt(tok.length()-1))) {
51 if (charClass(c) == CHARCLASS_WS) continue;
56 String[] ret = new String[components.size()];
57 components.toArray(ret);
61 public static Date parseDate(String s) {
62 if (s==null) return null;
65 } catch (Exception e) {
66 Log.error(RobustDateParser.class, e);
70 public static Date parseDate_(String s) {
71 String[] toks = tokenize(s);
72 int[] cclass = new int[toks.length];
73 for(int i=0; i<toks.length; i++)
74 cclass[i] = charClass(toks[i].charAt(0));
83 for(int i=0; i<toks.length; i++) {
84 if (cclass[i]==CHARCLASS_ALPHA) {
85 int tempmonth = parseMonth(toks[i]);
86 if (tempmonth != -1) {
88 if (i<toks.length-1 && cclass[i+1]==CHARCLASS_NUM && toks[i+1].length()<=2)
89 day = Integer.parseInt(toks[i+1]);
90 else if (i>0 && cclass[i-1]==CHARCLASS_NUM && toks[i-1].length()<=2)
91 day = Integer.parseInt(toks[i-1]);
92 } else if (tz==null && toks[i].length()==3 && toks[i].toUpperCase().equals(toks[i])) {
93 tz = TimeZone.getTimeZone(toks[i]);
96 if (cclass[i]==CHARCLASS_NUM) {
97 if (toks[i].length()==4) {
98 int y = Integer.parseInt(toks[i]);
99 if (y > 1960 && y < 2100)
100 year = Integer.parseInt(toks[i]);
101 else if (i>0 && (toks[i-1].equals("+") || toks[i-1].equals("-"))) {
102 String st = (toks[i-1]+toks[i]).trim();
103 while (st.length() > 0 && st.charAt(0)=='+') st = st.substring(1);
104 int ofs = Integer.parseInt(st);
106 tz = new SimpleTimeZone((ofs / 100) * 60 * 60 * 1000, (toks[i-1]+toks[i]));
108 } else if (i<toks.length-1 && toks[i+1].equals(":")) {
109 if (hour == -1) hour = Integer.parseInt(toks[i]);
110 else if (min == -1) min = Integer.parseInt(toks[i]);
111 } else if (i>0 && toks[i-1].equals(":")) {
112 if (sec == -1) sec = Integer.parseInt(toks[i]);
117 GregorianCalendar gc = new GregorianCalendar();
118 if (tz != null) gc.setTimeZone(tz);
119 gc.set(year, month-1, day, hour, min, sec);
120 Date d = gc.getTime();
123 StringBuffer sb = new StringBuffer();
124 sb.append("components: ");
126 sb.append("\""+t+"\" ");
127 Log.warn("RobustDateParser",
128 sb.toString() + "\n" +
129 "components: " + year+":"+month+":"+day+":"+hour+":"+min+":"+sec + "\n" +