org.springmodules.validation.util.date.DefaultDateParser Maven / Gradle / Ivy
/*
* Copyright 2004-2005 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springmodules.validation.util.date;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.collections.Predicate;
/**
* DefaultDateParser parses many date formats to a string.
*
* The supported date formats are:
*
*
* - yyyy-MM-dd (^\\d{4}\\-\\d{2}\\-\\d{2}$)
*
- yyyyMMdd (^\\d{8}$)
*
- yyyy-MM-dd HH:mm:ss (^\\d{4}\\-\\d{2}\\-\\d{2}\\s+\\d{2}:\\d{2}:\\d{2}$)
*
- yyyyMMdd HHmmss (^\\d{8}\\s+\\d{6}$)
*
- yyyyMMdd HH:mm:ss (^\\d{8}\\s+\\d{2}:\\d{2}:\\d{2}$)
*
- yyyy-MM-dd HHmmss (^\\d{4}\\-\\d{2}\\-\\d{2}\\s+\\d{6}$)
*
- T (^T$)
*
*
* Date formats can be added using DefaultDateParser#register(String, String).
*
* These modifiers are supported:
*
*
* - T+?S (add ? milliseconds to T, T can be any valid date format with modifiers)
*
- T-?S (subtract ? milliseconds from T, idem)
*
- T+?s (add ? seconds to T, idem)
*
- T-?s (subtract ? seconds from T, idem)
*
- T+?m (add ? minutes to T, idem)
*
- T-?m (subtract ? minutes from T, idem)
*
- T+?H (add ? hours to T, idem)
*
- T-?H (subtract ? hours from T, idem)
*
- T+?d (add ? hours to T, idem)
*
- T-?d (subtract ? hours from T, idem)
*
- T+?w (add ? weeks to T, idem)
*
- T-?w (subtract ? weeks from T, idem)
*
- T+?M (add ? months to T, idem)
*
- T-?M (subtract ? months from T, idem)
*
- T+?y (add ? years to T, idem)
*
- T-?y (subtract ? years from T, idem)
*
- T<s (shift T to start of current second, idem)
*
- T>s (shift T to start of next second, idem)
*
- T<m (shift T to start of current minute, idem)
*
- T>m (shift T to start of next minute, idem)
*
- T<H (shift T to start of current hour, idem)
*
- T>H (shift T to start of next hour, idem)
*
- T<d (shift T to start of current day, idem)
*
- T>d (shift T to start of next day, idem)
*
- T<w (shift T to start of current week, idem)
*
- T>w (shift T to start of next week, idem)
*
- T<y (shift T to start of current year, idem)
*
- T>y (shift T to start of next year, idem)
*
*
* Modifiers can be added using DefaultDateParser#register(String, DateModifier).
*
* Modifiers can be combined and are parsed from left to right, for example:
*
* 2005-04-09 23:30:00>M+10d+8H
results in 2005-05-11 08:00:00
.
*
* @author Steven Devijver
* @since 25-04-2005
*/
public class DefaultDateParser implements DateParser {
private static DefaultDateParser instance = new DefaultDateParser();
private Map registrations = new HashMap();
public static DefaultDateParser getInstance() {
return instance;
}
public DefaultDateParser() {
super();
register("^\\d{8}$", "yyyyMMdd");
register("^\\d{4}\\-\\d{2}\\-\\d{2}$", "yyyy-MM-dd");
register("^\\d{4}\\-\\d{2}\\-\\d{2}\\s+\\d{2}:\\d{2}:\\d{2}$", "yyyy-MM-dd HH:mm:ss");
register("^\\d{8}\\s+\\d{6}$", "yyyyMMdd HHmmss");
register("^\\d{8}\\s+\\d{2}:\\d{2}:\\d{2}$", "yyyyMMdd HH:mm:ss");
register("^\\d{4}\\-\\d{2}\\-\\d{2}\\s+\\d{6}$", "yyyy-MM-dd HHmmss");
register("^T$", new DateModifier() {
public void modify(Calendar calendar, String value) {
}
});
register("^T\\+(\\d+)S$", new DateModifier() {
public void modify(Calendar calendar, String value) {
calendar.add(Calendar.MILLISECOND, Integer.parseInt(value));
}
});
register("^T\\-(\\d+)S$", new DateModifier() {
public void modify(Calendar calendar, String value) {
calendar.add(Calendar.MILLISECOND, Integer.parseInt(value) * -1);
}
});
register("^T>s$", new DateModifier() {
public void modify(Calendar calendar, String value) {
calendar.add(Calendar.SECOND, 1);
calendar.add(Calendar.MILLISECOND, calendar.get(Calendar.MILLISECOND) + 1 * -1);
}
});
register("^Tm$", new DateModifier() {
public void modify(Calendar calendar, String value) {
calendar.add(Calendar.MINUTE, 1);
calendar.add(Calendar.SECOND, calendar.get(Calendar.SECOND) * -1);
calendar.add(Calendar.MILLISECOND, calendar.get(Calendar.MILLISECOND) + 1 * -1);
}
});
register("^TH$", new DateModifier() {
public void modify(Calendar calendar, String value) {
calendar.add(Calendar.HOUR_OF_DAY, 1);
calendar.add(Calendar.MINUTE, calendar.get(Calendar.MINUTE) * -1);
calendar.add(Calendar.SECOND, calendar.get(Calendar.SECOND) * -1);
calendar.add(Calendar.MILLISECOND, calendar.get(Calendar.MILLISECOND) + 1 * -1);
}
});
register("^Td$", new DateModifier() {
public void modify(Calendar calendar, String value) {
calendar.add(Calendar.DAY_OF_YEAR, 1);
calendar.add(Calendar.HOUR_OF_DAY, calendar.get(Calendar.HOUR_OF_DAY) * -1);
calendar.add(Calendar.MINUTE, calendar.get(Calendar.MINUTE) * -1);
calendar.add(Calendar.SECOND, calendar.get(Calendar.SECOND) * -1);
calendar.add(Calendar.MILLISECOND, calendar.get(Calendar.MILLISECOND) + 1 * -1);
}
});
register("^Tw$", new DateModifier() {
public void modify(Calendar calendar, String value) {
int thisWeek = calendar.get(Calendar.WEEK_OF_YEAR);
calendar.add(Calendar.HOUR_OF_DAY, calendar.get(Calendar.HOUR_OF_DAY) * -1);
calendar.add(Calendar.MINUTE, calendar.get(Calendar.MINUTE) * -1);
calendar.add(Calendar.SECOND, calendar.get(Calendar.SECOND) * -1);
calendar.add(Calendar.MILLISECOND, calendar.get(Calendar.MILLISECOND) * -1);
while (thisWeek == calendar.get(Calendar.WEEK_OF_YEAR)) {
calendar.add(Calendar.DAY_OF_YEAR, 1);
}
calendar.add(Calendar.MILLISECOND, -1);
}
});
register("^TM$", new DateModifier() {
public void modify(Calendar calendar, String value) {
int thisMonth = calendar.get(Calendar.MONTH);
calendar.add(Calendar.HOUR_OF_DAY, calendar.get(Calendar.HOUR_OF_DAY) * -1);
calendar.add(Calendar.MINUTE, calendar.get(Calendar.MINUTE) * -1);
calendar.add(Calendar.SECOND, calendar.get(Calendar.SECOND) * -1);
calendar.add(Calendar.MILLISECOND, calendar.get(Calendar.MILLISECOND) * -1);
while (thisMonth == calendar.get(Calendar.MONTH)) {
calendar.add(Calendar.DAY_OF_YEAR, 1);
}
calendar.add(Calendar.MILLISECOND, -1);
}
});
register("^Ty$", new DateModifier() {
public void modify(Calendar calendar, String value) {
int thisYear = calendar.get(Calendar.YEAR);
calendar.add(Calendar.HOUR_OF_DAY, calendar.get(Calendar.HOUR_OF_DAY) * -1);
calendar.add(Calendar.MINUTE, calendar.get(Calendar.MINUTE) * -1);
calendar.add(Calendar.SECOND, calendar.get(Calendar.SECOND) * -1);
calendar.add(Calendar.MILLISECOND, calendar.get(Calendar.MILLISECOND) * -1);
while (thisYear == calendar.get(Calendar.YEAR)) {
calendar.add(Calendar.DAY_OF_YEAR, 1);
}
calendar.add(Calendar.MILLISECOND, -1);
}
});
register("^T 0) {
Date tmpT = null;
tmpT = simpleParse(tmpStr, t);
if (tmpT != null) {
t = tmpT;
if (firstPass) {
parsedSoFar = tmpStr.length();
} else {
parsedSoFar += tmpStr.length() - 1;
}
tmpStr = "T" + str.substring(parsedSoFar);
firstPass = false;
} else {
tmpStr = tmpStr.substring(0, tmpStr.length() - 1);
}
if (tmpStr.equals("T")) {
if (parsedSoFar == str.length()) {
break;
} else {
throw new DateParseException("Could not parse date string [" + str + "]!");
}
}
}
if (t == null) {
throw new DateParseException("Could not parse date string [" + str + "]!");
} else {
return t;
}
}
private Date simpleParse(String str, Date t) throws DateParseException {
for (Iterator iter = this.registrations.keySet().iterator(); iter.hasNext();) {
RegexpPredicate predicate = (RegexpPredicate) iter.next();
if (predicate.evaluate(str)) {
Object dateParser = this.registrations.get(predicate);
if (dateParser instanceof DateParser) {
return ((DateParser) dateParser).parse(str);
} else if (dateParser instanceof DateModifier) {
Calendar calendar = new GregorianCalendar();
calendar.setFirstDayOfWeek(Calendar.MONDAY);
if (t == null) {
calendar.setTime(new Date());
} else {
calendar.setTime(t);
}
((DateModifier) dateParser).modify(calendar, predicate.getGroup1(str));
return calendar.getTime();
}
}
}
return null;
}
/**
* Register a date format for a given regular expression.
*
* @param regexp the regular expression
* @param format the date format
*/
public void register(String regexp, String format) {
this.registrations.put(new RegexpPredicate(regexp), new BasicDateParser(format));
}
/**
*
Register your own date parser for a given regular expression.
*
* @param regexp the regular expression
* @param dateParser the date parser
*/
public void register(String regexp, DateModifier dateParser) {
this.registrations.put(new RegexpPredicate(regexp), dateParser);
}
public interface DateModifier {
public void modify(Calendar calendar, String value);
}
private class RegexpPredicate implements Predicate {
private Pattern pattern = null;
public RegexpPredicate(String regexp) {
super();
if (regexp == null || regexp.length() == 0) {
throw new IllegalArgumentException("Regular expression parameter should not be null or blank!");
}
this.pattern = Pattern.compile(regexp);
}
public boolean evaluate(Object o) {
return this.pattern.matcher((String) o).matches();
}
public String getGroup1(Object o) {
Matcher matcher = this.pattern.matcher((String) o);
if (matcher.matches() && matcher.groupCount() > 0) {
return matcher.group(1);
} else {
return null;
}
}
}
private class BasicDateParser implements DateParser {
private DateFormat dateFormat = null;
public BasicDateParser(String format) {
super();
if (format == null || format.length() == 0) {
throw new IllegalArgumentException("Format parameter should not be null or blank!");
}
this.dateFormat = new SimpleDateFormat(format);
}
public Date parse(String s) throws DateParseException {
try {
return this.dateFormat.parse(s);
} catch (ParseException e) {
return null;
}
}
}
}