Looly 5 年 前
コミット
4f94783fc1

+ 2 - 1
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修复
 

+ 105 - 3
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} 对象封装工具类
@@ -285,6 +290,27 @@ public class CalendarUtil {
 	}
 
 	/**
+	 * <p>检查两个Calendar时间戳是否相同。</p>
+	 *
+	 * <p>此方法检查两个Calendar的毫秒数时间戳是否相同。</p>
+	 *
+	 * @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();
+	}
+
+	/**
 	 * 获得指定日期区间内的年份和季度<br>
 	 *
 	 * @param startDate 起始日期(包含)
@@ -401,18 +427,19 @@ public class CalendarUtil {
 	 *     2018-02-24 12:13:14转换为 二〇一八年二月二十四日(withTime为false)
 	 *     2018-02-24 12:13:14 转换为 二〇一八年二月二十四日一十二时一十三分一十四秒(withTime为true)
 	 * </pre>
+	 *
 	 * @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;
 	}
+
+	/**
+	 * 通过给定的日期格式解析日期时间字符串。<br>
+	 * 传入的日期格式会逐个尝试,直到解析成功,返回{@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);
+	}
+
+	/**
+	 * 通过给定的日期格式解析日期时间字符串。<br>
+	 * 传入的日期格式会逐个尝试,直到解析成功,返回{@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);
+	}
+
+	/**
+	 * 通过给定的日期格式解析日期时间字符串。<br>
+	 * 传入的日期格式会逐个尝试,直到解析成功,返回{@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);
+	}
 }

+ 18 - 2
hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java

@@ -723,6 +723,21 @@ public class DateUtil extends CalendarUtil {
 	}
 
 	/**
+	 * 通过给定的日期格式解析日期时间字符串。<br>
+	 * 传入的日期格式会逐个尝试,直到解析成功,返回{@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));
+	}
+
+	/**
 	 * 解析日期时间字符串,格式支持:
 	 *
 	 * <pre>
@@ -1429,7 +1444,8 @@ public class DateUtil extends CalendarUtil {
 	}
 
 	/**
-	 * 是否为相同时间
+	 * 是否为相同时间<br>
+	 * 此方法比较两个日期的时间戳是否相同
 	 *
 	 * @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));
 	}
 
 	/**

+ 3 - 3
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);
 

+ 2 - 3
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} 格式化输出<br>
  * 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();
 	}