001package org.nuxeo.ecm.platform.suggestbox.utils; 002 003import java.util.Calendar; 004import java.util.regex.Matcher; 005import java.util.regex.Pattern; 006 007import org.joda.time.Chronology; 008import org.joda.time.DateTime; 009import org.joda.time.IllegalFieldValueException; 010import org.joda.time.chrono.GregorianChronology; 011 012public class DateMatcher { 013 014 private static final Pattern YEAR_ONLY_MATCHER = Pattern.compile("^\\d{4}$"); 015 016 private static final Pattern MONTH_DIGIT_ONLY_MATCHER = Pattern.compile("^\\d{2}$"); 017 018 private static final Pattern YEAR_MONTHS_MATCHER = Pattern.compile("^\\d{4}[_ -:]\\d{2}$"); 019 020 private static final Pattern MONTHS_YEAR_MATCHER = Pattern.compile("^\\d{2}[_ -:]\\d{4}$"); 021 022 private static final Pattern MONTHS_DAY_YEAR_MATCHER = Pattern.compile("^\\d{2}[_ -:]\\d{2,}[_ -:]\\d{4}$"); 023 024 private static final Pattern YEAR_MONTHS_DAY_MATCHER = Pattern.compile("^\\d{4}[_ -:]\\d{2,}[_ -:]\\d{2}$"); 025 026 private boolean withYears = false; 027 028 private boolean withMonth = false; 029 030 private boolean withDay = false; 031 032 private final Calendar dateSuggestion; 033 034 private DateMatcher(boolean withYears, boolean withMonth, boolean withDay, Calendar dateSuggestion) { 035 this.withYears = withYears; 036 this.withMonth = withMonth; 037 this.withDay = withDay; 038 this.dateSuggestion = dateSuggestion; 039 } 040 041 public boolean isWithYears() { 042 return withYears; 043 } 044 045 public void setWithYears(boolean withYears) { 046 this.withYears = withYears; 047 } 048 049 public boolean isWithMonth() { 050 return withMonth; 051 } 052 053 public void setWithMonth(boolean withMonth) { 054 this.withMonth = withMonth; 055 } 056 057 public boolean isWitDay() { 058 return withDay; 059 } 060 061 public void setWitDay(boolean witDay) { 062 withDay = witDay; 063 } 064 065 public Calendar getDateSuggestion() { 066 return dateSuggestion; 067 } 068 069 public boolean hasMatch() { 070 return getDateSuggestion() != null; 071 } 072 073 public static Matcher parsingDate(Pattern pattern, String input) { 074 return pattern.matcher(input.trim()); 075 } 076 077 public static DateMatcher fromInput(String input) { 078 try { 079 return doFromInput(input); 080 } catch (NumberFormatException e) { 081 return new DateMatcher(false, false, false, null); 082 } 083 } 084 085 public static DateMatcher doFromInput(String input) { 086 Matcher matcher = parsingDate(YEAR_ONLY_MATCHER, input); 087 088 if (matcher.find()) { 089 return new DateMatcher(true, false, false, dateToInstance(Integer.parseInt(matcher.group()), 1, 1)); 090 } 091 matcher = parsingDate(MONTH_DIGIT_ONLY_MATCHER, input); 092 if (matcher.find()) { 093 int month = Integer.parseInt(matcher.group()); 094 if (month > 12 || month < 1) { 095 return new DateMatcher(false, true, false, null); 096 } 097 return new DateMatcher(false, true, false, dateToInstance(Calendar.getInstance().get(Calendar.YEAR), month, 098 1)); 099 } 100 matcher = parsingDate(YEAR_MONTHS_MATCHER, input); 101 if (matcher.find()) { 102 int month = Integer.parseInt(matcher.group().substring(5)); 103 if (month > 12 || month < 1) { 104 return new DateMatcher(true, true, false, null); 105 } 106 int year = Integer.parseInt(matcher.group().substring(0, 4)); 107 108 return new DateMatcher(true, true, false, dateToInstance(year, month, 1)); 109 } 110 matcher = parsingDate(MONTHS_YEAR_MATCHER, input); 111 if (matcher.find()) { 112 int month = Integer.parseInt(matcher.group().substring(0, 2)); 113 if (month > 12 || month < 1) { 114 return new DateMatcher(true, true, false, null); 115 } 116 int year = Integer.parseInt(matcher.group().substring(3)); 117 118 return new DateMatcher(true, true, false, dateToInstance(year, month, 1)); 119 120 } 121 matcher = parsingDate(MONTHS_DAY_YEAR_MATCHER, input); 122 if (matcher.find()) { 123 int first = Integer.parseInt(matcher.group().substring(0, 2)); 124 int second = Integer.parseInt(matcher.group().substring(3, 5)); 125 int year = Integer.parseInt(matcher.group().substring(6)); 126 int control = first + second; 127 if (control < 2 || control > 12 + 31 || first < 1 || second < 1) { 128 return new DateMatcher(true, true, true, null); 129 } else if (control < 12 + 12 + 1) { 130 return new DateMatcher(true, true, true, dateToInstance(year, first, second)); 131 } 132 int month = first; 133 int day = second; 134 if (first > second) { 135 month = second; 136 day = first; 137 } 138 Calendar dateToInstance = dateToInstance(year, month, day); 139 return new DateMatcher(true, true, true, dateToInstance); 140 } 141 matcher = parsingDate(YEAR_MONTHS_DAY_MATCHER, input); 142 if (matcher.find()) { 143 int year = Integer.parseInt(matcher.group().substring(0, 4)); 144 int first = Integer.parseInt(matcher.group().substring(5, 7)); 145 int second = Integer.parseInt(matcher.group().substring(8)); 146 int control = first + second; 147 if (control < 2 || control > 12 + 31 || first < 1 || second < 1) { 148 return new DateMatcher(true, true, true, null); 149 } else if (control < 12 + 12 + 1) { 150 return new DateMatcher(true, true, true, dateToInstance(year, first, second)); 151 } 152 int month = first; 153 int day = second; 154 if (first > second) { 155 month = second; 156 day = first; 157 } 158 Calendar dateToInstance = dateToInstance(year, month, day); 159 return new DateMatcher(true, true, true, dateToInstance); 160 } 161 162 return new DateMatcher(false, false, false, null); 163 } 164 165 protected static Calendar dateToInstance(int year, int month, int day) { 166 try { 167 Chronology chrono = GregorianChronology.getInstance(); 168 DateTime dt = new DateTime(year, month, day, 12, 0, 0, 0, chrono); 169 return dt.toGregorianCalendar(); 170 } catch (IllegalArgumentException e) { 171 return null; 172 } 173 } 174 175}