【DeveloperLog】SimpleDateFormat的parse问题、ISO-
8601格式
在并发处理时,SimpleDateFormat进⾏时间格式转换会出现问题。本博将就问题情况以及如何进⾏时间转换作为讨论。SimpleDateFormate并发parse()问题⼩实验
下⾯是⼀个简单的观察⼩例⼦,同时提供ISO-8601时间格式的⼈⼯处理:
public class ParseTest {
private final static SimpleDateFormat ISO8601_DATE = new SimpleDateFormat(ISO8601_DATEFORMAT);
public static Date iso8601Parse(String iso8601string) throws ParseException{
String s = place("Z", "+00:00");
int index = s.lastIndexOf(':');
s = s.substring(0,19)+ s.substring(index-3,index)+s.substring(index +1);
return ISO8601_DATE.parse(s);
}
public void test(String timeStr){
for(int i = 0 ; i < 100; i ++){
new Thread(new Runnable() {
@Override
public void run() {
try {
Date date = iso8601Parse(timeStr);
System.out.println("test1 : " + date);
} catch (Exception e) {
System.out.println("ERROR : test1 " + e.toString());
e.printStackTrace(); //这⾥抛出来的并不是预计的ParseException
}
}
}).start();
}
}
public static void main(String[] args) throws InterruptedException {
String timeStr = "2016-11-18T01:16:43.593203Z";
ParseTest t = new ParseTest();
}
}
例⼦很简单,就是通过开启线程,并发执⾏同⼀SimpleDateFormat对象的parse(String str)操作。运⾏时出现异常,如下:
报错:
java.lang.NumberFormatException: For input string: "2016E20164"
at java.lang.NumberFormatException.forInputString(Unknown Source)
at java.lang.Long.parseLong(Unknown Source)
at java.lang.Long.parseLong(Unknown Source)
Long(Unknown Source)
DecimalFormat.parse(Unknown Source)
SimpleDateFormat.subParse(Unknown Source)
SimpleDateFormat.parse(Unknown Source)
DateFormat.parse(Unknown Source)
at cn.st.ParseTest.iso8601Parse1(ParseTest.java:21)
at cn.st.ParseTest$1.run(ParseTest.java:38)
at java.lang.Thread.run(Unknown Source)
或者
java.lang.NumberFormatException: multiple points
at sun.adJavaFormatString(Unknown Source)
at sun.misc.FloatingDecimal.parseDouble(Unknown Source)
at java.lang.Double.parseDouble(Unknown Source)
Double(Unknown Source)
DecimalFormat.parse(Unknown Source)
SimpleDateFormat.subParse(Unknown Source)
SimpleDateFormat.parse(Unknown Source)
DateFormat.parse(Unknown Source)
at cn.st.ParseTest.iso8601Parse1(ParseTest.java:21)
at cn.st.ParseTest$1.run(ParseTest.java:38)
at java.lang.Thread.run(Unknown Source)
更诡异的是看打印信息:date翻译出现问题
test1 : Fri Nov 18 09:16:43 CST 2016
test1 : Fri Nov 18 09:16:43 CST 2016
test1 : Sat Dec 18 09:16:43 CST 1
test1 : Fri Nov 18 09:16:43 CST 2016
test1 : Fri Nov 18 09:16:43 CST 2016
test1 : Fri Nov 18 09:16:43 CST 2016
根据情况,我们猜测SimpleDateFormat在处理parse()中很可能使⽤了⽅法之外的对象,例如是SimpleDateFormate的属性,引发了并发执⾏的错误。当然具体的原因需要是查源代码。不过,我们只是使⽤者,可以通过程序修订来避免问题:
public class ParseTest {
private final static String ISO8601_DATEFORMAT = "yyyy-MM-dd'T'HH:mm:ssZ";
//Warning : 如果采⽤静态的共⽤SimpleDateFormat,在多线程的情况下,会出现不确定的解析错误。
//private final static SimpleDateFormat ISO8601_DATE = new SimpleDateFormat(ISO8601_DATEFORMAT);
public static Date iso8601Parse(String iso8601string) throws ParseException{
String s = place("Z", "+00:00");
int index = s.lastIndexOf(':');
s = s.substring(0,19)+ s.substring(index-3,index)+s.substring(index +1);
return new SimpleDateFormat(ISO8601_DATEFORMAT).parse(s);
}
public void test(String timeStr){
for(int i = 0 ; i < 100; i ++){
new Thread(new Runnable() {
@Override
public void run() {
try {
Date date = iso8601Parse(timeStr);
System.out.println("test1 : " + date);
} catch (Exception e) {
System.out.println("ERROR : test1 " + e.toString());
e.printStackTrace(); //这⾥抛出来的并不是预计的ParseException
}
}
}).start();
}
}
public static void main(String[] args) throws InterruptedException {
String timeStr = "2016-11-18T01:16:43.593203Z";
ParseTest t = new ParseTest();
}
}
问题解决。
ISO-8601的时间解析
实际上,Java1.8具有丰富的时间⽇期处理,可以使⽤OffsetDateTime和Instant来处理ISO-8601字符串。
error parse newOffsetDateTime.parse(iso8601Str);
Instant.parse(iso8601Str);
时间⽇期格式转换
对于格式转换,建议使⽤DateTimeFormatter
private static final DateTimeFormatter TRIGGER_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime datetime = w();
datetime.format(TRIGGER_TIME_FORMATTER);

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。