diff --git a/CHANGELOG.md b/CHANGELOG.md index b2e1d0ebd..ba932a47e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ------------------------------------------------------------------------------------------------------------- -## 5.3.11 (2020-07-30) +## 5.3.11 (2020-08-01) ### 新特性 * 【captcha】 AbstractCaptcha增加getImageBase64Data方法(pr#985@Github) @@ -11,6 +11,7 @@ * 【core 】 改进Img,目标图片类型未定义使用源图片类型(issue#I1PB0B@Gitee) * 【json 】 JSONConfig增加Transient选项(issue#I1PLHN@Gitee) * 【core 】 MapUtil增加getXXX的默认值重载(issue#I1PTGI@Gitee) +* 【core 】 CalendarUtil增加parseByPatterns方法(issue#993@Github) ### Bug修复 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 705b51670..6f0e4e268 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,13 +2,18 @@ package cn.hutool.core.date; import cn.hutool.core.comparator.CompareUtil; import cn.hutool.core.convert.NumberChineseFormatter; +import cn.hutool.core.date.format.FastDateParser; +import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; +import java.text.ParsePosition; import java.time.Instant; import java.time.LocalDateTime; import java.util.Calendar; import java.util.Date; import java.util.LinkedHashSet; +import java.util.Locale; +import java.util.TimeZone; /** * 针对{@link Calendar} 对象封装工具类 @@ -284,6 +289,27 @@ public class CalendarUtil { cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA); } + /** + *

检查两个Calendar时间戳是否相同。

+ * + *

此方法检查两个Calendar的毫秒数时间戳是否相同。

