单个类可解析Java中的任何日期格式

时间:2019-01-07 11:18:23

标签: java simpledateformat date-format java-time datetime-parsing

我一直在解析以下格式的日期。我维护着这些格式的数组,并解析所有这些格式的每个日期字符串。

我使用的代码是-

SimpleDateFormat simpleDateFormat = new SimpleDateFormat(dateFormat);
simpleDateFormat.setTimeZone(timeZone); //timeZone is a java.util.TimeZone object       
Date date = simpleDateFormat.parse(dateString);

现在,我也想解析yyyy-MM-dd'T'HH:mm:ss.SSSSSSXXX格式,但是使用SimpleDateFormat时不考虑6位数的微秒。所以我调查了java.time包。

要解析yyyy-MM-dd'T'HH:mm:ss.SSSSSSXXX格式,我将需要 OffsetDateTime 类,而对于其他格式,我将需要 ZonedDateTime 类。格式将在 DateTimeFormatter 类中设置。

是否可以使用诸如SimpleDateFormat之类的单个类来传递所有格式?

1 个答案:

答案 0 :(得分:2)

Since your Java 8 doesn’t behave as would be reasonably expected, I suggest that a workaround is trying to parse without zone first. If a zone or an offset is parsed from the string, this will be used. If the parsing without zone fails, try with a zone. The following method does that:

private static void parseAndPrint(String formatPattern, String dateTimeString) {
    // Try parsing without zone first
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern(formatPattern);
    Instant parsedInstant;
    try {
        parsedInstant = formatter.parse(dateTimeString, Instant::from);
    } catch (DateTimeParseException dtpe) {
        // Try parsing with zone
        ZoneId defaultZone = ZoneId.of("Asia/Calcutta");
        formatter = formatter.withZone(defaultZone);
        parsedInstant = formatter.parse(dateTimeString, Instant::from);
    }
    System.out.println("Parsed instant: " + parsedInstant);
}

Let’s try it:

    parseAndPrint("yyyy-MM-dd'T'HH:mm:ss.SSSSSSXXX", "2018-10-22T02:17:58.717853Z");
    parseAndPrint("yyyy-MM-dd'T'HH:mm:ss.SSSSSS", "2018-10-22T02:17:58.717853");
    parseAndPrint("EEE MMM d HH:mm:ss zzz yyyy", "Mon Oct 22 02:17:58 CEST 2018");

Output on Java 8 is:

Parsed instant: 2018-10-22T02:17:58.717853Z
Parsed instant: 2018-10-21T20:47:58.717853Z
Parsed instant: 2018-10-22T00:17:58Z

The first example has an offset in the string and the last a time zone abbreviation in the string, and in both cases are these respected: the instant printed has adjusted the time into UTC (since an Instant always prints in UTC, its toString method makes sure). The middle example has got neither offset nor time zone in the string, so uses the default time zone of Asia/Calcutta specified in the method.

That said, parsing a three or four letter time zone abbreviation like CEST is a dangerous and discouraged practice since the abbreviations are often ambiguous. I included the example for demonstration only.

Is there a way to use a single class…?

I have used Instant for all cases, so yes there is a way to use just one class. The limitation is that you do not know afterward whether any time zone or offset was in the string nor what it was. You didn’t know when you were using SimpleDateFormat and Date either, so I figured it was OK?

A bug in Java 8?

The results from your demonstration on REX tester are disappointing and wrong and do not agree with the results I got on Java 11. It seems to me that you have been hit by a bug in Java 8, possibly this one: Parsing with DateTimeFormatter.withZone does not behave as described in javadocs.