From 8ba988e028db18e04700afa73e8b66cc9e630ab8 Mon Sep 17 00:00:00 2001 From: Looly Date: Sun, 8 Mar 2020 09:55:31 +0800 Subject: [PATCH] fix FastDateParser --- CHANGELOG.md | 1 + .../cn/hutool/core/date/format/DateBasic.java | 1 + .../core/date/format/FastDateParser.java | 4 +- .../hutool/core/date/format/FormatCache.java | 80 +++---------------- .../main/java/cn/hutool/core/lang/Tuple.java | 32 ++++++-- .../cn/hutool/core/date/DateUtilTest.java | 28 +++++-- 6 files changed, 66 insertions(+), 80 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1466c14cd..c39170c2f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ ## 5.2.1 ### 新特性 +* 【core 】 修改FastDateParser策略,与JDK保持一致(issue#I1AXIN@Gitee) ### Bug修复 * 【setting】 修复Props.toBean方法null的问题 * 【core 】 修复DataUtil.parseLocalDateTime无时间部分报错问题(issue#I1B18H@Gitee) diff --git a/hutool-core/src/main/java/cn/hutool/core/date/format/DateBasic.java b/hutool-core/src/main/java/cn/hutool/core/date/format/DateBasic.java index 397a78664..8f8ee2118 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/format/DateBasic.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/format/DateBasic.java @@ -10,6 +10,7 @@ import java.util.TimeZone; * @since 2.16.2 */ public interface DateBasic { + /** * 获得日期格式化或者转换的格式 * 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 078cc24ab..751e71c0a 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 @@ -740,7 +740,9 @@ class FastDateParser extends AbstractDateBasic implements DateParser { } else { final TzInfo tzInfo = tzNames.get(value.toLowerCase(locale)); cal.set(Calendar.DST_OFFSET, tzInfo.dstOffset); - cal.set(Calendar.ZONE_OFFSET, tzInfo.zone.getRawOffset()); + //issue#I1AXIN@Gitee +// cal.set(Calendar.ZONE_OFFSET, tzInfo.zone.getRawOffset()); + cal.set(Calendar.ZONE_OFFSET, parser.getTimeZone().getRawOffset()); } } } diff --git a/hutool-core/src/main/java/cn/hutool/core/date/format/FormatCache.java b/hutool-core/src/main/java/cn/hutool/core/date/format/FormatCache.java index c6d344e15..456a4c170 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/format/FormatCache.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/format/FormatCache.java @@ -3,13 +3,13 @@ package cn.hutool.core.date.format; import java.text.DateFormat; import java.text.Format; import java.text.SimpleDateFormat; -import java.util.Arrays; import java.util.Locale; import java.util.TimeZone; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import cn.hutool.core.lang.Assert; +import cn.hutool.core.lang.Tuple; /** * 日期格式化器缓存
@@ -24,16 +24,16 @@ abstract class FormatCache { */ static final int NONE = -1; - private final ConcurrentMap cInstanceCache = new ConcurrentHashMap<>(7); + private final ConcurrentMap cInstanceCache = new ConcurrentHashMap<>(7); - private static final ConcurrentMap cDateTimeInstanceCache = new ConcurrentHashMap<>(7); + private static final ConcurrentMap cDateTimeInstanceCache = new ConcurrentHashMap<>(7); /** * 使用默认的pattern、timezone和locale获得缓存中的实例 * @return a date/time formatter */ public F getInstance() { - return getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, TimeZone.getDefault(), Locale.getDefault()); + return getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, null, null); } /** @@ -53,7 +53,7 @@ abstract class FormatCache { if (locale == null) { locale = Locale.getDefault(); } - final MultipartKey key = new MultipartKey(pattern, timeZone, locale); + final Tuple key = new Tuple(pattern, timeZone, locale); F format = cInstanceCache.get(key); if (format == null) { format = createInstance(pattern, timeZone, locale); @@ -129,7 +129,7 @@ abstract class FormatCache { */ // package protected, for access from FastDateFormat; do not make public or protected F getDateInstance(final int dateStyle, final TimeZone timeZone, final Locale locale) { - return getDateTimeInstance(Integer.valueOf(dateStyle), null, timeZone, locale); + return getDateTimeInstance(dateStyle, null, timeZone, locale); } /** @@ -145,7 +145,7 @@ abstract class FormatCache { */ // package protected, for access from FastDateFormat; do not make public or protected F getTimeInstance(final int timeStyle, final TimeZone timeZone, final Locale locale) { - return getDateTimeInstance(null, Integer.valueOf(timeStyle), timeZone, locale); + return getDateTimeInstance(null, timeStyle, timeZone, locale); } /** @@ -161,18 +161,18 @@ abstract class FormatCache { */ // package protected, for access from test code; do not make public or protected static String getPatternForStyle(final Integer dateStyle, final Integer timeStyle, final Locale locale) { - final MultipartKey key = new MultipartKey(dateStyle, timeStyle, locale); + final Tuple key = new Tuple(dateStyle, timeStyle, locale); String pattern = cDateTimeInstanceCache.get(key); if (pattern == null) { try { DateFormat formatter; if (dateStyle == null) { - formatter = DateFormat.getTimeInstance(timeStyle.intValue(), locale); + formatter = DateFormat.getTimeInstance(timeStyle, locale); } else if (timeStyle == null) { - formatter = DateFormat.getDateInstance(dateStyle.intValue(), locale); + formatter = DateFormat.getDateInstance(dateStyle, locale); } else { - formatter = DateFormat.getDateTimeInstance(dateStyle.intValue(), timeStyle.intValue(), locale); + formatter = DateFormat.getDateTimeInstance(dateStyle, timeStyle, locale); } pattern = ((SimpleDateFormat) formatter).toPattern(); final String previous = cDateTimeInstanceCache.putIfAbsent(key, pattern); @@ -188,62 +188,4 @@ abstract class FormatCache { } return pattern; } - - // ---------------------------------------------------------------------- - /** - *

