diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e0d1d1c3..07efc3863 100644 --- a/CHANGELOG.md +++ b/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) ------------------------------------------------------------------------------------------------------------- diff --git a/hutool-core/src/main/java/cn/hutool/core/date/LocalDateTimeUtil.java b/hutool-core/src/main/java/cn/hutool/core/date/LocalDateTimeUtil.java index 4b5c29eb1..c95540f9f 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/LocalDateTimeUtil.java +++ b/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); } /** diff --git a/hutool-core/src/main/java/cn/hutool/core/util/StrUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/StrUtil.java index 1aad6bea1..662ac844f 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/StrUtil.java +++ b/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 isIgnoreCase) { + public static boolean startWith(CharSequence str, CharSequence prefix, boolean ignoreCase) { + return startWith(str, prefix, ignoreCase, false); + } + + /** + * 是否以指定字符串开头
+ * 如果给定的字符串和开头字符串都为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 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; } /** @@ -625,6 +650,17 @@ public class StrUtil { return startWith(str, prefix, false); } + /** + * 是否以指定字符串开头,忽略相等字符串的情况 + * + * @param str 被监测字符串 + * @param prefix 开头字符串 + * @return 是否以指定字符串开头并且两个字符串不相等 + */ + public static boolean startWithIgnoreEquals(CharSequence str, CharSequence prefix) { + return startWith(str, prefix, false, true); + } + /** * 是否以指定字符串开头,忽略大小写 * diff --git a/hutool-core/src/test/java/cn/hutool/core/date/LocalDateTimeUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/date/LocalDateTimeUtilTest.java index aee6bd293..a8db0580a 100644 --- a/hutool-core/src/test/java/cn/hutool/core/date/LocalDateTimeUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/date/LocalDateTimeUtilTest.java @@ -53,6 +53,24 @@ public class LocalDateTimeUtilTest { Assert.assertEquals("2020-01-23T12:23:56", localDateTime.toString()); } + @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"); diff --git a/hutool-core/src/test/java/cn/hutool/core/util/StrUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/util/StrUtilTest.java index c66ce1dbe..5791433ff 100644 --- a/hutool-core/src/test/java/cn/hutool/core/util/StrUtilTest.java +++ b/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)); + } }