This commit is contained in:
Looly 2024-06-11 16:13:07 +08:00
parent 57692b6cbb
commit 21be35c9c3
11 changed files with 90 additions and 119 deletions

View File

@ -13,19 +13,19 @@
package org.dromara.hutool.core.date.format.parser; package org.dromara.hutool.core.date.format.parser;
import org.dromara.hutool.core.date.DateException; import org.dromara.hutool.core.date.DateException;
import org.dromara.hutool.core.date.format.DateBasic;
import java.util.Date; import java.util.Date;
/** /**
* 日期解析接口用于解析日期字符串为 {@link Date} 对象<br> * 日期解析接口用于解析日期字符串为 {@link Date} 对象
* Thanks to Apache Commons Lang 3.5 *
* @author Looly
*/ */
public interface DateParser extends DateBasic{ @FunctionalInterface
public interface DateParser {
/** /**
* 将日期字符串解析并转换为 {@link Date} 对象<br> * 将日期字符串解析并转换为 {@link Date} 对象
* 等价于 {@link java.text.DateFormat#parse(String)}
* *
* @param source 被解析的日期字符串 * @param source 被解析的日期字符串
* @return {@link Date}对象 * @return {@link Date}对象

View File

@ -15,10 +15,11 @@ package org.dromara.hutool.core.date.format.parser;
import org.dromara.hutool.core.date.DateException; import org.dromara.hutool.core.date.DateException;
import org.dromara.hutool.core.date.DatePattern; import org.dromara.hutool.core.date.DatePattern;
import org.dromara.hutool.core.date.DateTime; import org.dromara.hutool.core.date.DateTime;
import org.dromara.hutool.core.date.format.DefaultDateBasic;
import org.dromara.hutool.core.regex.ReUtil; import org.dromara.hutool.core.regex.ReUtil;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.core.text.CharUtil; import org.dromara.hutool.core.text.CharUtil;
import org.dromara.hutool.core.text.StrUtil;
import java.io.Serializable;
/** /**
* ISO8601日期字符串JDK的Date对象toString默认格式解析支持格式 * ISO8601日期字符串JDK的Date对象toString默认格式解析支持格式
@ -34,7 +35,7 @@ import org.dromara.hutool.core.text.CharUtil;
* @author looly * @author looly
* @since 6.0.0 * @since 6.0.0
*/ */
public class ISO8601DateParser extends DefaultDateBasic implements PredicateDateParser { public class ISO8601DateParser implements PredicateDateParser, Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**

View File

@ -15,11 +15,11 @@ package org.dromara.hutool.core.date.format.parser;
import org.dromara.hutool.core.date.DateException; import org.dromara.hutool.core.date.DateException;
import org.dromara.hutool.core.date.DatePattern; import org.dromara.hutool.core.date.DatePattern;
import org.dromara.hutool.core.date.DateTime; import org.dromara.hutool.core.date.DateTime;
import org.dromara.hutool.core.date.format.DefaultDateBasic;
import org.dromara.hutool.core.regex.ReUtil; import org.dromara.hutool.core.regex.ReUtil;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.core.text.CharUtil; import org.dromara.hutool.core.text.CharUtil;
import org.dromara.hutool.core.text.StrUtil;
import java.io.Serializable;
import java.util.regex.Pattern; import java.util.regex.Pattern;
/** /**
@ -35,7 +35,7 @@ import java.util.regex.Pattern;
* @author looly * @author looly
* @since 6.0.0 * @since 6.0.0
*/ */
public class NormalDateParser extends DefaultDateBasic implements PredicateDateParser { public class NormalDateParser implements PredicateDateParser, Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final Pattern patternNorm = Pattern.compile("\\d{4}-\\d{1,2}-\\d{1,2}(\\s\\d{1,2}:\\d{1,2}(:\\d{1,2})?(.\\d{1,6})?)?"); private static final Pattern patternNorm = Pattern.compile("\\d{4}-\\d{1,2}-\\d{1,2}(\\s\\d{1,2}:\\d{1,2}(:\\d{1,2})?(.\\d{1,6})?)?");

View File

@ -15,8 +15,8 @@ package org.dromara.hutool.core.date.format.parser;
import org.dromara.hutool.core.date.CalendarUtil; import org.dromara.hutool.core.date.CalendarUtil;
import org.dromara.hutool.core.date.DateException; import org.dromara.hutool.core.date.DateException;
import org.dromara.hutool.core.date.DateTime; import org.dromara.hutool.core.date.DateTime;
import org.dromara.hutool.core.date.format.DefaultDateBasic;
import java.io.Serializable;
import java.util.Calendar; import java.util.Calendar;
import java.util.Locale; import java.util.Locale;
@ -27,7 +27,7 @@ import java.util.Locale;
* @author looly * @author looly
* @since 6.0.0 * @since 6.0.0
*/ */
public class PatternsDateParser extends DefaultDateBasic implements DateParser { public class PatternsDateParser implements DateParser, Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**
@ -74,7 +74,11 @@ public class PatternsDateParser extends DefaultDateBasic implements DateParser {
return this; return this;
} }
@Override /**
* 获取{@link Locale}
*
* @return {@link Locale}
*/
public Locale getLocale() { public Locale getLocale() {
return locale; return locale;
} }

View File

@ -12,6 +12,8 @@
package org.dromara.hutool.core.date.format.parser; package org.dromara.hutool.core.date.format.parser;
import org.dromara.hutool.core.date.format.DateBasic;
import java.text.ParsePosition; import java.text.ParsePosition;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
@ -22,7 +24,7 @@ import java.util.Date;
* *
* @since 2.16.2 * @since 2.16.2
*/ */
public interface PositionDateParser extends DateParser { public interface PositionDateParser extends DateParser, DateBasic {
/** /**
* 将日期字符串解析并转换为 {@link Date} 对象<br> * 将日期字符串解析并转换为 {@link Date} 对象<br>
@ -35,16 +37,14 @@ public interface PositionDateParser extends DateParser {
Date parse(CharSequence source, ParsePosition pos); Date parse(CharSequence source, ParsePosition pos);
/** /**
* 根据给定格式更新{@link Calendar} * 根据给定格式更新{@link Calendar}<br>
* Upon success, the ParsePosition index is updated to indicate how much of the source text was consumed. * 解析成功后{@link ParsePosition#getIndex()}更新成转换到的位置<br>
* Not all source text needs to be consumed. * 失败则{@link ParsePosition#getErrorIndex()}更新到解析失败的位置
* Upon parse failure, ParsePosition error index is updated to the offset of the source text which does not match the supplied format.
* *
* @param source 被转换的日期字符串 * @param source 被转换的日期字符串
* @param pos 定义开始转换的位置转换结束后更新转换到的位置 * @param pos 定义开始转换的位置转换结束后更新转换到的位置
* @param calendar The calendar into which to set parsed fields. * @param calendar 解析并更新的{@link Calendar}
* @return true, if source has been parsed (pos parsePosition is updated); otherwise false (and pos errorIndex is updated) * @return 解析成功返回 {@code true}否则返回{@code false}
* @throws IllegalArgumentException when Calendar has been set to be not lenient, and a parsed field is out of range.
*/ */
boolean parse(CharSequence source, ParsePosition pos, Calendar calendar); boolean parse(CharSequence source, ParsePosition pos, Calendar calendar);
} }

View File

@ -4,7 +4,7 @@ import java.util.function.Predicate;
/** /**
* 通过判断字符串的匹配解析为日期<br> * 通过判断字符串的匹配解析为日期<br>
* 通过实现{@link #test(Object)}方法判断字符串是否符合此解析器的规则如果符合则调用{@link #parse(String)}完成解析 * 通过实现{@link #test(Object)}方法判断字符串是否符合此解析器的规则如果符合则调用{@link #parse(CharSequence)}完成解析
* *
* @author looly * @author looly
* @since 6.0.0 * @since 6.0.0

View File

@ -15,10 +15,11 @@ package org.dromara.hutool.core.date.format.parser;
import org.dromara.hutool.core.date.DateException; import org.dromara.hutool.core.date.DateException;
import org.dromara.hutool.core.date.DatePattern; import org.dromara.hutool.core.date.DatePattern;
import org.dromara.hutool.core.date.DateTime; import org.dromara.hutool.core.date.DateTime;
import org.dromara.hutool.core.date.format.DefaultDateBasic;
import org.dromara.hutool.core.math.NumberUtil; import org.dromara.hutool.core.math.NumberUtil;
import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.core.text.StrUtil;
import java.io.Serializable;
/** /**
* 纯数字的日期字符串解析支持格式包括 * 纯数字的日期字符串解析支持格式包括
* <ul> * <ul>
@ -32,7 +33,7 @@ import org.dromara.hutool.core.text.StrUtil;
* @author looly * @author looly
* @since 6.0.0 * @since 6.0.0
*/ */
public class PureDateParser extends DefaultDateBasic implements PredicateDateParser { public class PureDateParser implements PredicateDateParser, Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**

View File

@ -14,10 +14,10 @@ package org.dromara.hutool.core.date.format.parser;
import org.dromara.hutool.core.date.DatePattern; import org.dromara.hutool.core.date.DatePattern;
import org.dromara.hutool.core.date.DateTime; import org.dromara.hutool.core.date.DateTime;
import org.dromara.hutool.core.date.format.DefaultDateBasic;
import org.dromara.hutool.core.date.format.FastDateFormat; import org.dromara.hutool.core.date.format.FastDateFormat;
import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.core.text.StrUtil;
import java.io.Serializable;
import java.util.Locale; import java.util.Locale;
/** /**
@ -32,7 +32,7 @@ import java.util.Locale;
* @author looly * @author looly
* @since 6.0.0 * @since 6.0.0
*/ */
public class RFC2822DateParser extends DefaultDateBasic implements PredicateDateParser { public class RFC2822DateParser implements PredicateDateParser, Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final String KEYWORDS_LOCALE_CHINA = "星期"; private static final String KEYWORDS_LOCALE_CHINA = "星期";
@ -59,8 +59,8 @@ public class RFC2822DateParser extends DefaultDateBasic implements PredicateDate
@Override @Override
public DateTime parse(final CharSequence source) { public DateTime parse(final CharSequence source) {
// issue#I9C2D4 // issue#I9C2D4
if(StrUtil.contains(source, ',')){ if (StrUtil.contains(source, ',')) {
if(StrUtil.contains(source, KEYWORDS_LOCALE_CHINA)){ if (StrUtil.contains(source, KEYWORDS_LOCALE_CHINA)) {
// 例如星期四, 28 三月 2024 14:33:49 GMT // 例如星期四, 28 三月 2024 14:33:49 GMT
return new DateTime(source, FastDateFormat.getInstance(DatePattern.HTTP_DATETIME_PATTERN, Locale.CHINA)); return new DateTime(source, FastDateFormat.getInstance(DatePattern.HTTP_DATETIME_PATTERN, Locale.CHINA));
} }
@ -68,7 +68,7 @@ public class RFC2822DateParser extends DefaultDateBasic implements PredicateDate
return new DateTime(source, DatePattern.HTTP_DATETIME_FORMAT); return new DateTime(source, DatePattern.HTTP_DATETIME_FORMAT);
} }
if(StrUtil.contains(source, KEYWORDS_LOCALE_CHINA)){ if (StrUtil.contains(source, KEYWORDS_LOCALE_CHINA)) {
// 例如星期四, 28 三月 2024 14:33:49 GMT // 例如星期四, 28 三月 2024 14:33:49 GMT
return new DateTime(source, FastDateFormat.getInstance(DatePattern.JDK_DATETIME_PATTERN, Locale.CHINA)); return new DateTime(source, FastDateFormat.getInstance(DatePattern.JDK_DATETIME_PATTERN, Locale.CHINA));
} }

View File

@ -13,7 +13,8 @@
package org.dromara.hutool.core.date.format.parser; package org.dromara.hutool.core.date.format.parser;
import org.dromara.hutool.core.date.*; import org.dromara.hutool.core.date.*;
import org.dromara.hutool.core.date.format.DefaultDateBasic; import org.dromara.hutool.core.lang.Opt;
import org.dromara.hutool.core.regex.PatternPool;
import org.dromara.hutool.core.regex.ReUtil; import org.dromara.hutool.core.regex.ReUtil;
import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.core.text.StrUtil;
@ -31,8 +32,7 @@ import java.util.regex.Pattern;
* @author Looly * @author Looly
* @since 6.0.0 * @since 6.0.0
*/ */
public class RegexDateParser extends DefaultDateBasic implements PredicateDateParser { public class RegexDateParser implements PredicateDateParser {
private static final long serialVersionUID = 1L;
private static final int[] NSS = {100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1}; private static final int[] NSS = {100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1};
@ -43,7 +43,7 @@ public class RegexDateParser extends DefaultDateBasic implements PredicateDatePa
* @return RegexDateParser * @return RegexDateParser
*/ */
public static RegexDateParser of(final String regex) { public static RegexDateParser of(final String regex) {
return new RegexDateParser(Pattern.compile(regex)); return new RegexDateParser(PatternPool.get(regex));
} }
private final Pattern pattern; private final Pattern pattern;
@ -66,86 +66,7 @@ public class RegexDateParser extends DefaultDateBasic implements PredicateDatePa
public Date parse(final CharSequence source) throws DateException { public Date parse(final CharSequence source) throws DateException {
final Matcher matcher = this.pattern.matcher(source); final Matcher matcher = this.pattern.matcher(source);
if(!matcher.matches()){ if(!matcher.matches()){
throw new DateException("Invalid date string: [{}]", source); throw new DateException("Invalid date string: [{}], not match the date regex: [{}].", source, this.pattern.pattern());
}
final DateBuilder dateBuilder = DateBuilder.of();
// year
final String year = ReUtil.group(matcher, "year");
if (StrUtil.isNotEmpty(year)) {
dateBuilder.setYear(parseYear(year));
}
// month
final String month = ReUtil.group(matcher, "month");
if (StrUtil.isNotEmpty(month)) {
dateBuilder.setMonth(parseMonth(month));
}
// week
final String week = ReUtil.group(matcher, "week");
if (StrUtil.isNotEmpty(week)) {
dateBuilder.setWeek(parseWeek(week));
}
// day
final String day = ReUtil.group(matcher, "day");
if (StrUtil.isNotEmpty(day)) {
dateBuilder.setDay(parseNumberLimit(day, 1, 31));
}
// hour
final String hour = ReUtil.group(matcher, "hour");
if (StrUtil.isNotEmpty(hour)) {
dateBuilder.setHour(parseNumberLimit(hour, 0, 23));
}
// minute
final String minute = ReUtil.group(matcher, "minute");
if (StrUtil.isNotEmpty(minute)) {
dateBuilder.setMinute(parseNumberLimit(minute, 0, 59));
}
// second
final String second = ReUtil.group(matcher, "second");
if (StrUtil.isNotEmpty(second)) {
dateBuilder.setSecond(parseNumberLimit(second, 0, 59));
}
// ns
final String ns = ReUtil.group(matcher, "ns");
if (StrUtil.isNotEmpty(ns)) {
dateBuilder.setNs(parseNano(ns));
}
// am or pm
final String m = ReUtil.group(matcher, "m");
if (StrUtil.isNotEmpty(m)) {
if ('p' == m.charAt(0)) {
dateBuilder.setPm(true);
} else {
dateBuilder.setAm(true);
}
}
// zero zone offset
final String zero = ReUtil.group(matcher, "zero");
if (StrUtil.isNotEmpty(zero)) {
dateBuilder.setZoneOffsetSetted(true);
dateBuilder.setZoneOffset(0);
}
// zone offset
final String zoneOffset = ReUtil.group(matcher, "zoneOffset");
if (StrUtil.isNotEmpty(zoneOffset)) {
dateBuilder.setZoneOffsetSetted(true);
dateBuilder.setZoneOffset(parseZoneOffset(zoneOffset));
}
// unix时间戳
final String unixsecond = ReUtil.group(matcher, "unixsecond");
if (StrUtil.isNotEmpty(unixsecond)) {
dateBuilder.setUnixsecond(parseLong(unixsecond));
} }
// 毫秒时间戳 // 毫秒时间戳
@ -154,6 +75,49 @@ public class RegexDateParser extends DefaultDateBasic implements PredicateDatePa
return DateUtil.date(parseLong(millisecond)); return DateUtil.date(parseLong(millisecond));
} }
final DateBuilder dateBuilder = DateBuilder.of();
// year
Opt.ofNullable(ReUtil.group(matcher, "year")).ifPresent((year) -> dateBuilder.setYear(parseYear(year)));
// month
Opt.ofNullable(ReUtil.group(matcher, "month")).ifPresent((month) -> dateBuilder.setMonth(parseMonth(month)));
// week
Opt.ofNullable(ReUtil.group(matcher, "week")).ifPresent((week) -> dateBuilder.setWeek(parseWeek(week)));
// day
Opt.ofNullable(ReUtil.group(matcher, "day")).ifPresent((day) -> dateBuilder.setDay(parseNumberLimit(day, 1, 31)));
// hour
Opt.ofNullable(ReUtil.group(matcher, "hour")).ifPresent((hour) -> dateBuilder.setHour(parseNumberLimit(hour, 0, 23)));
// minute
Opt.ofNullable(ReUtil.group(matcher, "minute")).ifPresent((minute) -> dateBuilder.setMinute(parseNumberLimit(minute, 0, 59)));
// second
Opt.ofNullable(ReUtil.group(matcher, "second")).ifPresent((second) -> dateBuilder.setSecond(parseNumberLimit(second, 0, 59)));
// ns
Opt.ofNullable(ReUtil.group(matcher, "ns")).ifPresent((ns) -> dateBuilder.setNs(parseNano(ns)));
// am or pm
Opt.ofNullable(ReUtil.group(matcher, "m")).ifPresent((m) -> {
if ('p' == m.charAt(0)) {
dateBuilder.setPm(true);
} else {
dateBuilder.setAm(true);
}
});
// zero zone offset
Opt.ofNullable(ReUtil.group(matcher, "zero")).ifPresent((zero) -> {
dateBuilder.setZoneOffsetSetted(true);
dateBuilder.setZoneOffset(0);
});
// zone offset
Opt.ofNullable(ReUtil.group(matcher, "zoneOffset")).ifPresent((zoneOffset) -> {
dateBuilder.setZoneOffsetSetted(true);
dateBuilder.setZoneOffset(parseZoneOffset(zoneOffset));
});
// unix时间戳
Opt.ofNullable(ReUtil.group(matcher, "unixsecond")).ifPresent((unixsecond) -> {
dateBuilder.setUnixsecond(parseLong(unixsecond));
});
return dateBuilder.toDate(); return dateBuilder.toDate();
} }

View File

@ -2,8 +2,8 @@ package org.dromara.hutool.core.date.format.parser;
import org.dromara.hutool.core.collection.ListUtil; import org.dromara.hutool.core.collection.ListUtil;
import org.dromara.hutool.core.date.DateException; import org.dromara.hutool.core.date.DateException;
import org.dromara.hutool.core.date.format.DefaultDateBasic;
import java.io.Serializable;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@ -14,7 +14,7 @@ import java.util.List;
* @author looly * @author looly
* @since 6.0.0 * @since 6.0.0
*/ */
public class RegisterDateParser extends DefaultDateBasic implements DateParser { public class RegisterDateParser implements DateParser, Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**

View File

@ -15,11 +15,12 @@ package org.dromara.hutool.core.date.format.parser;
import org.dromara.hutool.core.date.DatePattern; import org.dromara.hutool.core.date.DatePattern;
import org.dromara.hutool.core.date.DateTime; import org.dromara.hutool.core.date.DateTime;
import org.dromara.hutool.core.date.DateUtil; import org.dromara.hutool.core.date.DateUtil;
import org.dromara.hutool.core.date.format.DefaultDateBasic;
import org.dromara.hutool.core.regex.PatternPool; import org.dromara.hutool.core.regex.PatternPool;
import org.dromara.hutool.core.regex.ReUtil; import org.dromara.hutool.core.regex.ReUtil;
import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.core.text.StrUtil;
import java.io.Serializable;
/** /**
* 时间日期字符串日期默认为当天支持格式类似于 * 时间日期字符串日期默认为当天支持格式类似于
* <pre> * <pre>
@ -30,7 +31,7 @@ import org.dromara.hutool.core.text.StrUtil;
* @author looly * @author looly
* @since 6.0.0 * @since 6.0.0
*/ */
public class TimeParser extends DefaultDateBasic implements PredicateDateParser { public class TimeParser implements PredicateDateParser, Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**