- * Helper class to hold multi-part Map keys - *

- */ - private static class MultipartKey { - private final Object[] keys; - private int hashCode; - - /** - * Constructs an instance of MultipartKey to hold the specified objects. - * - * @param keys the set of objects that make up the key. Each key may be null. - */ - public MultipartKey(final Object... keys) { - this.keys = keys; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final MultipartKey other = (MultipartKey) obj; - return false != Arrays.equals(keys, other.keys); - } - - - - /** - * {@inheritDoc} - */ - @Override - public int hashCode() { - if (hashCode == 0) { - int rc = 0; - for (final Object key : keys) { - if (key != null) { - rc = rc * 7 + key.hashCode(); - } - } - hashCode = rc; - } - return hashCode; - } - } - } diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/Tuple.java b/hutool-core/src/main/java/cn/hutool/core/lang/Tuple.java index 95443af54..93039bea3 100644 --- a/hutool-core/src/main/java/cn/hutool/core/lang/Tuple.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/Tuple.java @@ -1,12 +1,12 @@ package cn.hutool.core.lang; +import cn.hutool.core.clone.CloneSupport; +import cn.hutool.core.collection.ArrayIter; + import java.io.Serializable; import java.util.Arrays; import java.util.Iterator; -import cn.hutool.core.clone.CloneSupport; -import cn.hutool.core.collection.ArrayIter; - /** * 不可变数组类型,用于多值返回
* 多值可以支持每个元素值类型不同 @@ -17,7 +17,9 @@ import cn.hutool.core.collection.ArrayIter; public class Tuple extends CloneSupport implements Iterable, Serializable{ private static final long serialVersionUID = -7689304393482182157L; - private Object[] members; + private final Object[] members; + private int hashCode; + private boolean cacheHash; /** * 构造 @@ -45,12 +47,31 @@ public class Tuple extends CloneSupport implements Iterable, Seri public Object[] getMembers(){ return this.members; } + + /** + * 缓存Hash值,当为true时,此对象的hash值只被计算一次,常用于Tuple中的值不变时使用。 + * 注意:当为true时,member变更对象后,hash值不会变更。 + * + * @param cacheHash 是否缓存hash值 + * @return this + * @since 5.2.1 + */ + public Tuple setCacheHash(boolean cacheHash){ + this.cacheHash = cacheHash; + return this; + } @Override public int hashCode() { + if(this.cacheHash && 0 != this.hashCode){ + return this.hashCode; + } final int prime = 31; int result = 1; result = prime * result + Arrays.deepHashCode(members); + if(this.cacheHash){ + this.hashCode = result; + } return result; } @@ -74,8 +95,9 @@ public class Tuple extends CloneSupport implements Iterable, Seri return Arrays.toString(members); } + @SuppressWarnings("NullableProblems") @Override public Iterator iterator() { - return new ArrayIter(members); + return new ArrayIter<>(members); } } diff --git a/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java index b0305d3e7..f71af6338 100644 --- a/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java @@ -2,6 +2,7 @@ package cn.hutool.core.date; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.BetweenFormater.Level; +import cn.hutool.core.date.format.FastDateFormat; import org.junit.Assert; import org.junit.Test; @@ -16,6 +17,7 @@ import java.util.Calendar; import java.util.Date; import java.util.LinkedHashSet; import java.util.List; +import java.util.Locale; import java.util.NoSuchElementException; import java.util.Objects; import java.util.TimeZone; @@ -505,23 +507,39 @@ public class DateUtilTest { Assert.assertEquals("2018-09-13 13:34:39.999", dateStr); } - @SuppressWarnings("ConstantConditions") @Test public void parseCSTTest(){ String dateStr = "Wed Sep 16 11:26:23 CST 2009"; + + SimpleDateFormat sdf = new SimpleDateFormat(DatePattern.JDK_DATETIME_PATTERN, Locale.US); + final DateTime parse = DateUtil.parse(dateStr, sdf); + DateTime dateTime = DateUtil.parseCST(dateStr); - Assert.assertEquals("2009-09-17 01:26:23", dateTime.toString()); + Assert.assertEquals(parse, dateTime); dateTime = DateUtil.parse(dateStr); - Assert.assertEquals("2009-09-17 01:26:23", dateTime.toString()); + Assert.assertEquals(parse, dateTime); + } + + @Test + public void parseCSTTest2(){ + String dateStr = "Wed Sep 16 11:26:23 CST 2009"; + + SimpleDateFormat sdf = new SimpleDateFormat(DatePattern.JDK_DATETIME_PATTERN, Locale.US); + sdf.setTimeZone(TimeZone.getTimeZone("America/Chicago")); + final DateTime parse = DateUtil.parse(dateStr, sdf); + + FastDateFormat fdf = FastDateFormat.getInstance(DatePattern.JDK_DATETIME_PATTERN, TimeZone.getTimeZone("America/Chicago"), Locale.US); + final DateTime parse2 = DateUtil.parse(dateStr, fdf); + + Assert.assertEquals(parse, parse2); } - @SuppressWarnings("ConstantConditions") @Test public void parseJDkTest() { String dateStr = "Thu May 16 17:57:18 GMT+08:00 2019"; DateTime time = DateUtil.parse(dateStr); - Assert.assertEquals("2019-05-16 17:57:18", time.toString()); + Assert.assertEquals("2019-05-16 17:57:18", Objects.requireNonNull(time).toString()); } @Test