java实现动态日期宏变量

在常用的调度平台,都会提供一个{{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'
*/

 

posted @ 2021-11-30 19:16  Mars.wang  阅读(228)  评论(0编辑  收藏  举报