时区有冒号时如何解决解析异常?

How to solve parse exception when timezone has colon?

我从网络服务接收 DateTime 作为 StringDateTime 字符串的一个示例是:"DateTime":"2021-06-06T04:54:41-04:00".

这个2021-06-06T04:54:41-04:00或多或少符合ISO-8601格式,所以我用这个模式来解析它:yyyy-MM-dd'T'HH:mm:ssZ。但是,响应 DateTime 的时区部分中的冒号导致了问题。 2021-06-06T04:54:41-04:00 给出解析异常,但 2021-06-06T04:54:41-0400 解析正常。

下面的代码应该更好地解释它:

public void stringToDate() {

        String pattern = "yyyy-MM-dd'T'HH:mm:ssZ";  //ISO - 8601 Format
        TimeZone timeZoneEST = TimeZone.getTimeZone("US/Eastern");
        SimpleDateFormat sdf = new SimpleDateFormat(pattern, new Locale("en", "US"));
        sdf.setLenient(false);
        sdf.setTimeZone(timeZoneEST);
        
        String timeFromWebService = "2021-06-06T04:54:41-04:00";
        try {
            Date parsedDate = sdf.parse(timeFromWebService); // not working because of colon in timezone part
            System.out.println(parsedDate);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        
        try {
            Thread.sleep(1000);  //sleep to avoid interleaving output from stacktrace (above) and syso (below)
        } catch (InterruptedException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        
        String timeFromWebServiceModified = "2021-06-06T04:54:41-0400";  //removed colon from timezone part
        try {
            Date parsedDate = sdf.parse(timeFromWebServiceModified); // working because colon is removed in timezone part
            System.out.println(parsedDate);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        
    }

我想在不修改响应的情况下处理此解析 DateTime。关于如何解析原始 DateTime 的任何建议。关于使用什么模式的任何建议都将非常有帮助。

java.util 日期时间 API 及其格式 API、SimpleDateFormat 已过时且容易出错。建议完全停止使用它们并切换到 modern Date-Time API*.

解决方案使用java.time,现代API:

import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import java.util.stream.Stream;

public class Main {
    public static void main(String[] args) {
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("u-M-d'T'H:m:s[XXX][XX][X]", Locale.ENGLISH);
        
        //Test
        Stream.of(
                    "2021-06-06T04:54:41-04:00",
                    "2021-06-06T04:54:41-0400",
                    "2021-06-06T04:54:41-04",
                    "2021-06-06T04:54:41Z"                  
        ).forEach(s -> System.out.println(OffsetDateTime.parse(s, dtf)));
    }
}

输出:

2021-06-06T04:54:41-04:00
2021-06-06T04:54:41-04:00
2021-06-06T04:54:41-04:00
2021-06-06T04:54:41Z

ONLINE DEMO

检查How to use OffsetDateTime in JDBC?

详细了解 java.timemodern Date-Time API* 来自 Trail:日期时间.

使用遗留解决方案 API:

SimpleDateFormat 没有指定可选模式的功能,我们使用方括号和 DateTimeFormatter 的方式。在这种情况下,您可以创建 SimpleDateFormat 的多个实例并尝试每个实例。

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        SimpleDateFormat sfdArr[] = {
                            new SimpleDateFormat("y-M-d'T'H:m:sXXX", Locale.ENGLISH),
                            new SimpleDateFormat("y-M-d'T'H:m:sXX", Locale.ENGLISH),
                            new SimpleDateFormat("y-M-d'T'H:m:sX", Locale.ENGLISH)
        };
        
        String []strDateTimeArr = {
                    "2021-06-06T04:54:41-04:00",
                    "2021-06-06T04:54:41-0400",
                    "2021-06-06T04:54:41-04",
                    "2021-06-06T04:54:41Z"                  
        };
        
        for(String s : strDateTimeArr) {
            Date date = null;
            for(SimpleDateFormat sdf : sfdArr) {
                try {
                    date = sdf.parse(s);
                }catch(ParseException e) {
                    //...
                }
            }
            System.out.println(date);
        }
    }
}

ONLINE DEMO


* 无论出于何种原因,如果您必须坚持Java 6 或Java 7,您可以使用ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and