mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-05-09 23:51:34 +08:00
fix FastDateParser
This commit is contained in:
parent
81dbc75ba3
commit
8ba988e028
@ -6,6 +6,7 @@
|
|||||||
## 5.2.1
|
## 5.2.1
|
||||||
|
|
||||||
### 新特性
|
### 新特性
|
||||||
|
* 【core 】 修改FastDateParser策略,与JDK保持一致(issue#I1AXIN@Gitee)
|
||||||
### Bug修复
|
### Bug修复
|
||||||
* 【setting】 修复Props.toBean方法null的问题
|
* 【setting】 修复Props.toBean方法null的问题
|
||||||
* 【core 】 修复DataUtil.parseLocalDateTime无时间部分报错问题(issue#I1B18H@Gitee)
|
* 【core 】 修复DataUtil.parseLocalDateTime无时间部分报错问题(issue#I1B18H@Gitee)
|
||||||
|
@ -10,6 +10,7 @@ import java.util.TimeZone;
|
|||||||
* @since 2.16.2
|
* @since 2.16.2
|
||||||
*/
|
*/
|
||||||
public interface DateBasic {
|
public interface DateBasic {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得日期格式化或者转换的格式
|
* 获得日期格式化或者转换的格式
|
||||||
*
|
*
|
||||||
|
@ -740,7 +740,9 @@ class FastDateParser extends AbstractDateBasic implements DateParser {
|
|||||||
} else {
|
} else {
|
||||||
final TzInfo tzInfo = tzNames.get(value.toLowerCase(locale));
|
final TzInfo tzInfo = tzNames.get(value.toLowerCase(locale));
|
||||||
cal.set(Calendar.DST_OFFSET, tzInfo.dstOffset);
|
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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,13 +3,13 @@ package cn.hutool.core.date.format;
|
|||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.text.Format;
|
import java.text.Format;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
|
||||||
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.lang.Assert;
|
||||||
|
import cn.hutool.core.lang.Tuple;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 日期格式化器缓存<br>
|
* 日期格式化器缓存<br>
|
||||||
@ -24,16 +24,16 @@ abstract class FormatCache<F extends Format> {
|
|||||||
*/
|
*/
|
||||||
static final int NONE = -1;
|
static final int NONE = -1;
|
||||||
|
|
||||||
private final ConcurrentMap<MultipartKey, F> cInstanceCache = new ConcurrentHashMap<>(7);
|
private final ConcurrentMap<Tuple, F> cInstanceCache = new ConcurrentHashMap<>(7);
|
||||||
|
|
||||||
private static final ConcurrentMap<MultipartKey, String> cDateTimeInstanceCache = new ConcurrentHashMap<>(7);
|
private static final ConcurrentMap<Tuple, String> cDateTimeInstanceCache = new ConcurrentHashMap<>(7);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 使用默认的pattern、timezone和locale获得缓存中的实例
|
* 使用默认的pattern、timezone和locale获得缓存中的实例
|
||||||
* @return a date/time formatter
|
* @return a date/time formatter
|
||||||
*/
|
*/
|
||||||
public F getInstance() {
|
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<F extends Format> {
|
|||||||
if (locale == null) {
|
if (locale == null) {
|
||||||
locale = Locale.getDefault();
|
locale = Locale.getDefault();
|
||||||
}
|
}
|
||||||
final MultipartKey key = new MultipartKey(pattern, timeZone, locale);
|
final Tuple key = new Tuple(pattern, timeZone, locale);
|
||||||
F format = cInstanceCache.get(key);
|
F format = cInstanceCache.get(key);
|
||||||
if (format == null) {
|
if (format == null) {
|
||||||
format = createInstance(pattern, timeZone, locale);
|
format = createInstance(pattern, timeZone, locale);
|
||||||
@ -129,7 +129,7 @@ abstract class FormatCache<F extends Format> {
|
|||||||
*/
|
*/
|
||||||
// package protected, for access from FastDateFormat; do not make public or protected
|
// package protected, for access from FastDateFormat; do not make public or protected
|
||||||
F getDateInstance(final int dateStyle, final TimeZone timeZone, final Locale locale) {
|
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<F extends Format> {
|
|||||||
*/
|
*/
|
||||||
// package protected, for access from FastDateFormat; do not make public or protected
|
// package protected, for access from FastDateFormat; do not make public or protected
|
||||||
F getTimeInstance(final int timeStyle, final TimeZone timeZone, final Locale locale) {
|
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<F extends Format> {
|
|||||||
*/
|
*/
|
||||||
// package protected, for access from test code; do not make public or protected
|
// 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) {
|
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);
|
String pattern = cDateTimeInstanceCache.get(key);
|
||||||
if (pattern == null) {
|
if (pattern == null) {
|
||||||
try {
|
try {
|
||||||
DateFormat formatter;
|
DateFormat formatter;
|
||||||
if (dateStyle == null) {
|
if (dateStyle == null) {
|
||||||
formatter = DateFormat.getTimeInstance(timeStyle.intValue(), locale);
|
formatter = DateFormat.getTimeInstance(timeStyle, locale);
|
||||||
} else if (timeStyle == null) {
|
} else if (timeStyle == null) {
|
||||||
formatter = DateFormat.getDateInstance(dateStyle.intValue(), locale);
|
formatter = DateFormat.getDateInstance(dateStyle, locale);
|
||||||
} else {
|
} else {
|
||||||
formatter = DateFormat.getDateTimeInstance(dateStyle.intValue(), timeStyle.intValue(), locale);
|
formatter = DateFormat.getDateTimeInstance(dateStyle, timeStyle, locale);
|
||||||
}
|
}
|
||||||
pattern = ((SimpleDateFormat) formatter).toPattern();
|
pattern = ((SimpleDateFormat) formatter).toPattern();
|
||||||
final String previous = cDateTimeInstanceCache.putIfAbsent(key, pattern);
|
final String previous = cDateTimeInstanceCache.putIfAbsent(key, pattern);
|
||||||
@ -188,62 +188,4 @@ abstract class FormatCache<F extends Format> {
|
|||||||
}
|
}
|
||||||
return pattern;
|
return pattern;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* Helper class to hold multi-part Map keys
|
|
||||||
* </p>
|
|
||||||
*/
|
|
||||||
private static class MultipartKey {
|
|
||||||
private final Object[] keys;
|
|
||||||
private int hashCode;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs an instance of <code>MultipartKey</code> 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
package cn.hutool.core.lang;
|
package cn.hutool.core.lang;
|
||||||
|
|
||||||
|
import cn.hutool.core.clone.CloneSupport;
|
||||||
|
import cn.hutool.core.collection.ArrayIter;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
import cn.hutool.core.clone.CloneSupport;
|
|
||||||
import cn.hutool.core.collection.ArrayIter;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 不可变数组类型,用于多值返回<br>
|
* 不可变数组类型,用于多值返回<br>
|
||||||
* 多值可以支持每个元素值类型不同
|
* 多值可以支持每个元素值类型不同
|
||||||
@ -17,7 +17,9 @@ import cn.hutool.core.collection.ArrayIter;
|
|||||||
public class Tuple extends CloneSupport<Tuple> implements Iterable<Object>, Serializable{
|
public class Tuple extends CloneSupport<Tuple> implements Iterable<Object>, Serializable{
|
||||||
private static final long serialVersionUID = -7689304393482182157L;
|
private static final long serialVersionUID = -7689304393482182157L;
|
||||||
|
|
||||||
private Object[] members;
|
private final Object[] members;
|
||||||
|
private int hashCode;
|
||||||
|
private boolean cacheHash;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构造
|
* 构造
|
||||||
@ -46,11 +48,30 @@ public class Tuple extends CloneSupport<Tuple> implements Iterable<Object>, Seri
|
|||||||
return this.members;
|
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
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
|
if(this.cacheHash && 0 != this.hashCode){
|
||||||
|
return this.hashCode;
|
||||||
|
}
|
||||||
final int prime = 31;
|
final int prime = 31;
|
||||||
int result = 1;
|
int result = 1;
|
||||||
result = prime * result + Arrays.deepHashCode(members);
|
result = prime * result + Arrays.deepHashCode(members);
|
||||||
|
if(this.cacheHash){
|
||||||
|
this.hashCode = result;
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,8 +95,9 @@ public class Tuple extends CloneSupport<Tuple> implements Iterable<Object>, Seri
|
|||||||
return Arrays.toString(members);
|
return Arrays.toString(members);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("NullableProblems")
|
||||||
@Override
|
@Override
|
||||||
public Iterator<Object> iterator() {
|
public Iterator<Object> iterator() {
|
||||||
return new ArrayIter<Object>(members);
|
return new ArrayIter<>(members);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package cn.hutool.core.date;
|
|||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.date.BetweenFormater.Level;
|
import cn.hutool.core.date.BetweenFormater.Level;
|
||||||
|
import cn.hutool.core.date.format.FastDateFormat;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
@ -16,6 +17,7 @@ import java.util.Calendar;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
@ -505,23 +507,39 @@ public class DateUtilTest {
|
|||||||
Assert.assertEquals("2018-09-13 13:34:39.999", dateStr);
|
Assert.assertEquals("2018-09-13 13:34:39.999", dateStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
|
||||||
@Test
|
@Test
|
||||||
public void parseCSTTest(){
|
public void parseCSTTest(){
|
||||||
String dateStr = "Wed Sep 16 11:26:23 CST 2009";
|
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);
|
DateTime dateTime = DateUtil.parseCST(dateStr);
|
||||||
Assert.assertEquals("2009-09-17 01:26:23", dateTime.toString());
|
Assert.assertEquals(parse, dateTime);
|
||||||
|
|
||||||
dateTime = DateUtil.parse(dateStr);
|
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
|
@Test
|
||||||
public void parseJDkTest() {
|
public void parseJDkTest() {
|
||||||
String dateStr = "Thu May 16 17:57:18 GMT+08:00 2019";
|
String dateStr = "Thu May 16 17:57:18 GMT+08:00 2019";
|
||||||
DateTime time = DateUtil.parse(dateStr);
|
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
|
@Test
|
||||||
|
Loading…
x
Reference in New Issue
Block a user