From 481281f7009a22eb0fb4a759b0e93a4df74c6630 Mon Sep 17 00:00:00 2001 From: Looly Date: Tue, 21 Jun 2022 19:52:56 +0800 Subject: [PATCH] fix code --- .../cn/hutool/core/date/CalendarUtil.java | 7 +- .../java/cn/hutool/core/date/DateTime.java | 11 +- .../java/cn/hutool/core/date/DateUtil.java | 220 +----------------- .../core/date/format/DefaultDateBasic.java | 34 +++ .../core/date/format/FastDateFormat.java | 4 +- .../core/date/format/FastDatePrinter.java | 3 +- ...actDateBasic.java => SimpleDateBasic.java} | 30 ++- .../date/format/parser/CSTDateParser.java | 26 +++ .../core/date/format/parser/DateParser.java | 35 +++ .../format/{ => parser}/FastDateParser.java | 8 +- .../date/format/parser/NormalDateParser.java | 54 +++++ .../format/parser/PatternsDateParser.java | 73 ++++++ .../PositionDateParser.java} | 40 +--- .../date/format/parser/PureDateParser.java | 41 ++++ .../core/date/format/parser/TimeParser.java | 34 +++ .../date/format/parser/UTCDateParser.java | 75 ++++++ .../core/date/format/parser/package-info.java | 7 + .../hutool/core/text/split/package-info.java | 6 + 18 files changed, 448 insertions(+), 260 deletions(-) create mode 100644 hutool-core/src/main/java/cn/hutool/core/date/format/DefaultDateBasic.java rename hutool-core/src/main/java/cn/hutool/core/date/format/{AbstractDateBasic.java => SimpleDateBasic.java} (68%) create mode 100644 hutool-core/src/main/java/cn/hutool/core/date/format/parser/CSTDateParser.java create mode 100644 hutool-core/src/main/java/cn/hutool/core/date/format/parser/DateParser.java rename hutool-core/src/main/java/cn/hutool/core/date/format/{ => parser}/FastDateParser.java (98%) create mode 100644 hutool-core/src/main/java/cn/hutool/core/date/format/parser/NormalDateParser.java create mode 100644 hutool-core/src/main/java/cn/hutool/core/date/format/parser/PatternsDateParser.java rename hutool-core/src/main/java/cn/hutool/core/date/format/{DateParser.java => parser/PositionDateParser.java} (56%) create mode 100644 hutool-core/src/main/java/cn/hutool/core/date/format/parser/PureDateParser.java create mode 100644 hutool-core/src/main/java/cn/hutool/core/date/format/parser/TimeParser.java create mode 100644 hutool-core/src/main/java/cn/hutool/core/date/format/parser/UTCDateParser.java create mode 100644 hutool-core/src/main/java/cn/hutool/core/date/format/parser/package-info.java create mode 100644 hutool-core/src/main/java/cn/hutool/core/text/split/package-info.java diff --git a/hutool-core/src/main/java/cn/hutool/core/date/CalendarUtil.java b/hutool-core/src/main/java/cn/hutool/core/date/CalendarUtil.java index 105be0cd9..107034c51 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/CalendarUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/CalendarUtil.java @@ -2,9 +2,10 @@ package cn.hutool.core.date; import cn.hutool.core.comparator.CompareUtil; import cn.hutool.core.convert.NumberChineseFormatter; -import cn.hutool.core.date.format.DateParser; -import cn.hutool.core.date.format.FastDateParser; +import cn.hutool.core.date.format.parser.DateParser; +import cn.hutool.core.date.format.parser.FastDateParser; import cn.hutool.core.date.format.GlobalCustomFormat; +import cn.hutool.core.date.format.parser.PositionDateParser; import cn.hutool.core.util.ObjUtil; import cn.hutool.core.text.StrUtil; @@ -758,7 +759,7 @@ public class CalendarUtil { * @return 解析后的 {@link Calendar},解析失败返回{@code null} * @since 5.7.14 */ - public static Calendar parse(final CharSequence str, final boolean lenient, final DateParser parser) { + public static Calendar parse(final CharSequence str, final boolean lenient, final PositionDateParser parser) { final Calendar calendar = Calendar.getInstance(parser.getTimeZone(), parser.getLocale()); calendar.clear(); calendar.setLenient(lenient); diff --git a/hutool-core/src/main/java/cn/hutool/core/date/DateTime.java b/hutool-core/src/main/java/cn/hutool/core/date/DateTime.java index 9a748656e..9178b4a34 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/DateTime.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/DateTime.java @@ -1,12 +1,13 @@ package cn.hutool.core.date; -import cn.hutool.core.date.format.DateParser; import cn.hutool.core.date.format.DatePrinter; import cn.hutool.core.date.format.FastDateFormat; import cn.hutool.core.date.format.GlobalCustomFormat; +import cn.hutool.core.date.format.parser.DateParser; +import cn.hutool.core.date.format.parser.PositionDateParser; import cn.hutool.core.lang.Assert; -import cn.hutool.core.util.ObjUtil; import cn.hutool.core.text.StrUtil; +import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.SystemUtil; import java.sql.Timestamp; @@ -310,7 +311,7 @@ public class DateTime extends Date { * @param dateParser 格式化器 {@link DateParser},可以使用 {@link FastDateFormat} * @see DatePattern */ - public DateTime(final CharSequence dateStr, final DateParser dateParser) { + public DateTime(final CharSequence dateStr, final PositionDateParser dateParser) { this(dateStr, dateParser, SystemUtil.getBoolean(SystemUtil.HUTOOL_DATE_LENIENT, true)); } @@ -322,7 +323,7 @@ public class DateTime extends Date { * @param lenient 是否宽容模式 * @see DatePattern */ - public DateTime(final CharSequence dateStr, final DateParser dateParser, final boolean lenient) { + public DateTime(final CharSequence dateStr, final PositionDateParser dateParser, final boolean lenient) { this(parse(dateStr, dateParser, lenient)); } @@ -1087,7 +1088,7 @@ public class DateTime extends Date { * @param lenient 是否宽容模式 * @return {@link Calendar} */ - private static Calendar parse(final CharSequence dateStr, final DateParser parser, final boolean lenient) { + private static Calendar parse(final CharSequence dateStr, final PositionDateParser parser, final boolean lenient) { Assert.notNull(parser, "Parser or DateFromat must be not null !"); Assert.notBlank(dateStr, "Date String must be not blank !"); diff --git a/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java b/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java index 2946f4a55..c5e69f613 100755 --- a/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java @@ -2,16 +2,20 @@ package cn.hutool.core.date; import cn.hutool.core.collection.ListUtil; import cn.hutool.core.comparator.CompareUtil; -import cn.hutool.core.date.format.DateParser; import cn.hutool.core.date.format.DatePrinter; import cn.hutool.core.date.format.FastDateFormat; import cn.hutool.core.date.format.GlobalCustomFormat; +import cn.hutool.core.date.format.parser.CSTDateParser; +import cn.hutool.core.date.format.parser.DateParser; +import cn.hutool.core.date.format.parser.NormalDateParser; +import cn.hutool.core.date.format.parser.PureDateParser; +import cn.hutool.core.date.format.parser.TimeParser; +import cn.hutool.core.date.format.parser.UTCDateParser; import cn.hutool.core.lang.Assert; import cn.hutool.core.math.NumberUtil; import cn.hutool.core.regex.PatternPool; import cn.hutool.core.regex.ReUtil; import cn.hutool.core.text.StrUtil; -import cn.hutool.core.util.CharUtil; import java.text.DateFormat; import java.text.SimpleDateFormat; @@ -656,28 +660,6 @@ public class DateUtil extends CalendarUtil { // ------------------------------------ Parse start ---------------------------------------------- - /** - * 构建LocalDateTime对象
- * 格式:yyyy-MM-dd HH:mm:ss - * - * @param dateStr 时间字符串(带格式) - * @return LocalDateTime对象 - */ - public static LocalDateTime parseLocalDateTime(final CharSequence dateStr) { - return parseLocalDateTime(dateStr, DatePattern.NORM_DATETIME_PATTERN); - } - - /** - * 构建LocalDateTime对象 - * - * @param dateStr 时间字符串(带格式) - * @param format 使用{@link DatePattern}定义的格式 - * @return LocalDateTime对象 - */ - public static LocalDateTime parseLocalDateTime(final CharSequence dateStr, final String format) { - return TimeUtil.parse(dateStr, format); - } - /** * 构建DateTime对象 * @@ -765,154 +747,7 @@ public class DateUtil extends CalendarUtil { * @since 5.3.11 */ public static DateTime parse(final String str, final String... parsePatterns) throws DateException { - return new DateTime(CalendarUtil.parseByPatterns(str, parsePatterns)); - } - - /** - * 解析日期时间字符串,格式支持: - * - *
-	 * yyyy-MM-dd HH:mm:ss
-	 * yyyy/MM/dd HH:mm:ss
-	 * yyyy.MM.dd HH:mm:ss
-	 * yyyy年MM月dd日 HH:mm:ss
-	 * 
- * - * @param dateString 标准形式的时间字符串 - * @return 日期对象 - */ - public static DateTime parseDateTime(CharSequence dateString) { - dateString = normalize(dateString); - return parse(dateString, DatePattern.NORM_DATETIME_FORMAT); - } - - /** - * 解析日期字符串,忽略时分秒,支持的格式包括: - *
-	 * yyyy-MM-dd
-	 * yyyy/MM/dd
-	 * yyyy.MM.dd
-	 * yyyy年MM月dd日
-	 * 
- * - * @param dateString 标准形式的日期字符串 - * @return 日期对象 - */ - public static DateTime parseDate(CharSequence dateString) { - dateString = normalize(dateString); - return parse(dateString, DatePattern.NORM_DATE_FORMAT); - } - - /** - * 解析时间,格式HH:mm:ss,日期部分默认为1970-01-01 - * - * @param timeString 标准形式的日期字符串 - * @return 日期对象 - */ - public static DateTime parseTime(CharSequence timeString) { - timeString = normalize(timeString); - return parse(timeString, DatePattern.NORM_TIME_FORMAT); - } - - /** - * 解析时间,格式HH:mm 或 HH:mm:ss,日期默认为今天 - * - * @param timeString 标准形式的日期字符串 - * @return 日期对象 - * @since 3.1.1 - */ - public static DateTime parseTimeToday(CharSequence timeString) { - timeString = StrUtil.format("{} {}", formatToday(), timeString); - if (1 == StrUtil.count(timeString, ':')) { - // 时间格式为 HH:mm - return parse(timeString, DatePattern.NORM_DATETIME_MINUTE_PATTERN); - } else { - // 时间格式为 HH:mm:ss - return parse(timeString, DatePattern.NORM_DATETIME_FORMAT); - } - } - - /** - * 解析UTC时间,格式:
- *
    - *
  1. yyyy-MM-dd'T'HH:mm:ss'Z'
  2. - *
  3. yyyy-MM-dd'T'HH:mm:ss.SSS'Z'
  4. - *
  5. yyyy-MM-dd'T'HH:mm:ssZ
  6. - *
  7. yyyy-MM-dd'T'HH:mm:ss.SSSZ
  8. - *
  9. yyyy-MM-dd'T'HH:mm:ss+0800
  10. - *
  11. yyyy-MM-dd'T'HH:mm:ss+08:00
  12. - *
- * - * @param utcString UTC时间 - * @return 日期对象 - * @since 4.1.14 - */ - public static DateTime parseUTC(String utcString) { - if (utcString == null) { - return null; - } - final int length = utcString.length(); - if (StrUtil.contains(utcString, 'Z')) { - if (length == DatePattern.UTC_PATTERN.length() - 4) { - // 格式类似:2018-09-13T05:34:31Z,-4表示减去4个单引号的长度 - return parse(utcString, DatePattern.UTC_FORMAT); - } - - final int patternLength = DatePattern.UTC_MS_PATTERN.length(); - // 格式类似:2018-09-13T05:34:31.999Z,-4表示减去4个单引号的长度 - // -4 ~ -6范围表示匹配毫秒1~3位的情况 - if (length <= patternLength - 4 && length >= patternLength - 6) { - return parse(utcString, DatePattern.UTC_MS_FORMAT); - } - } else if (StrUtil.contains(utcString, '+')) { - // 去除类似2019-06-01T19:45:43 +08:00加号前的空格 - utcString = utcString.replace(" +", "+"); - final String zoneOffset = StrUtil.subAfter(utcString, '+', true); - if (StrUtil.isBlank(zoneOffset)) { - throw new DateException("Invalid format: [{}]", utcString); - } - if (false == StrUtil.contains(zoneOffset, ':')) { - // +0800转换为+08:00 - final String pre = StrUtil.subBefore(utcString, '+', true); - utcString = pre + "+" + zoneOffset.substring(0, 2) + ":" + "00"; - } - - if (StrUtil.contains(utcString, CharUtil.DOT)) { - // 带毫秒,格式类似:2018-09-13T05:34:31.999+08:00 - return parse(utcString, DatePattern.UTC_MS_WITH_XXX_OFFSET_FORMAT); - } else { - // 格式类似:2018-09-13T05:34:31+08:00 - return parse(utcString, DatePattern.UTC_WITH_XXX_OFFSET_FORMAT); - } - } else { - if (length == DatePattern.UTC_SIMPLE_PATTERN.length() - 2) { - // 格式类似:2018-09-13T05:34:31 - return parse(utcString, DatePattern.UTC_SIMPLE_FORMAT); - } else if (StrUtil.contains(utcString, CharUtil.DOT)) { - // 可能为: 2021-03-17T06:31:33.99 - return parse(utcString, DatePattern.UTC_SIMPLE_MS_FORMAT); - } - } - // 没有更多匹配的时间格式 - throw new DateException("No format fit for date String [{}] !", utcString); - } - - /** - * 解析CST时间,格式:
- *
    - *
  1. EEE MMM dd HH:mm:ss z yyyy(例如:Wed Aug 01 00:00:00 CST 2012)
  2. - *
- * - * @param cstString UTC时间 - * @return 日期对象 - * @since 4.6.9 - */ - public static DateTime parseCST(final CharSequence cstString) { - if (cstString == null) { - return null; - } - - return parse(cstString, DatePattern.JDK_DATETIME_FORMAT); + return date(CalendarUtil.parseByPatterns(str, parsePatterns)); } /** @@ -951,64 +786,33 @@ public class DateUtil extends CalendarUtil { String dateStr = dateCharSequence.toString(); // 去掉两边空格并去掉中文日期中的“日”和“秒”,以规范长度 dateStr = StrUtil.removeAll(dateStr.trim(), '日', '秒'); - final int length = dateStr.length(); if (NumberUtil.isNumber(dateStr)) { // 纯数字形式 - if (length == DatePattern.PURE_DATETIME_PATTERN.length()) { - return parse(dateStr, DatePattern.PURE_DATETIME_FORMAT); - } else if (length == DatePattern.PURE_DATETIME_MS_PATTERN.length()) { - return parse(dateStr, DatePattern.PURE_DATETIME_MS_FORMAT); - } else if (length == DatePattern.PURE_DATE_PATTERN.length()) { - return parse(dateStr, DatePattern.PURE_DATE_FORMAT); - } else if (length == DatePattern.PURE_TIME_PATTERN.length()) { - return parse(dateStr, DatePattern.PURE_TIME_FORMAT); - } + return PureDateParser.INSTANCE.parse(dateStr); } else if (ReUtil.isMatch(PatternPool.TIME, dateStr)) { // HH:mm:ss 或者 HH:mm 时间格式匹配单独解析 - return parseTimeToday(dateStr); + return TimeParser.INSTANCE.parse(dateStr); } else if (StrUtil.containsAnyIgnoreCase(dateStr, wtb)) { // JDK的Date对象toString默认格式,类似于: // Tue Jun 4 16:25:15 +0800 2019 // Thu May 16 17:57:18 GMT+08:00 2019 // Wed Aug 01 00:00:00 CST 2012 - return parseCST(dateStr); + return CSTDateParser.INSTANCE.parse(dateStr); } else if (StrUtil.contains(dateStr, 'T')) { // UTC时间 - return parseUTC(dateStr); + return UTCDateParser.INSTANCE.parse(dateStr); } //标准日期格式(包括单个数字的日期时间) dateStr = normalize(dateStr); if (ReUtil.isMatch(DatePattern.REGEX_NORM, dateStr)) { - final int colonCount = StrUtil.count(dateStr, CharUtil.COLON); - switch (colonCount) { - case 0: - // yyyy-MM-dd - return parse(dateStr, DatePattern.NORM_DATE_FORMAT); - case 1: - // yyyy-MM-dd HH:mm - return parse(dateStr, DatePattern.NORM_DATETIME_MINUTE_FORMAT); - case 2: - final int indexOfDot = StrUtil.indexOf(dateStr, CharUtil.DOT); - if (indexOfDot > 0) { - final int length1 = dateStr.length(); - // yyyy-MM-dd HH:mm:ss.SSS 或者 yyyy-MM-dd HH:mm:ss.SSSSSS - if (length1 - indexOfDot > 4) { - // 类似yyyy-MM-dd HH:mm:ss.SSSSSS,采取截断操作 - dateStr = StrUtil.subPre(dateStr, indexOfDot + 4); - } - return parse(dateStr, DatePattern.NORM_DATETIME_MS_FORMAT); - } - // yyyy-MM-dd HH:mm:ss - return parse(dateStr, DatePattern.NORM_DATETIME_FORMAT); - } + return NormalDateParser.INSTANCE.parse(dateStr); } // 没有更多匹配的时间格式 throw new DateException("No format fit for date String [{}] !", dateStr); } - // ------------------------------------ Parse end ---------------------------------------------- // ------------------------------------ Offset start ---------------------------------------------- diff --git a/hutool-core/src/main/java/cn/hutool/core/date/format/DefaultDateBasic.java b/hutool-core/src/main/java/cn/hutool/core/date/format/DefaultDateBasic.java new file mode 100644 index 000000000..15e3fea38 --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/date/format/DefaultDateBasic.java @@ -0,0 +1,34 @@ +package cn.hutool.core.date.format; + +import java.io.Serializable; +import java.util.Locale; +import java.util.TimeZone; + +/** + * 默认日期基本信息类,包括: + * + * + * @author looly + */ +public class DefaultDateBasic implements DateBasic, Serializable { + private static final long serialVersionUID = 1L; + + @Override + public String getPattern() { + return null; + } + + @Override + public TimeZone getTimeZone() { + return TimeZone.getDefault(); + } + + @Override + public Locale getLocale() { + return Locale.getDefault(); + } +} diff --git a/hutool-core/src/main/java/cn/hutool/core/date/format/FastDateFormat.java b/hutool-core/src/main/java/cn/hutool/core/date/format/FastDateFormat.java index 088403d5d..43d8b855e 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/format/FastDateFormat.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/format/FastDateFormat.java @@ -1,6 +1,8 @@ package cn.hutool.core.date.format; import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.format.parser.FastDateParser; +import cn.hutool.core.date.format.parser.PositionDateParser; import java.text.DateFormat; import java.text.FieldPosition; @@ -29,7 +31,7 @@ import java.util.TimeZone; * Thanks to Apache Commons Lang 3.5 * @since 2.16.2 */ -public class FastDateFormat extends Format implements DateParser, DatePrinter { +public class FastDateFormat extends Format implements PositionDateParser, DatePrinter { private static final long serialVersionUID = 8097890768636183236L; /** FULL locale dependent date or time style. */ diff --git a/hutool-core/src/main/java/cn/hutool/core/date/format/FastDatePrinter.java b/hutool-core/src/main/java/cn/hutool/core/date/format/FastDatePrinter.java index b69e32b86..7b7dbd518 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/format/FastDatePrinter.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/format/FastDatePrinter.java @@ -1,6 +1,7 @@ package cn.hutool.core.date.format; import cn.hutool.core.date.DateException; +import cn.hutool.core.date.format.parser.FastDateParser; import java.io.IOException; import java.io.ObjectInputStream; @@ -20,7 +21,7 @@ import java.util.concurrent.ConcurrentMap; * * @see FastDateParser */ -public class FastDatePrinter extends AbstractDateBasic implements DatePrinter { +public class FastDatePrinter extends SimpleDateBasic implements DatePrinter { private static final long serialVersionUID = -6305750172255764887L; /** 规则列表. */ diff --git a/hutool-core/src/main/java/cn/hutool/core/date/format/AbstractDateBasic.java b/hutool-core/src/main/java/cn/hutool/core/date/format/SimpleDateBasic.java similarity index 68% rename from hutool-core/src/main/java/cn/hutool/core/date/format/AbstractDateBasic.java rename to hutool-core/src/main/java/cn/hutool/core/date/format/SimpleDateBasic.java index 889ea7006..df3fc92ca 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/format/AbstractDateBasic.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/format/SimpleDateBasic.java @@ -4,23 +4,35 @@ import java.io.Serializable; import java.util.Locale; import java.util.TimeZone; -public abstract class AbstractDateBasic implements DateBasic, Serializable { +/** + * 抽象日期基本信息类,包括日期格式、时区、本地化等信息 + * + * @author looly + */ +public class SimpleDateBasic implements DateBasic, Serializable { private static final long serialVersionUID = 6333136319870641818L; - /** The pattern */ - protected final String pattern; - /** The time zone. */ + /** + * The pattern + */ + protected final String pattern; + /** + * The time zone. + */ protected final TimeZone timeZone; - /** The locale. */ + /** + * The locale. + */ protected final Locale locale; /** * 构造,内部使用 - * @param pattern 使用{@link java.text.SimpleDateFormat} 相同的日期格式 + * + * @param pattern 使用{@link java.text.SimpleDateFormat} 相同的日期格式 * @param timeZone 非空时区{@link TimeZone} - * @param locale 非空{@link Locale} 日期地理位置 + * @param locale 非空{@link Locale} 日期地理位置 */ - protected AbstractDateBasic(final String pattern, final TimeZone timeZone, final Locale locale) { + protected SimpleDateBasic(final String pattern, final TimeZone timeZone, final Locale locale) { this.pattern = pattern; this.timeZone = timeZone; this.locale = locale; @@ -48,7 +60,7 @@ public abstract class AbstractDateBasic implements DateBasic, Serializable { if (obj instanceof FastDatePrinter == false) { return false; } - final AbstractDateBasic other = (AbstractDateBasic) obj; + final SimpleDateBasic other = (SimpleDateBasic) obj; return pattern.equals(other.pattern) && timeZone.equals(other.timeZone) && locale.equals(other.locale); } diff --git a/hutool-core/src/main/java/cn/hutool/core/date/format/parser/CSTDateParser.java b/hutool-core/src/main/java/cn/hutool/core/date/format/parser/CSTDateParser.java new file mode 100644 index 000000000..dbe94f8ed --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/date/format/parser/CSTDateParser.java @@ -0,0 +1,26 @@ +package cn.hutool.core.date.format.parser; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.format.DefaultDateBasic; + +/** + * CST日期字符串(JDK的Date对象toString默认格式)解析,支持格式类似于; + *
+ *   Tue Jun 4 16:25:15 +0800 2019
+ *   Thu May 16 17:57:18 GMT+08:00 2019
+ *   Wed Aug 01 00:00:00 CST 2012
+ * 
+ * + * @author looly + * @since 6.0.0 + */ +public class CSTDateParser extends DefaultDateBasic implements DateParser { + + public static CSTDateParser INSTANCE = new CSTDateParser(); + + @Override + public DateTime parse(final String source) { + return new DateTime(source, DatePattern.JDK_DATETIME_FORMAT); + } +} diff --git a/hutool-core/src/main/java/cn/hutool/core/date/format/parser/DateParser.java b/hutool-core/src/main/java/cn/hutool/core/date/format/parser/DateParser.java new file mode 100644 index 000000000..189be48e4 --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/date/format/parser/DateParser.java @@ -0,0 +1,35 @@ +package cn.hutool.core.date.format.parser; + +import cn.hutool.core.date.format.DateBasic; + +import java.text.ParseException; +import java.util.Date; + +/** + * 日期解析接口,用于解析日期字符串为 {@link Date} 对象
+ * Thanks to Apache Commons Lang 3.5 + */ +public interface DateParser extends DateBasic { + + /** + * 将日期字符串解析并转换为 {@link Date} 对象
+ * 等价于 {@link java.text.DateFormat#parse(String)} + * + * @param source 被解析的日期字符串 + * @return {@link Date}对象 + * @throws ParseException 转换异常,被转换的字符串格式错误。 + */ + Date parse(String source) throws ParseException; + + /** + * 将日期字符串解析并转换为 {@link Date} 对象
+ * + * @param source 被解析的日期字符串 + * @return {@link Date}对象 + * @throws ParseException if the beginning of the specified string cannot be parsed. + * @see java.text.DateFormat#parseObject(String) + */ + default Object parseObject(final String source) throws ParseException { + return parse(source); + } +} diff --git a/hutool-core/src/main/java/cn/hutool/core/date/format/FastDateParser.java b/hutool-core/src/main/java/cn/hutool/core/date/format/parser/FastDateParser.java similarity index 98% rename from hutool-core/src/main/java/cn/hutool/core/date/format/FastDateParser.java rename to hutool-core/src/main/java/cn/hutool/core/date/format/parser/FastDateParser.java index cc4ccff59..b4b38bb8f 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/format/FastDateParser.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/format/parser/FastDateParser.java @@ -1,4 +1,8 @@ -package cn.hutool.core.date.format; +package cn.hutool.core.date.format.parser; + +import cn.hutool.core.date.format.FastDateFormat; +import cn.hutool.core.date.format.FastDatePrinter; +import cn.hutool.core.date.format.SimpleDateBasic; import java.io.IOException; import java.io.ObjectInputStream; @@ -30,7 +34,7 @@ import java.util.regex.Pattern; * @see FastDatePrinter * @since 2.16.2 */ -public class FastDateParser extends AbstractDateBasic implements DateParser { +public class FastDateParser extends SimpleDateBasic implements PositionDateParser { private static final long serialVersionUID = -3199383897950947498L; static final Locale JAPANESE_IMPERIAL = new Locale("ja", "JP", "JP"); diff --git a/hutool-core/src/main/java/cn/hutool/core/date/format/parser/NormalDateParser.java b/hutool-core/src/main/java/cn/hutool/core/date/format/parser/NormalDateParser.java new file mode 100644 index 000000000..f090b86ac --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/date/format/parser/NormalDateParser.java @@ -0,0 +1,54 @@ +package cn.hutool.core.date.format.parser; + +import cn.hutool.core.date.DateException; +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.format.DefaultDateBasic; +import cn.hutool.core.text.StrUtil; +import cn.hutool.core.util.CharUtil; + +/** + * 标准日期字符串解析,支持格式; + *
+ *     yyyy-MM-dd HH:mm:ss.SSSSSS
+ *     yyyy-MM-dd HH:mm:ss.SSS
+ *     yyyy-MM-dd HH:mm:ss
+ *     yyyy-MM-dd HH:mm
+ *     yyyy-MM-dd
+ * 
+ * + * @author looly + * @since 6.0.0 + */ +public class NormalDateParser extends DefaultDateBasic implements DateParser { + + public static NormalDateParser INSTANCE = new NormalDateParser(); + + @Override + public DateTime parse(String source) { + final int colonCount = StrUtil.count(source, CharUtil.COLON); + switch (colonCount) { + case 0: + // yyyy-MM-dd + return new DateTime(source, DatePattern.NORM_DATE_FORMAT); + case 1: + // yyyy-MM-dd HH:mm + return new DateTime(source, DatePattern.NORM_DATETIME_MINUTE_FORMAT); + case 2: + final int indexOfDot = StrUtil.indexOf(source, CharUtil.DOT); + if (indexOfDot > 0) { + final int length1 = source.length(); + // yyyy-MM-dd HH:mm:ss.SSS 或者 yyyy-MM-dd HH:mm:ss.SSSSSS + if (length1 - indexOfDot > 4) { + // 类似yyyy-MM-dd HH:mm:ss.SSSSSS,采取截断操作 + source = StrUtil.subPre(source, indexOfDot + 4); + } + return new DateTime(source, DatePattern.NORM_DATETIME_MS_FORMAT); + } + // yyyy-MM-dd HH:mm:ss + return new DateTime(source, DatePattern.NORM_DATETIME_FORMAT); + } + + throw new DateException("No format fit for date String [{}] !", source); + } +} diff --git a/hutool-core/src/main/java/cn/hutool/core/date/format/parser/PatternsDateParser.java b/hutool-core/src/main/java/cn/hutool/core/date/format/parser/PatternsDateParser.java new file mode 100644 index 000000000..c4332a60b --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/date/format/parser/PatternsDateParser.java @@ -0,0 +1,73 @@ +package cn.hutool.core.date.format.parser; + +import cn.hutool.core.date.CalendarUtil; +import cn.hutool.core.date.DateException; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.format.DefaultDateBasic; + +import java.util.Calendar; +import java.util.Locale; + +/** + * 通过给定的日期格式解析日期时间字符串。
+ * 传入的日期格式会逐个尝试,直到解析成功,返回{@link Calendar}对象,否则抛出{@link DateException}异常。 + * + * @author looly + * @since 6.0.0 + */ +public class PatternsDateParser extends DefaultDateBasic implements DateParser { + + /** + * 创建 PatternsDateParser + * + * @param parsePatterns 多个日期格式 + * @return PatternsDateParser + */ + public static PatternsDateParser of(final String... parsePatterns) { + return new PatternsDateParser(parsePatterns); + } + + private String[] parsePatterns; + private Locale locale; + + /** + * 构造 + * + * @param parsePatterns 多个日期格式 + */ + public PatternsDateParser(final String... parsePatterns) { + this.parsePatterns = parsePatterns; + } + + /** + * 设置多个日期格式 + * + * @param parsePatterns 日期格式列表 + * @return this + */ + public PatternsDateParser setParsePatterns(final String... parsePatterns) { + this.parsePatterns = parsePatterns; + return this; + } + + /** + * 设置{@link Locale} + * + * @param locale {@link Locale} + * @return this + */ + public PatternsDateParser setLocale(final Locale locale) { + this.locale = locale; + return this; + } + + @Override + public Locale getLocale() { + return locale; + } + + @Override + public DateTime parse(final String source) { + return new DateTime(CalendarUtil.parseByPatterns(source, this.locale, this.parsePatterns)); + } +} diff --git a/hutool-core/src/main/java/cn/hutool/core/date/format/DateParser.java b/hutool-core/src/main/java/cn/hutool/core/date/format/parser/PositionDateParser.java similarity index 56% rename from hutool-core/src/main/java/cn/hutool/core/date/format/DateParser.java rename to hutool-core/src/main/java/cn/hutool/core/date/format/parser/PositionDateParser.java index 998b38dc4..62fbcfc89 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/format/DateParser.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/format/parser/PositionDateParser.java @@ -1,33 +1,23 @@ -package cn.hutool.core.date.format; +package cn.hutool.core.date.format.parser; -import java.text.ParseException; import java.text.ParsePosition; import java.util.Calendar; import java.util.Date; /** - * 日期解析接口,用于解析日期字符串为 {@link Date} 对象
+ * 带有{@link ParsePosition}的日期解析接口,用于解析日期字符串为 {@link Date} 对象
* Thanks to Apache Commons Lang 3.5 + * * @since 2.16.2 */ -public interface DateParser extends DateBasic{ - - /** - * 将日期字符串解析并转换为 {@link Date} 对象
- * 等价于 {@link java.text.DateFormat#parse(String)} - * - * @param source 日期字符串 - * @return {@link Date} - * @throws ParseException 转换异常,被转换的字符串格式错误。 - */ - Date parse(String source) throws ParseException; +public interface PositionDateParser extends DateParser { /** * 将日期字符串解析并转换为 {@link Date} 对象
* 等价于 {@link java.text.DateFormat#parse(String, ParsePosition)} * * @param source 日期字符串 - * @param pos {@link ParsePosition} + * @param pos {@link ParsePosition} * @return {@link Date} */ Date parse(String source, ParsePosition pos); @@ -38,35 +28,23 @@ public interface DateParser extends DateBasic{ * Not all source text needs to be consumed. * 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 pos 定义开始转换的位置,转换结束后更新转换到的位置 + * @param source 被转换的日期字符串 + * @param pos 定义开始转换的位置,转换结束后更新转换到的位置 * @param calendar The calendar into which to set parsed fields. * @return true, if source has been parsed (pos parsePosition is updated); otherwise false (and pos errorIndex is updated) * @throws IllegalArgumentException when Calendar has been set to be not lenient, and a parsed field is out of range. */ boolean parse(String source, ParsePosition pos, Calendar calendar); - /** - * 将日期字符串解析并转换为 {@link Date} 对象
- * - * @param source A {@code String} whose beginning should be parsed. - * @return a {@code java.util.Date} object - * @throws ParseException if the beginning of the specified string cannot be parsed. - * @see java.text.DateFormat#parseObject(String) - */ - default Object parseObject(final String source) throws ParseException{ - return parse(source); - } - /** * 根据 {@link ParsePosition} 给定将日期字符串解析并转换为 {@link Date} 对象
* * @param source A {@code String} whose beginning should be parsed. - * @param pos the parse position + * @param pos the parse position * @return a {@code java.util.Date} object * @see java.text.DateFormat#parseObject(String, ParsePosition) */ - default Object parseObject(final String source, final ParsePosition pos){ + default Object parseObject(final String source, final ParsePosition pos) { return parse(source, pos); } } diff --git a/hutool-core/src/main/java/cn/hutool/core/date/format/parser/PureDateParser.java b/hutool-core/src/main/java/cn/hutool/core/date/format/parser/PureDateParser.java new file mode 100644 index 000000000..e5dd0f30e --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/date/format/parser/PureDateParser.java @@ -0,0 +1,41 @@ +package cn.hutool.core.date.format.parser; + +import cn.hutool.core.date.DateException; +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.format.DefaultDateBasic; + +/** + * 纯数字的日期字符串解析,支持格式包括; + * + * + * @author looly + * @since 6.0.0 + */ +public class PureDateParser extends DefaultDateBasic implements DateParser { + + public static PureDateParser INSTANCE = new PureDateParser(); + + @Override + public DateTime parse(final String source) throws DateException { + final int length = source.length(); + // 纯数字形式 + if (length == DatePattern.PURE_DATETIME_PATTERN.length()) { + return new DateTime(source, DatePattern.PURE_DATETIME_FORMAT); + } else if (length == DatePattern.PURE_DATETIME_MS_PATTERN.length()) { + return new DateTime(source, DatePattern.PURE_DATETIME_MS_FORMAT); + } else if (length == DatePattern.PURE_DATE_PATTERN.length()) { + return new DateTime(source, DatePattern.PURE_DATE_FORMAT); + } else if (length == DatePattern.PURE_TIME_PATTERN.length()) { + return new DateTime(source, DatePattern.PURE_TIME_FORMAT); + } + + throw new DateException("No pure format fit for date String [{}] !", source); + } + +} diff --git a/hutool-core/src/main/java/cn/hutool/core/date/format/parser/TimeParser.java b/hutool-core/src/main/java/cn/hutool/core/date/format/parser/TimeParser.java new file mode 100644 index 000000000..c8aec9a26 --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/date/format/parser/TimeParser.java @@ -0,0 +1,34 @@ +package cn.hutool.core.date.format.parser; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.date.format.DefaultDateBasic; +import cn.hutool.core.text.StrUtil; + +/** + * 时间日期字符串,日期默认为当天,支持格式类似于; + *
+ *   HH:mm:ss
+ *   HH:mm
+ * 
+ * + * @author looly + * @since 6.0.0 + */ +public class TimeParser extends DefaultDateBasic implements DateParser { + + public static TimeParser INSTANCE = new TimeParser(); + + @Override + public DateTime parse(String source) { + source = StrUtil.format("{} {}", DateUtil.formatToday(), source); + if (1 == StrUtil.count(source, ':')) { + // 时间格式为 HH:mm + return new DateTime(source, DatePattern.NORM_DATETIME_MINUTE_PATTERN); + } else { + // 时间格式为 HH:mm:ss + return new DateTime(source, DatePattern.NORM_DATETIME_FORMAT); + } + } +} diff --git a/hutool-core/src/main/java/cn/hutool/core/date/format/parser/UTCDateParser.java b/hutool-core/src/main/java/cn/hutool/core/date/format/parser/UTCDateParser.java new file mode 100644 index 000000000..9403c858a --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/date/format/parser/UTCDateParser.java @@ -0,0 +1,75 @@ +package cn.hutool.core.date.format.parser; + +import cn.hutool.core.date.DateException; +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.format.DefaultDateBasic; +import cn.hutool.core.text.StrUtil; +import cn.hutool.core.util.CharUtil; + +/** + * UTC日期字符串(JDK的Date对象toString默认格式)解析,支持格式; + *
    + *
  1. yyyy-MM-dd'T'HH:mm:ss'Z'
  2. + *
  3. yyyy-MM-dd'T'HH:mm:ss.SSS'Z'
  4. + *
  5. yyyy-MM-dd'T'HH:mm:ssZ
  6. + *
  7. yyyy-MM-dd'T'HH:mm:ss.SSSZ
  8. + *
  9. yyyy-MM-dd'T'HH:mm:ss+0800
  10. + *
  11. yyyy-MM-dd'T'HH:mm:ss+08:00
  12. + *
+ * + * @author looly + * @since 6.0.0 + */ +public class UTCDateParser extends DefaultDateBasic implements DateParser { + + public static UTCDateParser INSTANCE = new UTCDateParser(); + + @Override + public DateTime parse(String source) { + final int length = source.length(); + if (StrUtil.contains(source, 'Z')) { + if (length == DatePattern.UTC_PATTERN.length() - 4) { + // 格式类似:2018-09-13T05:34:31Z,-4表示减去4个单引号的长度 + return new DateTime(source, DatePattern.UTC_FORMAT); + } + + final int patternLength = DatePattern.UTC_MS_PATTERN.length(); + // 格式类似:2018-09-13T05:34:31.999Z,-4表示减去4个单引号的长度 + // -4 ~ -6范围表示匹配毫秒1~3位的情况 + if (length <= patternLength - 4 && length >= patternLength - 6) { + return new DateTime(source, DatePattern.UTC_MS_FORMAT); + } + } else if (StrUtil.contains(source, '+')) { + // 去除类似2019-06-01T19:45:43 +08:00加号前的空格 + source = source.replace(" +", "+"); + final String zoneOffset = StrUtil.subAfter(source, '+', true); + if (StrUtil.isBlank(zoneOffset)) { + throw new DateException("Invalid format: [{}]", source); + } + if (false == StrUtil.contains(zoneOffset, ':')) { + // +0800转换为+08:00 + final String pre = StrUtil.subBefore(source, '+', true); + source = pre + "+" + zoneOffset.substring(0, 2) + ":" + "00"; + } + + if (StrUtil.contains(source, CharUtil.DOT)) { + // 带毫秒,格式类似:2018-09-13T05:34:31.999+08:00 + return new DateTime(source, DatePattern.UTC_MS_WITH_XXX_OFFSET_FORMAT); + } else { + // 格式类似:2018-09-13T05:34:31+08:00 + return new DateTime(source, DatePattern.UTC_WITH_XXX_OFFSET_FORMAT); + } + } else { + if (length == DatePattern.UTC_SIMPLE_PATTERN.length() - 2) { + // 格式类似:2018-09-13T05:34:31 + return new DateTime(source, DatePattern.UTC_SIMPLE_FORMAT); + } else if (StrUtil.contains(source, CharUtil.DOT)) { + // 可能为: 2021-03-17T06:31:33.99 + return new DateTime(source, DatePattern.UTC_SIMPLE_MS_FORMAT); + } + } + // 没有更多匹配的时间格式 + throw new DateException("No UTC format fit for date String [{}] !", source); + } +} diff --git a/hutool-core/src/main/java/cn/hutool/core/date/format/parser/package-info.java b/hutool-core/src/main/java/cn/hutool/core/date/format/parser/package-info.java new file mode 100644 index 000000000..e321b02af --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/date/format/parser/package-info.java @@ -0,0 +1,7 @@ +/** + * 提供日期解析相关封装 + * + * @author looly + * + */ +package cn.hutool.core.date.format.parser; diff --git a/hutool-core/src/main/java/cn/hutool/core/text/split/package-info.java b/hutool-core/src/main/java/cn/hutool/core/text/split/package-info.java new file mode 100644 index 000000000..cbda2abbf --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/text/split/package-info.java @@ -0,0 +1,6 @@ +/** + * 字符串切分封装和工具类 + * + * @author looly + */ +package cn.hutool.core.text.split;