Looly 5 years ago
parent
commit
db7c54bf69

+ 1 - 0
CHANGELOG.md

@@ -24,6 +24,7 @@
 * 【log    】     修复打印null对象显示{msg}异常问题(issue#1084@Github)
 * 【extra  】     修复ServletUtil.getReader中未关闭的问题
 * 【extra  】     修复QrCodeUtil在新版本zxing报错问题(issue#1088@Github)
+* 【core   】     修复LocalDateTimeUtil.parse无法解析yyyyMMddHHmmssSSS的bug(issue#1082@Github)
 
 -------------------------------------------------------------------------------------------------------------
 

+ 26 - 1
hutool-core/src/main/java/cn/hutool/core/date/LocalDateTimeUtil.java

@@ -1,6 +1,8 @@
 package cn.hutool.core.date;
 
 import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.ReUtil;
+import cn.hutool.core.util.StrUtil;
 
 import java.time.Duration;
 import java.time.Instant;
@@ -10,6 +12,7 @@ import java.time.LocalTime;
 import java.time.ZoneId;
 import java.time.ZonedDateTime;
 import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatterBuilder;
 import java.time.temporal.ChronoField;
 import java.time.temporal.TemporalAccessor;
 import java.time.temporal.TemporalUnit;
@@ -245,7 +248,29 @@ public class LocalDateTimeUtil {
 		if (null == text) {
 			return null;
 		}
-		return parse(text, DateTimeFormatter.ofPattern(format));
+
+		DateTimeFormatter formatter = null;
+		if(StrUtil.isNotBlank(format)){
+			// 修复yyyyMMddHHmmssSSS格式不能解析的问题
+			// fix issue#1082
+			//see https://stackoverflow.com/questions/22588051/is-java-time-failing-to-parse-fraction-of-second
+			// jdk8 bug at: https://bugs.openjdk.java.net/browse/JDK-8031085
+			if(StrUtil.startWithIgnoreEquals(format, DatePattern.PURE_DATETIME_PATTERN)){
+				final String fraction = StrUtil.removePrefix(format, DatePattern.PURE_DATETIME_PATTERN);
+				if(ReUtil.isMatch("[S]{1,2}", fraction)){
+					//将yyyyMMddHHmmssS、yyyyMMddHHmmssSS的日期统一替换为yyyyMMddHHmmssSSS格式,用0补
+					text += StrUtil.repeat('0', 3-fraction.length());
+				}
+				formatter = new DateTimeFormatterBuilder()
+						.appendPattern(DatePattern.PURE_DATETIME_PATTERN)
+						.appendValue(ChronoField.MILLI_OF_SECOND, 3)
+						.toFormatter();
+			} else{
+				formatter = DateTimeFormatter.ofPattern(format);
+			}
+		}
+
+		return parse(text, formatter);
 	}
 
 	/**

+ 41 - 5
hutool-core/src/main/java/cn/hutool/core/util/StrUtil.java

@@ -599,19 +599,44 @@ public class StrUtil {
 	 *
 	 * @param str          被监测字符串
 	 * @param prefix       开头字符串
-	 * @param isIgnoreCase 是否忽略大小写
+	 * @param ignoreCase 是否忽略大小写
 	 * @return 是否以指定字符串开头
+	 * @since 5.4.3
+	 */
+	public static boolean startWith(CharSequence str, CharSequence prefix, boolean ignoreCase) {
+		return startWith(str, prefix, ignoreCase, false);
+	}
+
+	/**
+	 * 是否以指定字符串开头<br>
+	 * 如果给定的字符串和开头字符串都为null则返回true,否则任意一个值为null返回false
+	 *
+	 * @param str          被监测字符串
+	 * @param prefix       开头字符串
+	 * @param ignoreCase 是否忽略大小写
+	 * @param ignoreEquals 是否忽略字符串相等的情况
+	 * @return 是否以指定字符串开头
+	 * @since 5.4.3
 	 */
-	public static boolean startWith(CharSequence str, CharSequence prefix, boolean isIgnoreCase) {
+	public static boolean startWith(CharSequence str, CharSequence prefix, boolean ignoreCase, boolean ignoreEquals) {
 		if (null == str || null == prefix) {
+			if(false == ignoreEquals){
+				return false;
+			}
 			return null == str && null == prefix;
 		}
 
-		if (isIgnoreCase) {
-			return str.toString().toLowerCase().startsWith(prefix.toString().toLowerCase());
+		boolean isStartWith;
+		if (ignoreCase) {
+			isStartWith = str.toString().toLowerCase().startsWith(prefix.toString().toLowerCase());
 		} else {
-			return str.toString().startsWith(prefix.toString());
+			isStartWith = str.toString().startsWith(prefix.toString());
 		}
+
+		if(isStartWith){
+			return (false == ignoreEquals) || (false == equals(str, prefix, ignoreCase));
+		}
+		return false;
 	}
 
 	/**
@@ -626,6 +651,17 @@ public class StrUtil {
 	}
 
 	/**
+	 * 是否以指定字符串开头,忽略相等字符串的情况
+	 *
+	 * @param str    被监测字符串
+	 * @param prefix 开头字符串
+	 * @return 是否以指定字符串开头并且两个字符串不相等
+	 */
+	public static boolean startWithIgnoreEquals(CharSequence str, CharSequence prefix) {
+		return startWith(str, prefix, false, true);
+	}
+
+	/**
 	 * 是否以指定字符串开头,忽略大小写
 	 *
 	 * @param str    被监测字符串

+ 18 - 0
hutool-core/src/test/java/cn/hutool/core/date/LocalDateTimeUtilTest.java

@@ -54,6 +54,24 @@ public class LocalDateTimeUtilTest {
 	}
 
 	@Test
+	public void parseTest5() {
+		LocalDateTime localDateTime = LocalDateTimeUtil.parse("19940121183604", "yyyyMMddHHmmss");
+		Assert.assertEquals("1994-01-21T18:36:04", localDateTime.toString());
+	}
+
+	@Test
+	public void parseTest6() {
+		LocalDateTime localDateTime = LocalDateTimeUtil.parse("19940121183604682", "yyyyMMddHHmmssSSS");
+		Assert.assertEquals("1994-01-21T18:36:04.682", localDateTime.toString());
+
+		localDateTime = LocalDateTimeUtil.parse("1994012118360468", "yyyyMMddHHmmssSS");
+		Assert.assertEquals("1994-01-21T18:36:04.680", localDateTime.toString());
+
+		localDateTime = LocalDateTimeUtil.parse("199401211836046", "yyyyMMddHHmmssS");
+		Assert.assertEquals("1994-01-21T18:36:04.600", localDateTime.toString());
+	}
+
+	@Test
 	public void parseDateTest() {
 		LocalDate localDate = LocalDateTimeUtil.parseDate("2020-01-23");
 		Assert.assertEquals("2020-01-23", localDate.toString());

+ 9 - 0
hutool-core/src/test/java/cn/hutool/core/util/StrUtilTest.java

@@ -456,4 +456,13 @@ public class StrUtilTest {
 		strings = StrUtil.wrapAllWithPair("`", StrUtil.splitToArray("1,2,3,4", ','));
 		Assert.assertEquals("[`1`, `2`, `3`, `4`]", StrUtil.utf8Str(strings));
 	}
+
+	@Test
+	public void startWithTest(){
+		String a = "123";
+		String b = "123";
+
+		Assert.assertTrue(StrUtil.startWith(a, b));
+		Assert.assertFalse(StrUtil.startWithIgnoreEquals(a, b));
+	}
 }