+ * + * @param date1 时间1 + * @param date2 时间2 + * @return 两个Calendar时间戳是否相同。如果两个时间都为{@code null}返回true,否则有{@code null}返回false + * @since 5.3.11 + */ + public static boolean isSameInstant(Calendar date1, Calendar date2) { + if (null == date1) { + return null == date2; + } + if (null == date2) { + return false; + } + + return date1.getTimeInMillis() == date2.getTimeInMillis(); + } + /** * 获得指定日期区间内的年份和季度
* @@ -401,18 +427,19 @@ public class CalendarUtil { * 2018-02-24 12:13:14转换为 二〇一八年二月二十四日(withTime为false) * 2018-02-24 12:13:14 转换为 二〇一八年二月二十四日一十二时一十三分一十四秒(withTime为true) * + * * @param calendar {@link Calendar} * @param withTime 是否包含时间部分 * @return 格式化后的字符串 * @since 5.3.9 */ - public static String formatChineseDate(Calendar calendar, boolean withTime){ + public static String formatChineseDate(Calendar calendar, boolean withTime) { final StringBuilder result = StrUtil.builder(); // 年 String year = String.valueOf(calendar.get(Calendar.YEAR)); final int length = year.length(); - for(int i = 0;i < length; i++){ + for (int i = 0; i < length; i++) { result.append(NumberChineseFormatter.numberCharToChinese(year.charAt(i), false)); } result.append('年'); @@ -427,7 +454,7 @@ public class CalendarUtil { result.append(NumberChineseFormatter.format(day, false)); result.append('日'); - if(withTime){ + if (withTime) { // 时 int hour = calendar.get(Calendar.HOUR_OF_DAY); result.append(NumberChineseFormatter.format(hour, false)); @@ -484,4 +511,79 @@ public class CalendarUtil { return age; } + + /** + * 通过给定的日期格式解析日期时间字符串。
+ * 传入的日期格式会逐个尝试,直到解析成功,返回{@link Calendar}对象,否则抛出{@link DateException}异常。 + * 方法来自:Apache Commons-Lang3 + * + * @param str 日期时间字符串,非空 + * @param parsePatterns 需要尝试的日期时间格式数组,非空, 见SimpleDateFormat + * @return 解析后的Calendar + * @throws IllegalArgumentException if the date string or pattern array is null + * @throws DateException if none of the date patterns were suitable + * @since 5.3.11 + */ + public static Calendar parseByPatterns(String str, String... parsePatterns) throws DateException { + return parseByPatterns(str, null, parsePatterns); + } + + /** + * 通过给定的日期格式解析日期时间字符串。
+ * 传入的日期格式会逐个尝试,直到解析成功,返回{@link Calendar}对象,否则抛出{@link DateException}异常。 + * 方法来自:Apache Commons-Lang3 + * + * @param str 日期时间字符串,非空 + * @param locale 地区,当为{@code null}时使用{@link Locale#getDefault()} + * @param parsePatterns 需要尝试的日期时间格式数组,非空, 见SimpleDateFormat + * @return 解析后的Calendar + * @throws IllegalArgumentException if the date string or pattern array is null + * @throws DateException if none of the date patterns were suitable + * @since 5.3.11 + */ + public static Calendar parseByPatterns(String str, Locale locale, String... parsePatterns) throws DateException { + return parseByPatterns(str, locale, true, parsePatterns); + } + + /** + * 通过给定的日期格式解析日期时间字符串。
+ * 传入的日期格式会逐个尝试,直到解析成功,返回{@link Calendar}对象,否则抛出{@link DateException}异常。 + * 方法来自:Apache Commons-Lang3 + * + * @param str 日期时间字符串,非空 + * @param locale 地区,当为{@code null}时使用{@link Locale#getDefault()} + * @param lenient 日期时间解析是否使用严格模式 + * @param parsePatterns 需要尝试的日期时间格式数组,非空, 见SimpleDateFormat + * @return 解析后的Calendar + * @throws IllegalArgumentException if the date string or pattern array is null + * @throws DateException if none of the date patterns were suitable + * @see java.util.Calendar#isLenient() + * @since 5.3.11 + */ + public static Calendar parseByPatterns(String str, Locale locale, boolean lenient, String... parsePatterns) throws DateException { + if (str == null || parsePatterns == null) { + throw new IllegalArgumentException("Date and Patterns must not be null"); + } + + final TimeZone tz = TimeZone.getDefault(); + final Locale lcl = ObjectUtil.defaultIfNull(locale, Locale.getDefault()); + final ParsePosition pos = new ParsePosition(0); + final Calendar calendar = Calendar.getInstance(tz, lcl); + calendar.setLenient(lenient); + + for (final String parsePattern : parsePatterns) { + final FastDateParser fdp = new FastDateParser(parsePattern, tz, lcl); + calendar.clear(); + try { + if (fdp.parse(str, pos, calendar) && pos.getIndex() == str.length()) { + return calendar; + } + } catch (final IllegalArgumentException ignore) { + // leniency is preventing calendar from being set + } + pos.setIndex(0); + } + + throw new DateException("Unable to parse the date: {}", str); + } } 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 ac725c4dc..a0feee3d4 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java @@ -722,6 +722,21 @@ public class DateUtil extends CalendarUtil { return new DateTime(dateStr, new SimpleDateFormat(format, locale)); } + /** + * 通过给定的日期格式解析日期时间字符串。
+ * 传入的日期格式会逐个尝试,直到解析成功,返回{@link DateTime}对象,否则抛出{@link DateException}异常。 + * + * @param str 日期时间字符串,非空 + * @param parsePatterns 需要尝试的日期时间格式数组,非空, 见SimpleDateFormat + * @return 解析后的Date + * @throws IllegalArgumentException if the date string or pattern array is null + * @throws DateException if none of the date patterns were suitable + * @since 5.3.11 + */ + public static DateTime parse(String str, String... parsePatterns) throws DateException { + return new DateTime(CalendarUtil.parseByPatterns(str, parsePatterns)); + } + /** * 解析日期时间字符串,格式支持: * @@ -1429,7 +1444,8 @@ public class DateUtil extends CalendarUtil { } /** - * 是否为相同时间 + * 是否为相同时间
+ * 此方法比较两个日期的时间戳是否相同 * * @param date1 日期1 * @param date2 日期2 @@ -1452,7 +1468,7 @@ public class DateUtil extends CalendarUtil { if (date1 == null || date2 == null) { throw new IllegalArgumentException("The date must not be null"); } - return isSameDay(calendar(date1), calendar(date2)); + return CalendarUtil.isSameDay(calendar(date1), calendar(date2)); } /** 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/FastDateParser.java index 751e71c0a..f5f4b5780 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/FastDateParser.java @@ -30,7 +30,7 @@ import java.util.regex.Pattern; * @see FastDatePrinter * @since 2.16.2 */ -class FastDateParser extends AbstractDateBasic implements DateParser { +public class FastDateParser extends AbstractDateBasic implements DateParser { private static final long serialVersionUID = -3199383897950947498L; static final Locale JAPANESE_IMPERIAL = new Locale("ja", "JP", "JP"); @@ -60,7 +60,7 @@ class FastDateParser extends AbstractDateBasic implements DateParser { * @param timeZone non-null time zone to use * @param locale non-null locale */ - protected FastDateParser(final String pattern, final TimeZone timeZone, final Locale locale) { + public FastDateParser(String pattern, TimeZone timeZone, Locale locale) { this(pattern, timeZone, locale, null); } @@ -74,7 +74,7 @@ class FastDateParser extends AbstractDateBasic implements DateParser { * @param locale non-null locale * @param centuryStart The start of the century for 2 digit year parsing */ - protected FastDateParser(final String pattern, final TimeZone timeZone, final Locale locale, final Date centuryStart) { + public FastDateParser(final String pattern, final TimeZone timeZone, final Locale locale, final Date centuryStart) { super(pattern, timeZone, locale); final Calendar definingCalendar = Calendar.getInstance(timeZone, locale); 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 00db5b766..895d9534b 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 @@ -18,10 +18,9 @@ import java.util.concurrent.ConcurrentMap; * {@link java.text.SimpleDateFormat} 的线程安全版本,用于将 {@link Date} 格式化输出
* Thanks to Apache Commons Lang 3.5 * - * @since 2.16.2 * @see FastDateParser */ -class FastDatePrinter extends AbstractDateBasic implements DatePrinter { +public class FastDatePrinter extends AbstractDateBasic implements DatePrinter { private static final long serialVersionUID = -6305750172255764887L; /** 规则列表. */ @@ -38,7 +37,7 @@ class FastDatePrinter extends AbstractDateBasic implements DatePrinter { * @param timeZone 非空时区{@link TimeZone} * @param locale 非空{@link Locale} 日期地理位置 */ - protected FastDatePrinter(final String pattern, final TimeZone timeZone, final Locale locale) { + public FastDatePrinter(final String pattern, final TimeZone timeZone, final Locale locale) { super(pattern, timeZone, locale); init(); }