001/* 002 * (C) Copyright 2011 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Olivier Grisel 018 */ 019package org.nuxeo.ecm.platform.suggestbox.utils; 020 021import java.util.Calendar; 022import java.util.regex.Matcher; 023import java.util.regex.Pattern; 024 025import org.joda.time.Chronology; 026import org.joda.time.DateTime; 027import org.joda.time.IllegalFieldValueException; 028import org.joda.time.chrono.GregorianChronology; 029 030public class DateMatcher { 031 032 private static final Pattern YEAR_ONLY_MATCHER = Pattern.compile("^\\d{4}$"); 033 034 private static final Pattern MONTH_DIGIT_ONLY_MATCHER = Pattern.compile("^\\d{2}$"); 035 036 private static final Pattern YEAR_MONTHS_MATCHER = Pattern.compile("^\\d{4}[_ -:]\\d{2}$"); 037 038 private static final Pattern MONTHS_YEAR_MATCHER = Pattern.compile("^\\d{2}[_ -:]\\d{4}$"); 039 040 private static final Pattern MONTHS_DAY_YEAR_MATCHER = Pattern.compile("^\\d{2}[_ -:]\\d{2,}[_ -:]\\d{4}$"); 041 042 private static final Pattern YEAR_MONTHS_DAY_MATCHER = Pattern.compile("^\\d{4}[_ -:]\\d{2,}[_ -:]\\d{2}$"); 043 044 private boolean withYears = false; 045 046 private boolean withMonth = false; 047 048 private boolean withDay = false; 049 050 private final Calendar dateSuggestion; 051 052 private DateMatcher(boolean withYears, boolean withMonth, boolean withDay, Calendar dateSuggestion) { 053 this.withYears = withYears; 054 this.withMonth = withMonth; 055 this.withDay = withDay; 056 this.dateSuggestion = dateSuggestion; 057 } 058 059 public boolean isWithYears() { 060 return withYears; 061 } 062 063 public void setWithYears(boolean withYears) { 064 this.withYears = withYears; 065 } 066 067 public boolean isWithMonth() { 068 return withMonth; 069 } 070 071 public void setWithMonth(boolean withMonth) { 072 this.withMonth = withMonth; 073 } 074 075 public boolean isWitDay() { 076 return withDay; 077 } 078 079 public void setWitDay(boolean witDay) { 080 withDay = witDay; 081 } 082 083 public Calendar getDateSuggestion() { 084 return dateSuggestion; 085 } 086 087 public boolean hasMatch() { 088 return getDateSuggestion() != null; 089 } 090 091 public static Matcher parsingDate(Pattern pattern, String input) { 092 return pattern.matcher(input.trim()); 093 } 094 095 public static DateMatcher fromInput(String input) { 096 try { 097 return doFromInput(input); 098 } catch (NumberFormatException e) { 099 return new DateMatcher(false, false, false, null); 100 } 101 } 102 103 public static DateMatcher doFromInput(String input) { 104 Matcher matcher = parsingDate(YEAR_ONLY_MATCHER, input); 105 106 if (matcher.find()) { 107 return new DateMatcher(true, false, false, dateToInstance(Integer.parseInt(matcher.group()), 1, 1)); 108 } 109 matcher = parsingDate(MONTH_DIGIT_ONLY_MATCHER, input); 110 if (matcher.find()) { 111 int month = Integer.parseInt(matcher.group()); 112 if (month > 12 || month < 1) { 113 return new DateMatcher(false, true, false, null); 114 } 115 return new DateMatcher(false, true, false, dateToInstance(Calendar.getInstance().get(Calendar.YEAR), month, 116 1)); 117 } 118 matcher = parsingDate(YEAR_MONTHS_MATCHER, input); 119 if (matcher.find()) { 120 int month = Integer.parseInt(matcher.group().substring(5)); 121 if (month > 12 || month < 1) { 122 return new DateMatcher(true, true, false, null); 123 } 124 int year = Integer.parseInt(matcher.group().substring(0, 4)); 125 126 return new DateMatcher(true, true, false, dateToInstance(year, month, 1)); 127 } 128 matcher = parsingDate(MONTHS_YEAR_MATCHER, input); 129 if (matcher.find()) { 130 int month = Integer.parseInt(matcher.group().substring(0, 2)); 131 if (month > 12 || month < 1) { 132 return new DateMatcher(true, true, false, null); 133 } 134 int year = Integer.parseInt(matcher.group().substring(3)); 135 136 return new DateMatcher(true, true, false, dateToInstance(year, month, 1)); 137 138 } 139 matcher = parsingDate(MONTHS_DAY_YEAR_MATCHER, input); 140 if (matcher.find()) { 141 int first = Integer.parseInt(matcher.group().substring(0, 2)); 142 int second = Integer.parseInt(matcher.group().substring(3, 5)); 143 int year = Integer.parseInt(matcher.group().substring(6)); 144 int control = first + second; 145 if (control < 2 || control > 12 + 31 || first < 1 || second < 1) { 146 return new DateMatcher(true, true, true, null); 147 } else if (control < 12 + 12 + 1) { 148 return new DateMatcher(true, true, true, dateToInstance(year, first, second)); 149 } 150 int month = first; 151 int day = second; 152 if (first > second) { 153 month = second; 154 day = first; 155 } 156 Calendar dateToInstance = dateToInstance(year, month, day); 157 return new DateMatcher(true, true, true, dateToInstance); 158 } 159 matcher = parsingDate(YEAR_MONTHS_DAY_MATCHER, input); 160 if (matcher.find()) { 161 int year = Integer.parseInt(matcher.group().substring(0, 4)); 162 int first = Integer.parseInt(matcher.group().substring(5, 7)); 163 int second = Integer.parseInt(matcher.group().substring(8)); 164 int control = first + second; 165 if (control < 2 || control > 12 + 31 || first < 1 || second < 1) { 166 return new DateMatcher(true, true, true, null); 167 } else if (control < 12 + 12 + 1) { 168 return new DateMatcher(true, true, true, dateToInstance(year, first, second)); 169 } 170 int month = first; 171 int day = second; 172 if (first > second) { 173 month = second; 174 day = first; 175 } 176 Calendar dateToInstance = dateToInstance(year, month, day); 177 return new DateMatcher(true, true, true, dateToInstance); 178 } 179 180 return new DateMatcher(false, false, false, null); 181 } 182 183 protected static Calendar dateToInstance(int year, int month, int day) { 184 try { 185 Chronology chrono = GregorianChronology.getInstance(); 186 DateTime dt = new DateTime(year, month, day, 12, 0, 0, 0, chrono); 187 return dt.toGregorianCalendar(); 188 } catch (IllegalArgumentException e) { 189 return null; 190 } 191 } 192 193}