【Developer Log】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 = 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);

时间日期格式转换

对于格式转换,建议使用DateTimeFormatter

private static final DateTimeFormatter TRIGGER_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

LocalDateTime datetime = LocalDateTime.now();
datetime.format(TRIGGER_TIME_FORMATTER);


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ISO-8601时间格式是一种广泛使用的日期和时间表示方法,它的格式为yyyy-MM-dd'T'HH:mm:ssZZ。要进行ISO-8601时间格式的转换,可以使用不同编程语言的内置函数或库来实现。 在Python中,可以使用datetime模块来进行ISO-8601时间格式的转换。可以使用datetime.strptime()函数将字符串解析为datetime对象,然后使用datetime.strftime()函数将datetime对象格式化为所需的字符串格式。例如,要将ISO-8601时间格式的字符串转换为本地时区的时间,可以使用以下代码: ```python import datetime iso_datetime = "2021-10-26T14:53:29+08:00" dt = datetime.datetime.strptime(iso_datetime, "%Y-%m-%dT%H:%M:%S%z") local_dt = dt.astimezone(datetime.timezone(datetime.timedelta(hours=8))) local_datetime_str = local_dt.strftime("%Y-%m-%d %H:%M:%S") print(local_datetime_str) ``` 在Java中,可以使用SimpleDateFormat类来进行ISO-8601时间格式的转换。可以使用SimpleDateFormat.parse()方法将字符串解析为Date对象,然后使用SimpleDateFormat.format()方法将Date对象格式化为所需的字符串格式。例如,要将ISO-8601时间格式的字符串转换为本地时区的时间,可以使用以下代码: ```java import java.text.SimpleDateFormat; import java.util.Date; import java.util.TimeZone; public class Main { public static void main(String[] args) throws Exception { String isoDatetime = "2021-10-26T14:53:29+08:00"; SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX"); Date date = isoFormat.parse(isoDatetime); SimpleDateFormat localFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); localFormat.setTimeZone(TimeZone.getDefault()); String localDatetimeStr = localFormat.format(date); System.out.println(localDatetimeStr); } } ``` 以上代码中,将ISO-8601时间格式的字符串解析为Date对象后,使用SimpleDateFormat将其格式化为本地时区的时间字符串。 请注意,根据不同的编程语言和库的实现,可能需要进行一些调整和配置,以确保正确的ISO-8601时间格式转换。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [python pandas ISO-8601时间转换为本地时间](https://blog.csdn.net/weixin_43924621/article/details/113920166)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [ISO8601时间格式的转换](https://blog.csdn.net/gdvfs12/article/details/120973705)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值