在常用的调度平台,都会提供一个{{ds}}或者${yyyyMMdd}类似的宏变量。
那么这个是怎么实现的呢;
首先定义一个日期加减运算的枚举类,我们可以根据用户提供表达式在当前日期上进行加减运算
public enum DateScaleEnum { y { @Override public LocalDateTime calculate(LocalDateTime origin, String op, Integer num) { if (op.equals("+")) { return origin.plusYears(num); } else { return origin.minusYears(num); } } }, M { @Override public LocalDateTime calculate(LocalDateTime origin, String op, Integer num) { if (op.equals("+")) { return origin.plusMonths(num); } else { return origin.minusMonths(num); } } }, d { @Override public LocalDateTime calculate(LocalDateTime origin, String op, Integer num) { if (op.equals("+")) { return origin.plusDays(num); } else { return origin.minusDays(num); } } }; public abstract LocalDateTime calculate(LocalDateTime origin, String op, Integer num); }
核心工具类
public class DateFormatUtil { private static final Pattern dynamicPattern = Pattern.compile("\\$\\{(.*?)\\}"); private static final Pattern namePattern = Pattern.compile("(?<format>[yMd\\-]+):?(?<op>\\+|\\-)?(?<num>[0-9]+)?(?<scale>[a-zA-Z])?"); /** * 正则查找动态日期字符串'${yyyyMMdd:+7d}',并进行格式化 * @param sourStr * @return */ public static String dynamicFormat(String sourStr) { String targetStr = sourStr; try { Matcher dynamicMatcher = dynamicPattern.matcher(targetStr); while (dynamicMatcher.find()) { String key = dynamicMatcher.group(); String keyclone = key.substring(2,key.length()-1); String value = getDynamicDate(keyclone); if (value != null) targetStr = targetStr.replace(key, value); } }catch (Exception e){ e.printStackTrace(); } return targetStr; } /** * 根据日期格式返回日期字符串 * @param key 'yyyyMMdd' 或 'yyyy-MM-dd:+1d' * @return 2021-11-23 * 根据格式串分别匹配出日期格式、加or减、加减数量和尺度 */ public static String getDynamicDate(String key) { Matcher dateMatcher = namePattern.matcher(key); LocalDateTime now = LocalDateTime.now(); String target=null; while (dateMatcher.find()) { String format= dateMatcher.group("format"); String op= dateMatcher.group("op"); String num= dateMatcher.group("num"); String scale= dateMatcher.group("scale"); DateFormatEnum dynamicDate = getDateFormat(format); if (op == null) { return dynamicDate.format(now); } DateScaleEnum dateScaleEnum = DateScaleEnum.valueOf(scale); LocalDateTime calculate = dateScaleEnum.calculate(now, op, Integer.valueOf(num)); target= dynamicDate.format(calculate); } return target; } /** * 根据用户提供的format对日期格式化 * @param format * @return */ public static DateFormatEnum getDateFormat(String format) { switch (format) { case "yyyy": return DateFormatEnum.Y; case "yyyy-MM": return DateFormatEnum.YM; case "yyyyMM": return DateFormatEnum.YM3; case "yyyyMMdd": return DateFormatEnum.YMD3; case "yyyy-MM-dd": default: return DateFormatEnum.YMD; } } public static void main(String[] args) { String sql="select a,b,c from table " + "where dt>='${yyyy:-1y}' and dt<='${yyyyMM:+10M}' and dt='${yyyyMMdd}'"; System.out.println(sql); String newSql = dynamicFormat(sql); System.out.println(newSql); } }
打印:
select a,b,c from table where dt>='${yyyy:-1y}' and dt<='${yyyyMM:+10M}' and dt='${yyyyMMdd}'
select a,b,c from table where dt>='2020' and dt<='202210' and dt='20211201'
补充用法:如果想写去年一月这样的日期,怎么办?
其实不需要再把正则表达式进一步优化,现在的方式就可以支持了。
public static void main(String[] args) { String sql="select a,b,c from table " + "where dt>='${yyyy:-1y}-01' and dt<='${yyyyMM:+10M}' and dt='${yyyy-MM-dd} 00:00:00'"; System.out.println(sql); String newSql = dynamicFormat(sql); System.out.println(newSql); } /** 输出: select a,b,c from table where dt>='${yyyy:-1y}-01' and dt<='${yyyyMM:+10M}' and dt='${yyyy-MM-dd} 00:00:00' select a,b,c from table where dt>='2020-01' and dt<='202210' and dt='2021-12-01 00:00:00' */