1

I have implemented the following method to convert a String to a Date because the Date(String) constructor is deprecated:

private Date format(String inputString) {
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
        try {
            return dateFormat.parse(inputString);
        } catch (ParseException e) {
            return new Date();
        }
    }

One inputString sample is 2017-06-01T01:00:00Z. However, when I examine the output, I observe that the exception handler was triggered and new Date() was returned, meaning there's something wrong with my pattern: "Jun 17, 2017 1:12:02 PM".

What am I missing with the pattern yyyy-MM-dd'T'HH:mm:ssZ?

4
  • 4
    I cannot more strongly advise against using the legacy java.util.Date class. You should instead use the appropriate class in the java.time package. Commented Jun 17, 2017 at 20:29
  • 1
    Can you print the stacktrace of the exception you are catching and then post that output here? Commented Jun 17, 2017 at 20:29
  • 2
    You should consider java.util.Date deprecated. The whole thing. Commented Jun 17, 2017 at 20:31
  • 2
    A lot of legacy code and libraries interoperate with Date. Dogmatic Date hate is not appropriate. Use Date if the solution to your problem calls for it, but do be aware of its weaknesses. Commented Jun 17, 2017 at 20:54

3 Answers 3

4

The Z pattern represents a numerical timezone offset. Thus the offset required here would be +0000.

The X pattern would allow you to use time zone offsets such as Z. (Yes, it seems counter-intuitive, but there you go.)

Source

Sign up to request clarification or add additional context in comments.

Comments

3

I agree with the comments by Joe C and Louis Wassermann: stay off the long outdated Date class if there’s any way you can. And there is. The modern replacement classes are so much more convenient and programmer friendly.

Furthermore, your input string conforms to the ISO 8601 standard for an instant, a point in time, so fits the Instant class precisely. No need for any explicit formatter for parsing it. I suggest:

private static Instant parse(String inputString) {
    try {
        return Instant.parse(inputString);
    } catch (DateTimeParseException dtpe) {
        System.err.println("Parsing: " + dtpe);
        return Instant.now();
    }
}

Use the method like the following, for example:

    String inputString = "2017-06-01T01:00:00Z";
    System.out.println(parse(inputString));

This prints:

2017-06-01T01:00:00Z

Well, it’s the same string you started out from, because Instant.toString() produces the same ISO 8601 string back.

I admit scottb a point too: we sometimes need to interoperate with legacy code that does require an oldfashioned Date instance. If this is your case, produce one from Date.from(parse(inputString)). This will produce a Date equal to the instant (on my computer printed as Thu Jun 01 03:00:00 CEST 2017 because that happens to be my time zone). In any case I recommend converting to Date in the last moment before entering your legacy code to minimize your own use of it.

Just for the experiment, let’s try to use your incorrect format pattern string with the newer DateTimeFormatter class:

    DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ").parse(inputString);

This yields a java.time.format.DateTimeParseException: Text '2017-06-01T01:00:00Z' could not be parsed at index 19. It’s trying to be helpful to you: index 19 of 2017-06-01T01:00:00Z is where it says Z. As the two other answers say, this is exactly where the format pattern doesn’t match the input. Take my word, this is just one example out of many where you get better help from the modern classes than from the old ones.

Comments

1

You have a literal Z in your input string, so you need to quote that too (or use X). Like,

DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");

or better (as pointed out in the comments)

DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");

Also, don't throw away exceptions (at least print a stack trace). In Java 8+, you should be using the new java.time classes. That might look something like,

private static LocalDateTime format(String inputString) {
    String pattern = "yyyy-MM-dd'T'HH:mm:ssX";
    return LocalDateTime.from(DateTimeFormatter.ofPattern(pattern)
           .parse(inputString));
}

3 Comments

I would bet that the Z in the input string is the timezone and not just a literal. So it would be more appropriate to use X (ISO8601 timezone) instead of 'Z'...
This Answer gives poor advice. By treating Z as a literal, and ignoring it, you are ignoring crucial information: the time zone or offset-from-UTC. You are discarding information with no benefit gained. Likewise, the LocalDateTime class purposely lacks info about offset or zone -- appropriate when such info is lacking, but silly to use purposely to discard info. A LocalDateTime does not represent a moment, a point on the timeline. See the better advice to use java.time classes and retain zone/offset info by Ole V.V.
Thanks for the edit. It’s an improvement to the oldfashioned code. In the modern code you are still effectively throwing the time zone information away. Only before you knew that the dropped zone information was Z, now you no longer check that and cannot be sure. This is even worse…

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.