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) {
25 if (s.length() < 3) return -1;
26 s = s.substring(0, 3).toLowerCase();
27 if (s.equals("jan")) return 1;
28 if (s.equals("feb")) return 2;
29 if (s.equals("mar")) return 3;
30 if (s.equals("apr")) return 4;
31 if (s.equals("may")) return 5;
32 if (s.equals("jun")) return 6;
33 if (s.equals("jul")) return 7;
34 if (s.equals("aug")) return 8;
35 if (s.equals("sep")) return 9;
36 if (s.equals("oct")) return 10;
37 if (s.equals("nov")) return 11;
38 if (s.equals("dec")) return 12;
42 public static String[] tokenize(String s) {
43 Vec components = new Vec();
45 for(int i=0; i<s.length(); i++) {
47 if (tok.length() > 0 && charClass(c) != charClass(tok.charAt(tok.length()-1))) {
53 if (charClass(c) == CHARCLASS_WS) continue;
58 String[] ret = new String[components.size()];
59 components.toArray(ret);
63 public static Date parseDate(String s) {
64 if (s==null) return null;
67 } catch (Exception e) {
68 Log.error(RobustDateParser.class, e);
72 public static Date parseDate_(String s) {
73 String[] toks = tokenize(s);
74 int[] cclass = new int[toks.length];
75 for(int i=0; i<toks.length; i++)
76 cclass[i] = charClass(toks[i].charAt(0));
85 for(int i=0; i<toks.length; i++) {
86 if (cclass[i]==CHARCLASS_ALPHA) {
87 int tempmonth = parseMonth(toks[i]);
88 if (tempmonth != -1) {
90 if (i<toks.length-1 && cclass[i+1]==CHARCLASS_NUM && toks[i+1].length()<=2)
91 day = Integer.parseInt(toks[i+1]);
92 else if (i>0 && cclass[i-1]==CHARCLASS_NUM && toks[i-1].length()<=2)
93 day = Integer.parseInt(toks[i-1]);
94 } else if (tz==null && toks[i].length()==3 && toks[i].toUpperCase().equals(toks[i])) {
95 tz = TimeZone.getTimeZone(toks[i]);
98 if (cclass[i]==CHARCLASS_NUM) {
99 if (toks[i].length()==4) {
100 int y = Integer.parseInt(toks[i]);
101 if (y > 1960 && y < 2100)
102 year = Integer.parseInt(toks[i]);
103 else if (i>0 && (toks[i-1].equals("+") || toks[i-1].equals("-"))) {
104 String st = (toks[i-1]+toks[i]).trim();
105 while (st.length() > 0 && st.charAt(0)=='+') st = st.substring(1);
106 int ofs = Integer.parseInt(st);
108 tz = new SimpleTimeZone((ofs / 100) * 60 * 60 * 1000, (toks[i-1]+toks[i]));
110 } else if (i<toks.length-1 && toks[i+1].equals(":")) {
111 if (hour == -1) hour = Integer.parseInt(toks[i]);
112 else if (min == -1) min = Integer.parseInt(toks[i]);
113 } else if (i>0 && toks[i-1].equals(":")) {
114 if (sec == -1) sec = Integer.parseInt(toks[i]);
119 GregorianCalendar gc = new GregorianCalendar();
120 if (tz != null) gc.setTimeZone(tz);
121 gc.set(year, month-1, day, hour, min, sec);
122 Date d = gc.getTime();
125 StringBuffer sb = new StringBuffer();
126 sb.append("components: ");
128 sb.append("\""+t+"\" ");
129 Log.warn("RobustDateParser",
130 sb.toString() + "\n" +
131 "components: " + year+":"+month+":"+day+":"+hour+":"+min+":"+sec + "\n" +