自己用的一个需要解析时间格式表达式的小工具类:
/**
* <pre>
* Copyright CDC [2000-2015]
* </pre>
*/
package org.kanpiaoxue.commons.utils;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import com.google.common.base.Preconditions;
import com.google.common.base.Splitter;
import com.google.common.collect.Maps;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* <pre>
* DateExpressionEngine.java
* @author kanpiaoxue<br>
* @version 1.0
* Create Time 2015年6月4日 下午7:16:02<br>
* Description : 时间表达式引擎
* </pre>
*/
public class DateExpressionEngine {
/**
* <pre>
* @param needProcessString 需要处理的字符串
* 里面可以含有任意多个时间表达式
* 格式:dateFormat[,offset]}
* dateFormat: 符合java的java.text.DateFormat规范的表达式
* DateUnit 时间格式单位:[注意大小写]
* y : year
* M : Month
* d : day
* w : week
* H : Hour
* m : minute
*
* [重点]这里的格式有两种,一种是一般日期表达式,一种是特殊表达式
*
* 一、一般日期表达式:
* offset的表达式:(-)?number+DateUnit
* offset的正则表达式: ^((?:-)?\\d+?)([y,M,w,d,H,m])$
*
* example:
* ${MM} ${MMdd} ${MM/dd} ${HH} ${HHmm}
* ${yyyyMMdd} ${yyyy-MM-dd} ${yyyy/MM/dd}
* ${yyyyMMddHH} ${yyyy-MM-dd HH} ${yyyy/MM/dd HH}
* ${yyyyMMddHHmm} ${yyyy-MM-dd HH:mm} ${yyyy/MM/dd HH:mm}
* ${yyyyMMdd,-1y} ${yyyy-MM-dd,-1y} ${yyyy/MM/dd,-1y}
* ${yyyyMMdd,-1M} ${yyyy-MM-dd,-1M} ${yyyy/MM/dd,-1M}
* ${yyyyMMdd,1d} ${yyyy-MM-dd,1d} ${yyyy/MM/dd,1d}
* ${yyyyMMddHH,1H} ${yyyy-MM-dd HH,1H} ${yyyy/MM/dd HH,1H}
* ${yyyyMMdd,1w} ${yyyy-MM-dd,1w} ${yyyy/MM/dd,1w}
* ${yyyyMMddHHmm,10m} ${yyyy-MM-dd HH:mm,10m} ${yyyy/MM/dd HH:mm,10m}
*
* 二、特殊表达式
* 用来计算:季度初/末,月初/末,周初/末(也就是周一和周日)
* offset的表达式:position+DateUnit
* offset的正则表达式:^([F,f,E,e])([M,w,W,q,Q])$
* ------------------
* F,f means: first
* E,e means: end
* ------------------
* M : Month
* w,W : Week
* q,Q : Quarter
*
* @param dateValue 时间的字符串,格式要求 yyyyMMdd,yyyyMMddHH,yyyyMMddHHmm
* @return 经过计算之后的字符串
* </pre>
*/
public static String formatDateExpression(String needProcessString, String dateValue) {
Preconditions.checkArgument(StringUtils.isNotBlank(needProcessString));
Preconditions.checkArgument(StringUtils.isNotBlank(dateValue));
Preconditions.checkArgument(DATE_PATTERN.matcher(dateValue).matches(),
"dateValue is unexpect format:%s. "
+ "Required min length is 8, like : 20150101. %s's length is : %s", dateValue,
dateValue, dateValue.length());
Matcher m = PATTERN.matcher(needProcessString);
/**
* 如果找到时间表达式则进行替换,如果找不到,则不进行处理
*/
while (m.find()) {
String expression = m.group(2);
/**
* <pre>
* ${expression} is group(1) , as: ${yyyyMMdd,-1y} , ${yyyyMMdd,FQ}
* expression is group(2) , as: yyyyMMdd,-1y , yyyyMMdd,FQ
* </pre>
*/
int start = m.start(1);
int end = m.end(1);
// expressionWrapper : ${yyyyMMdd,-1y} , ${yyyyMMdd,FQ}
String expressionWrapper = needProcessString.substring(start, end);
// replaceMent : 20150101 201501012359
// 得到正确的时间字符串
String replaceMent = getCorrectDateString(expression, dateValue);
// 替换表达式为正确的时间字符串
needProcessString = StringUtils.replace(needProcessString, expressionWrapper, replaceMent);
// find next
m = PATTERN.matcher(needProcessString);
}
return needProcessString;
}
private static String getCorrectDateString(String express, String dataVersionNo) {
// 将表达式切分开
List<String> lst = Splitter.on(',').trimResults().omitEmptyStrings().splitToList(express);
int size = lst.size();
Preconditions.checkArgument(size <= 2, "unexpected expression format:%s", express);
// 得到世界表达式的格式化部分
String format = lst.get(0);
// 将版本号的字符串转换为 DateTime 对象
DateTime dateTime = parseForDataVersionNo(dataVersionNo);
DateTime rs = dateTime;
// 如果存在复杂的计算表达式
if (lst.size() == 2) {
String offsetExpression = lst.get(1);
// 处理季度、月、周的第一天和最后一天
Matcher sm = OFFSET_SPECIAL_PATTERN.matcher(offsetExpression);
if (sm.matches()) {
String str1 = sm.group(1);
Preconditions.checkArgument(StringUtils.isNotBlank(str1), "unexpected expression format:%s",
express);
String unit = sm.group(2);
if (QUARTR_STRING.equalsIgnoreCase(unit)) {
DateTime startQuarter =
dateTime.plusMonths(0 - (dateTime.monthOfYear().get() - 1) % 3).dayOfMonth()
.withMinimumValue();
// 季度初
if (FIRST_STRING.equalsIgnoreCase(str1)) {
rs = startQuarter;
} else if (END_STRING.equalsIgnoreCase(str1)) {
rs = startQuarter.plusMonths(3).plusDays(-1);
// 季度末
} else {
throw new IllegalArgumentException(String.format("unexpected expression format:%s",
express));
}
} else if (MONTH_STRING.equals(unit)) {
if (FIRST_STRING.equalsIgnoreCase(str1)) {
rs = dateTime.dayOfMonth().withMinimumValue();
} else if (END_STRING.equalsIgnoreCase(str1)) {
rs = dateTime.dayOfMonth().withMaximumValue();
} else {
throw new IllegalArgumentException(String.format("unexpected expression format:%s",
express));
}
} else if (WEEK_STRING.equalsIgnoreCase(unit)) {
if (FIRST_STRING.equalsIgnoreCase(str1)) {
rs = dateTime.dayOfWeek().withMinimumValue();
} else if (END_STRING.equalsIgnoreCase(str1)) {
rs = dateTime.dayOfWeek().withMaximumValue();
} else {
throw new IllegalArgumentException(String.format("unexpected expression format:%s",
express));
}
}
return rs.toString(format);
}
// 处理一般的时间表达式
Matcher m = OFFSET_PATTERN.matcher(offsetExpression);
Preconditions.checkArgument(m.matches(), "unexpected expression format:%s", express);
String numString = m.group(1);
if (StringUtils.isBlank(numString)) {
numString = "0";
}
int num = Integer.valueOf(numString).intValue();
String unit = m.group(2);
if (YEAR_STRING.equalsIgnoreCase(unit)) {
// IgnoreCase
rs = dateTime.plusYears(num);
} else if (MONTH_STRING.equals(unit)) {
rs = dateTime.plusMonths(num);
} else if (WEEK_STRING.equalsIgnoreCase(unit)) {
// IgnoreCase
rs = dateTime.plusWeeks(num);
} else if (DAY_STRING.equalsIgnoreCase(unit)) {
// IgnoreCase
rs = dateTime.plusDays(num);
} else if (HOUR_STRING.equalsIgnoreCase(unit)) {
// IgnoreCase
rs = dateTime.plusHours(num);
} else if (MINUTE_STRING.equals(unit)) {
rs = dateTime.plusMinutes(num);
} else {
throw new IllegalArgumentException(String.format("unexpected expression format:%s", express));
}
}
return rs.toString(format);
}
/**
* <pre>
* ======================================== start ========================================
* <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
* <html>
* <head>
* &