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)));
}
}