【Developer Log】SimpleDateFormat的parse问题、ISO-8601格式
2016-12-01 09:31
411 查看
在并发处理时,SimpleDateFormat进行时间格式转换会出现问题。本博将就问题情况以及如何进行时间转换作为讨论。
例子很简单,就是通过开启线程,并发执行同一SimpleDateFormat对象的parse(String str)操作。运行时出现异常,如下:
根据情况,我们猜测SimpleDateFormat在处理parse()中很可能使用了方法之外的对象,例如是SimpleDateFormate的属性,引发了并发执行的错误。当然具体的原因需要是查源代码。不过,我们只是使用者,可以通过程序修订来避免问题:
问题解决。
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 = iso8601string.replace("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(); t.test(timeStr); } }
例子很简单,就是通过开启线程,并发执行同一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) at java.text.DigitList.getLong(Unknown Source) at java.text.DecimalFormat.parse(Unknown Source) at java.text.SimpleDateFormat.subParse(Unknown Source) at java.text.SimpleDateFormat.parse(Unknown Source) at java.text.DateFormat.parse(Unknown Source) at cn.flowingflying.wei.test.ParseTest.iso8601Parse1(ParseTest.java:21) at cn.flowingflying.wei.test.ParseTest$1.run(ParseTest.java:38) at java.lang.Thread.run(Unknown Source) 或者 java.lang.NumberFormatException: multiple points at sun.misc.FloatingDecimal.readJavaFormatString(Unknown Source) at sun.misc.FloatingDecimal.parseDouble(Unknown Source) at java.lang.Double.parseDouble(Unknown Source) at java.text.DigitList.getDouble(Unknown Source) at java.text.DecimalFormat.parse(Unknown Source) at java.text.SimpleDateFormat.subParse(Unknown Source) at java.text.SimpleDateFormat.parse(Unknown Source) at java.text.DateFormat.parse(Unknown Source) at cn.flowingflying.wei.test.ParseTest.iso8601Parse1(ParseTest.java:21) at cn.flowingflying.wei.test.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 = iso8601string.replace("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(); t.test(timeStr); } }
问题解决。
ISO-8601的时间解析
实际上,Java1.8具有丰富的时间日期处理,可以使用OffsetDateTime和Instant来处理ISO-8601字符串。OffsetDateTime.parse(iso8601Str); Instant.parse(iso8601Str);
时间日期格式转换
对于格式转换,建议使用DateTimeFormatterprivate static final DateTimeFormatter TRIGGER_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); LocalDateTime datetime = LocalDateTime.now(); datetime.format(TRIGGER_TIME_FORMATTER);
相关文章推荐
- 【关于SimpleDateFormat 的星期计算问题】
- JAVA日期格式问题 SimpleDateFormat方法
- 让SimpleDateFormat的parse方法严格解析
- 解决多线程下simpleDateFormat的安全问题
- 关于SimpleDateFormat安全的时间格式化线程安全问题
- SimpleDateFormat多线程问题
- 格式化时间遇到的问题SimpleDateFormat
- SimpleDateFormat的线程安全问题
- 一个并发问题(simpledateformat)
- SimpleDateFormat的线程安全问题
- 时间转换的好用方法(好招1)//Date date = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").parse("2007-09-21 11:00:10.0100");
- 使用SimpleDateFormat必须注意的问题
- 关于SimpleDateFormat的一个小问题
- SimpleDateFormat做静态成员 成员 多线程并发出现问题
- SimpleDateFormat的parse(String str)方法的用法
- 你的SimpleDateFormat起作用了吗?TimeZone问题
- android 利用SimpleDateFormat格式化时间不准确的问题
- SimpleDateFormat多线程调用问题
- Java SimpleDateFormat 线程不安全问题及解决方法
- SimpleDateFormat的线程安全问题