四、如何科学地在Java开发中——尽可能地自动解析转换各种时间格式的时间字符串为LocalDate?

需求

工具类,满足尽可能地自动解析转换各种时间格式的时间字符串为LocalDate,目前支持转换的时间格式有如下,时间字符串至少含有“yyyy”:

  • "yyyy"
  • "yyyy/MM"
  • "yyyy-MM"
  • "yyyy/MM/dd"
  • "yyyy-MM-dd"
  • "yyyy/MM/dd HH:mm"
  • "yyyy-MM-dd HH:mm"
  • "yyyy-MM-dd HH:mm:ss"

核心全部代码 复制到编译器可以直接运行 更多格式自己改造下

package test.date;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

/**
 * @description 全自动适配各种时间格式的字符串  必须包含年
 * @Date 2020/8/16 23:10
 */
@Slf4j
public class AutoDateUtils {

    public static final String FORMAT_DATETIME = "yyyy-MM-dd HH:mm:ss";
    public static final String FORMAT = "yyyy-MM-dd";
    public static final String FORMAT2 = "yyyy/MM/dd";
    public static final String FORMAT3 = "yyyy-MM-dd HH:mm";
    public static final String FORMAT5 = "yyyy/MM/dd HH:mm";
//    public static final String FORMAT6 = "yyyyMMdd";    # 暂不支持
//    public static final String FORMAT7 = "yyyy年MM月dd日 HH:mm:ss";  # 暂不支持
    public static final String FORMAT8 = "yyyy-MM";
//    public static final String FORMAT9 = "MM-dd";  # 暂不支持
    public static final String FORMAT10 = "yyyy";
    public static final String FORMAT11 = "yyyy/MM";



    /**
     * 自动适配字符串的配置格式
     */
    private static final List<String> FORMATTERS = Arrays.asList(FORMAT_DATETIME, FORMAT, FORMAT2, FORMAT3, FORMAT5, FORMAT8, FORMAT10, FORMAT11);
    private static Map<String, String> DAY_FORMATTER_MAPS = preParseLocalDate();

    // 预处理
    private static Map<String, String> preParseLocalDate() {

        Map<String, String> regexMap = new HashMap<>(FORMATTERS.size());
        // 最全的yyyy-MM-dd HH:mm:ss
        for (String format : FORMATTERS) {
            String regex = format.replace("yyyy", "\d{4}").replace("MM", "\d{2}").replace("dd", "\d{2}").replace("HH", "\d{2}").replace("mm", "\d{2}").replace("ss", "\d{2}");
            regexMap.put(format, regex);
        }
        return regexMap;
    }

    /**
     * 校验是否为localDate的任意一种格式
     *
     * @param timeText
     * @return
     */
    public static boolean judgeLocalDateFormat(String timeText) {
        for (String formatter : FORMATTERS) {
            String regex = DAY_FORMATTER_MAPS.get(formatter);
            if (Pattern.matches(regex, timeText)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 自动适配字符串, 转换日期字符串为LocalDate
     *
     * @param timeText
     * @return
     */
    public static LocalDate autoParseLocalDate(String timeText) {
        for (String formatter : FORMATTERS) {
            String regex = DAY_FORMATTER_MAPS.get(formatter);
            if (Pattern.matches(regex, timeText)) {
                // 特殊考虑
                if (formatter.equals(FORMAT10)) {
                    timeText = timeText.trim() + "-01-01";
                    formatter = FORMAT;
                } else if (formatter.equals(FORMAT11)) {
                    timeText = timeText.trim() + "/01";
                    formatter = FORMAT2;
                } else if (formatter.equals(FORMAT8)) {
                    timeText = timeText.trim() + "-01";
                    formatter = FORMAT;
                }
//
                return LocalDate.parse(timeText, DateTimeFormatter.ofPattern(formatter));

//              转为 LocalDateTime 格式, 直接反注释下面这一行并且将上面的 特殊考虑重新修订一遍
//              return LocalDateTime.parse(timeText, DateTimeFormatter.ofPattern(formatter));
            }
        }
        String msg = timeText + "没有合适的对应的formatter, 请先在DateUtil.DAY_FORMATTER_MAPS 中进行配置";
        log.error(msg);
        throw new RuntimeException(msg);
    }

    /**
     * 简单匹配转换yyyyMMdd类型的日期字符串,更多格式自己配置
     *
     * @param timeText
     * @return
     */
    public static String simpleParseStrOfYYYYMMHH(String timeText) throws Exception {
        List<String> regexs = Arrays.asList("\d{4}[-]\d{2}[-]\d{2}", "\d{4}[/]\d{2}[/]\d{2}");
        List<String> formats = Arrays.asList("yyyy-MM-dd", "yyyy/MM/dd");

        for (int idx = 0; idx < regexs.size(); idx++) {
            if (Pattern.matches(regexs.get(idx), timeText)) {
                try {
                    LocalDate parse = LocalDate.parse(timeText, DateTimeFormatter.ofPattern(formats.get(idx)));
                    return parse.toString();
                } catch (Exception e) {
                    throw new Exception("日期格式错误,请填写正确的日期");
                }
            }
        }
        throw new Exception("日期格式异常,建议日期格式类型应该为 "yyyy-MM-dd"");
    }


    @SneakyThrows
    public static void main(String[] args) {
        System.out.println(DAY_FORMATTER_MAPS);
        // 支持8种格式的时间日期字符串转为LocalDate
        System.out.println(autoParseLocalDate("2020-06-09 16:34:14"));
        System.out.println(autoParseLocalDate("2020-06-09 16:34"));
        System.out.println(autoParseLocalDate("2020/06/09 16:34"));
        System.out.println(autoParseLocalDate("2020/06/09"));
        System.out.println(autoParseLocalDate("2020-06-09"));
        System.out.println(autoParseLocalDate("2020-06"));
        System.out.println(autoParseLocalDate("2020/06"));
        System.out.println(autoParseLocalDate("2020"));

        // 刚开始写的简单版本,后来发现还可以再扩展就有了上面的autoParseLocalDate
        System.out.println("==================测试出来的彩蛋,自动纠正了,02-31不会抛异常");
        System.out.println(simpleParseStrOfYYYYMMHH("2019/09/30"));
        System.out.println(simpleParseStrOfYYYYMMHH("2019-02-29"));
        System.out.println(simpleParseStrOfYYYYMMHH("2019-02-30"));
        System.out.println(simpleParseStrOfYYYYMMHH("2019-02-31"));
        System.out.println(simpleParseStrOfYYYYMMHH("2019-02-20"));
    }
}

运行上面的main方法测试和输出

支持格式
{yyyy-MM=d{4}-d{2}, yyyy/MM=d{4}/d{2}, yyyy/MM/dd=d{4}/d{2}/d{2}, yyyy/MM/dd HH:mm=d{4}/d{2}/d{2} d{2}:d{2}, yyyy-MM-dd HH:mm:ss=d{4}-d{2}-d{2} d{2}:d{2}:d{2}, yyyy=d{4}, yyyy-MM-dd HH:mm=d{4}-d{2}-d{2} d{2}:d{2}, yyyy-MM-dd=d{4}-d{2}-d{2}}

打印结果:
2020-06-09
2020-06-09
2020-06-09
2020-06-09
2020-06-09
2020-06-01
2020-06-01
2020-01-01
2019-09-30
2019-02-28
2019-02-28
2019-02-28
2019-02-20

原文地址:https://www.cnblogs.com/zhazhaacmer/p/13515162.html