java工具类,字符串转时间

java工具类,字符串转时间

java 复制代码
package com.tomato.test2;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Arrays;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class TimeUtil {

    private static final Logger LOGGER = LoggerFactory.getLogger(TimeUtil.class);
    private static final Map<String, DateTimeFormatter> FORMATTER_CACHE = new ConcurrentHashMap<>();

    // 常用格式常量
    public static final String DEFAULT_YMDHMS_FORMAT = "yyyy-MM-dd HH:mm:ss";
    public static final String DMYHMS_FORMAT = "dd/MM/yyyy HH:mm:ss";
    public static final String DEFAULT_YMD_FORMAT = "yyyy-MM-dd";
    public static final String DEFAULT_DATE_FORMAT = "yyyy/MM/dd";
    public static final String SOLR_TDATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
    public static final String SOLR_TDATE_RETURN_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
    public static final String ORACLE_TDATE_RETURN_FORMAT = "yyyy-MM-dd HH:mm:ss.SSS";
    public static final String JS_TDATE_RETURN_FORMAT = "yyyy-MM-dd HH:mm:ss.S";
    public static final String COMPACT_YMDHMS_FORMAT = "yyyyMMddHHmmss";
    public static final String COMPACT_YMD_FORMAT = "yyyyMMdd";
    public static final String COMPACT_YMDH_FORMAT = "yyyyMMddHH";
    public static final String US_TIME_FORMAT = "EEE MMM d HH:mm:ss z yyyy";
    public static final String TDATE_RETURN_FORMAT = "yyyy-MM-dd HH:mm:ss.nnnnnnnnn";
    public static final String COMPACT_CHINESE_FORMAT = "yyyy年MM月dd日";
    public static final String YMDHS_FORMAT = "yyyy/MM/dd HH:mm";
    public static final String YMDHS_FORMAT_WITHOUT_SPLIT_TAG = "yyyyMMddHHmm";


    private static final Pattern DATE_ONLY_PATTERN = Pattern.compile("(\\d{4})-(\\d{1,2})-(\\d{1,2})");
    private static final Pattern DATE_TIME_PATTERN = Pattern.compile(
            "(\\d{4}-\\d{2}-\\d{2})(?:[T ](\\d{1,2})(?::(\\d{1,2})(?::(\\d{1,2}))?)?)?"
    );

    static {
        Arrays.asList(
                DEFAULT_YMDHMS_FORMAT,
                DMYHMS_FORMAT,
                DEFAULT_YMD_FORMAT,
                DEFAULT_DATE_FORMAT,
                SOLR_TDATE_FORMAT,
                SOLR_TDATE_RETURN_FORMAT,
                ORACLE_TDATE_RETURN_FORMAT,
                JS_TDATE_RETURN_FORMAT,
                COMPACT_YMDHMS_FORMAT,
                COMPACT_YMD_FORMAT,
                COMPACT_YMDH_FORMAT,
                COMPACT_CHINESE_FORMAT,
                YMDHS_FORMAT,
                YMDHS_FORMAT_WITHOUT_SPLIT_TAG,
                "yyyy-MM-dd HH:mm:ss.S",
                "yyyy-MM-dd HH:mm:ss.SSS",
                "yyyy-MM-dd HH:mm:ss.nnnnnnnnn",
                "dd/MM/yyyy HH:mm:ss"
        ).forEach(pattern -> FORMATTER_CACHE.put(pattern, DateTimeFormatter.ofPattern(pattern)));

        FORMATTER_CACHE.put(US_TIME_FORMAT, DateTimeFormatter.ofPattern(US_TIME_FORMAT, Locale.US));
    }

    private static DateTimeFormatter getFormatter(String pattern) {
        if (StringUtils.isBlank(pattern)) {
            throw new IllegalArgumentException("DateTime pattern must not be blank");
        }
        return FORMATTER_CACHE.computeIfAbsent(pattern, p -> {
            try {
                return DateTimeFormatter.ofPattern(p);
            } catch (Exception e) {
                LOGGER.error("Failed to create DateTimeFormatter for pattern: {}", p, e);
                throw new IllegalArgumentException("Invalid date pattern: " + p, e);
            }
        });
    }

    public static LocalDateTime parseTime(String timeStr, String pattern) {
        if (StringUtils.isBlank(timeStr) || "null".equalsIgnoreCase(timeStr.trim())) {
            return null;
        }
        timeStr = timeStr.trim();
        timeStr = preprocessTimeStr(timeStr, pattern);

        if (StringUtils.isNotBlank(pattern)) {
            try {
                DateTimeFormatter formatter = getFormatter(pattern);
                String input = timeStr;

                if (isDateOnlyPattern(pattern)) {
                    // 处理纯日期模式:截取日期部分并解析为 LocalDate → LocalDateTime
                    if (input.length() > 10 && input.matches("\\d{4}-\\d{2}-\\d{2}.*")) {
                        input = input.substring(0, 10);
                    }
                    java.time.LocalDate date = java.time.LocalDate.parse(input, formatter);
                    return date.atStartOfDay();
                } else {
                    // 含时间的模式:直接解析 LocalDateTime
                    return LocalDateTime.parse(input, formatter);
                }
            } catch (Exception e) {
                LOGGER.debug("指定格式解析失败:{},pattern:{}", timeStr, pattern, e);
            }
        }

        if (timeStr.contains("长期")) {
            return LocalDateTime.of(2999, 12, 31, 0, 0, 0);
        }

        return parseByAutoDetect(timeStr);
    }

    private static LocalDateTime parseByAutoDetect(String timeStr) {
        int len = timeStr.length();

        if (len == 10 && StringUtils.isNumeric(timeStr)) {
            try {
                return Instant.ofEpochSecond(Long.parseLong(timeStr))
                        .atZone(ZoneId.systemDefault())
                        .toLocalDateTime();
            } catch (Exception ignored) {
            }
        }

        if (len == 8) return tryParse(timeStr, COMPACT_YMD_FORMAT);
        if (len == 12) return tryParse(timeStr, YMDHS_FORMAT_WITHOUT_SPLIT_TAG);
        if (len == 14) return tryParse(timeStr, COMPACT_YMDHMS_FORMAT);

        if (len == 10) {
            if (timeStr.contains("-")) return tryParse(timeStr, DEFAULT_YMD_FORMAT);
            if (timeStr.contains("/")) return tryParse(timeStr, DEFAULT_DATE_FORMAT);
        }

        if (len >= 16 && len <= 19) {
            return tryParse(timeStr, DEFAULT_YMDHMS_FORMAT);
        }

        if (len == 21) return tryParse(timeStr, JS_TDATE_RETURN_FORMAT);
        if (len == 23) return tryParse(timeStr, ORACLE_TDATE_RETURN_FORMAT);
        if (len == 20) return tryParse(timeStr, SOLR_TDATE_RETURN_FORMAT);

        // 🔥 重点修复:SOLR UTC 格式必须用 Instant.parse(JDK 8 支持)
        if (len == 24 && timeStr.endsWith("Z")) {
            try {
                Instant instant = Instant.parse(timeStr);
                return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
            } catch (Exception ignored) {
            }
        }

        if (timeStr.contains("年") && timeStr.contains("月") && timeStr.contains("日")) {
            return tryParse(timeStr, COMPACT_CHINESE_FORMAT);
        }

        if (timeStr.matches("^[A-Za-z]{3} [A-Za-z]{3} \\d{1,2} .* \\d{4}$")) {
            try {
                ZonedDateTime zdt = ZonedDateTime.parse(timeStr, getFormatter(US_TIME_FORMAT));
                return zdt.toLocalDateTime();
            } catch (Exception ignored) {
            }
        }

        LOGGER.warn("无法自动解析时间字符串: '{}'", timeStr);
        return null;
    }

    private static LocalDateTime tryParse(String text, String pattern) {
        try {
            return LocalDateTime.parse(text, getFormatter(pattern));
        } catch (DateTimeParseException e) {
            return null;
        }
    }

    public static String format(LocalDateTime dateTime, String pattern) {
        if (dateTime == null || StringUtils.isBlank(pattern)) return "";
        return dateTime.format(getFormatter(pattern));
    }

    private static boolean isDateOnlyPattern(String pattern) {
        if (pattern == null) return false;
        String p = pattern;
        return !p.contains("H") && !p.contains("h") &&
                !p.contains("m") && !p.contains("s") &&
                !p.contains("S") && !p.contains("n");
    }

    private static String padToTwoDigits(String part) {
        if (part == null) return "00";
        try {
            int num = Integer.parseInt(part);
            if (num < 0 || num > 59) return "00";
            return String.format("%02d", num);
        } catch (NumberFormatException e) {
            LOGGER.debug("非法时间数字部分: '{}'", part);
            return "00";
        }
    }

    private static String preprocessTimeStr(String timeStr, String pattern) {
        if (StringUtils.isBlank(timeStr)) {
            return timeStr;
        }

        String standardized = timeStr.replaceAll("[./]", "-");

        // 显式声明 Matcher 类型(JDK 8 不支持 var)
        Matcher dateMatcher = DATE_ONLY_PATTERN.matcher(standardized);
        if (dateMatcher.find()) {
            String year = dateMatcher.group(1);
            String month = padToTwoDigits(dateMatcher.group(2));
            String day = padToTwoDigits(dateMatcher.group(3));
            standardized = dateMatcher.replaceFirst(year + "-" + month + "-" + day);
        }

        if (StringUtils.isNotBlank(pattern)) {
            boolean needsHour = pattern.contains("H") || pattern.contains("k") || pattern.contains("K") || pattern.contains("h");
            boolean needsMinute = pattern.contains("m");
            boolean needsSecond = pattern.contains("s");

            if (needsHour || needsMinute || needsSecond) {
                // 显式声明 Matcher
                Matcher dtMatcher = DATE_TIME_PATTERN.matcher(standardized);
                if (dtMatcher.matches()) {
                    String datePart = dtMatcher.group(1);
                    String hour = dtMatcher.group(2);
                    String minute = dtMatcher.group(3);
                    String second = dtMatcher.group(4);

                    StringBuilder result = new StringBuilder(datePart);

                    if (needsHour) {
                        result.append(" ").append(padToTwoDigits(hour));
                    } else {
                        return datePart;
                    }

                    if (needsMinute) {
                        result.append(":").append(padToTwoDigits(minute));
                    }

                    if (needsSecond) {
                        result.append(":").append(padToTwoDigits(second));
                    }

                    standardized = result.toString();
                }
            }
        }

        return standardized;
    }

    public static void main(String[] args) {

//        年月日,没有时分秒
//        String pattern = "yyyy-MM-dd";
//        LocalDateTime localDateTime = TimeUtil.parseTime("2012-05-05 12:34:56", pattern);

//        补全时分秒
//        String pattern = "yyyy-MM-dd HH:mm:ss";
//        LocalDateTime localDateTime = TimeUtil.parseTime("2012-01-05 12:36", pattern);

//        补全一位日期
//        String pattern = "yyyy-MM-dd HH:mm:ss";
//        LocalDateTime localDateTime = TimeUtil.parseTime("2012-1-05 12:36", pattern);

//        无法转换,localDateTime返回为null
        String pattern = "yyyy-MM-dd HH:mm:ss";
        LocalDateTime localDateTime = TimeUtil.parseTime("abc", pattern);


        if (localDateTime == null) {
            System.out.println("无法转换");
            return;
        }

        System.out.println(localDateTime.format(DateTimeFormatter.ofPattern(pattern)));
    }
}
相关推荐
源码潇潇和逸逸2 小时前
独立部署高校圈子平台:PHP+UniApp打造社交+交易+服务一站式校园解决方案
开发语言·uni-app·php
曹牧2 小时前
JSON 数组的正确使用方式
java·服务器·前端
LINgZone22 小时前
深入解析:Cglib与JDK动态代理的实现原理、区别及性能对比
java·开发语言
一次旅行2 小时前
今日心理学知识分享(三)
开发语言·javascript·程序人生·ecmascript
华科易迅2 小时前
Spring JDBC
java·后端·spring
AI科技星2 小时前
光速螺旋量子几何统一场论——基于 v ≡ c 公理的四大基本力全维度求导证明与精准数值验证
c语言·开发语言·人工智能·算法·机器学习·平面
云烟成雨TD2 小时前
Spring AI 1.x 系列【17】函数型工具开发与使用
java·人工智能·spring
天天学IT2 小时前
第三章 Qt 编译及安装
开发语言·qt·qt教程·qt6教程
xyq20242 小时前
Window Memcached 安装指南
开发语言