Java: Date parsing, why do I get an error

2019-01-09 20:06发布

问题:

    Date date = new Date();
    DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SZ");//2018-02-05T18:00:51.001+0000
    String text = dateFormat.format(date);

    Date test = dateFormat.parse(text);

The first three lines work fine. When I try to parse the string into a date again I get an error. How can I solve this?

The error looks like this:

Caused by: java.text.ParseException: Unparseable date: "2018-02-07T15:32:13.214+0100"
    at java.text.DateFormat.parse(DateFormat.java:366) ~[na:1.8.0_151]
    at TimeRange.parseDateFromIsoString(TimeRange.java:33) ~[classes/:na]

回答1:

    Date date = new Date();
    DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");//2018-02-05T18:00:51.001+0000
    String text = dateFormat.format(date);

    try {
        Date test = dateFormat.parse(text);
    } catch (ParseException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

worked for me. With "SSSZ" instead of "SZ" at the end of the pattern.



回答2:

I should like to contribute the modern answer. Because I discourage the use of SimpleDateFormat, more about that later.

java.time

    OffsetDateTime dateTime = OffsetDateTime.now(ZoneId.of("Europe/Rome"));
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSxx");
    String text = dateTime.format(formatter);
    OffsetDateTime test = OffsetDateTime.parse(text, formatter);

This produces a string like 2018-02-07T17:51:21.087+0100, pretty close to what I think you were after in the question, and parses it back nicely. With SSS in the format pattern string it always produces 3 decimals on the seconds and also requires exactly 3 decimals by parsing. You may use S or SSSSSS to get 1 or 6 decimals, for example. On my Java 9, OffsetDateTime.now() has a precision of 6 decimals (microseconds), so if I specify fewer, I lose precision in the formatting.

EDIT: For backward compatibility you cannot use the following, but for anyone reading along I should like to present a variant without an explicit formatter:

    String text = dateTime.toString();
    OffsetDateTime test = OffsetDateTime.parse(text);

The two differences in the produced string are:

  1. It produces as many groups of 3 decimals as are necessary to render the precision. Usually 3 decimals on my Java 8 and 6 decimals on my Java 9, but occassionally it hits a round number of milliseconds and produces fewer decimals. It parses a string with everything from 0 through 9 decimals, so this doesn’t present a problem in parsing. And I always preserve the full presicion of the original OffsetDateTime object.
  2. The offset from UTC is rendered with a colon, for example +01:00.

What went wrong in your code?

The SimpleDateFormat class is long outdated and notoriously troublesome, so even if you hadn’t had a problem with it at present, I would still recommend you drop it and use java.time, the modern Java date and time API, instead, as I do above.

One difference between the old SimpleDateFormat and the modern DateTimeFormatter is that while S in the modern formatter means fraction of second, in SimpleDateFormat it means milliseconds, so any other number than three is meaningless. However, it accepts other numbers. When formatting, your formatter produced enough digits for the milliseconds, for example 89 if there were 21.089 seconds or 214 when you had 13.214 as in the question.The former is incorrect, the 21.089 seconds were rendered as 21.89. I strongly believe that three-digit milliseconds caused your parsing to fail when you had only one S. On my Java 8 and 9 it works and also parses 21.89 as 21 seconds 89 milliseconds so the error evens out.

This behaviour agrees with the Java 9 documentation, which states: “For formatting, the number of pattern letters is the minimum number of digits, and shorter numbers are zero-padded to this amount. For parsing, the number of pattern letters is ignored unless it's needed to separate two adjacent fields.”

Link

  • Oracle tutorial: Date Time explaining how to use java.time.
  • SimpleDateFormat documentation for Java 9


回答3:

I Removed Z in the simple date format which relates to time zone Which gives Correct out Put Below is the snippet.

Date date = new Date();
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.S");//2018-02-05T18:00:51.001+0000
String text = dateFormat.format(date);

try {
    Date test = dateFormat.parse(text);
} catch (ParseException e) {
    e.printStackTrace();
}