1

I am trying to parse a timestamp with a SimpleDateFormat but it raises ParseException in Java 1.8. The same code works flawlessly in Java 9 or higher. The example code snippet

import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.text.SimpleDateFormat;
import java.text.ParseException;
public class TestStrftime{

     public static void main(String []args) throws ParseException {
        String TS_FMT = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX";
        SimpleDateFormat dateFormat = new SimpleDateFormat(TS_FMT);
        String szSableTimeStamp = "2020-01-16T19:32:13.540000Z";
        Instant sableTimestamp = dateFormat
                        .parse(szSableTimeStamp)
                        .toInstant().truncatedTo(ChronoUnit.SECONDS);
        System.out.println(sableTimestamp);
     }
}

and it raises the exception

Exception in thread "main" java.text.ParseException: Unparseable date: "2020-01-16T19:32:13.540000Z"
    at java.text.DateFormat.parse(DateFormat.java:366)
    at TestStrftime.main(TestStrftime.java:12)

but with Java 9 or higher, its able to parse the date with the desired output

2020-01-16T19:41:13Z

9
  • 3
    Why not use DateTimeFormatter? Commented Jan 19, 2020 at 6:35
  • Tried to reproduce with mave plugin set to 1.8. Worked fine. Anything else in your env that could cause the problem? ``` <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> ``` Commented Jan 19, 2020 at 6:43
  • 1
    Java 9: How could 2020-01-16T19:41:13Z be the desired output from parsing 2020-01-16T19:32:13.540000Z?? It’s 8 and a half minutes off. Commented Jan 19, 2020 at 7:07
  • 1
    As a compete aside, the variable name szSableTimeStamp seems to be wrong. Some C++ guidelines say to use sz at prefix for zero terminated strings. But Java strings are not zero terminated. Commented Jan 19, 2020 at 7:10
  • 1
    In any case I recommend you don’t use SimpleDateFormat. That class is notoriously troublesome and long outdated. Instead use DateTimeFormatter from java.time, the modern Java date and time API. (where also Instant and ChronoUnit come from) Commented Jan 19, 2020 at 12:36

2 Answers 2

4

tl;dr

Instant                             // The modern way to represent a moment in UTC. Resolves to nanoseconds.
.parse(                             // Parse text in standard ISO 8601 format without specifying any formatting pattern.
    "2020-01-16T19:32:13.540000Z"
)                                   // Returns an `Instant` object.
.truncatedTo(                       // Lop off part of the data.
    ChronoUnit.SECONDS              // Keep whole seconds and larger. Lose the fractional second, if any.
)                                   // Returns a new fresh second `Instant` object, per immutable objects pattern. Original `Instant` is left unaffected.
.toString()                         // Generate text in standard ISO 8601 format.

See this code run live at IdeOne.com.

2020-01-16T19:32:13Z

Details

You are mixing the terrible legacy date-time classes such as SimpleDateFormat with their modern replacements. Do not do this. Use only classes from the java.time packages.

The Instant class knows how to parse strings in standard ISO 8601 format such as your input string. No need to specify a formatting pattern.

String input = "2020-01-16T19:32:13.540000Z" ;  // Using standard ISO 8601 format.
Instant instant = Instant.parse( input ) ;      // By default parses ISO 8601 strings. No need to specify a formatting pattern.

If you want to drop any fractional second, truncate.

Instant instantWholeSeconds = instant.truncatedTo( ChronoUnit.SECONDS ) ;

Generate text in standard ISO 8601 format by calling Instant::toString().

String output = instantWholeSeconds.toString() ;  // Generate text in standard ISO 8601 format.

If you want a count of seconds since the epoch reference of the first moment of 1970 in UTC, interrogate the Instant object by calling getEpochSecond.

long secondsSinceEpoch = instant.getEpochSecond() ;

am trying to parse a timestamp with a SimpleDateFormat

Never use SimpleDateFormat again. Obsolete with the adoption of JSR 310.

The legacy date-time classes are a bloody awful mess. Avoid them like the plague.

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

Comments

4

The issue with SSSXXX not matching 540000Z was fixed by JDK-8072099: Format "ha" is unable to parse hours 10-12 in Java 9.

The real issue is that SSS represents millisecond, while 540000 is microseconds, so even the Java 9 parser gets it wrong by parsing that to 9 minutes (540 seconds).

Since you want an Instant object, do not use the old flawed SimpleDateFormat. Use DateTimeFormatter instead:

String TS_FMT = "uuuu-MM-dd'T'HH:mm:ss.SSSSSSXXX";
DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern(TS_FMT);
String szSableTimeStamp = "2020-01-16T19:32:13.540000Z";
Instant sableTimestamp = Instant.from(dateFormat.parse(szSableTimeStamp))
                .truncatedTo(ChronoUnit.SECONDS);
System.out.println(sableTimestamp);

However, since your format happens to match the ISO-8601 format, which is the natural format of an Instant, just use the Instant.parse() method, without any need for a formatter:

String szSableTimeStamp = "2020-01-16T19:32:13.540000Z";
Instant sableTimestamp = Instant.parse(szSableTimeStamp)
                .truncatedTo(ChronoUnit.SECONDS);
System.out.println(sableTimestamp);

4 Comments

Thank you. Yours is a complete answer but unfortunately I already accepted an answer.
@Abhijit You can change which answer you accept, if you want to. Basil's answer is good too, so accept the one you prefer, but up-vote both ;-)
I know, just a courtesy I don't want to change. But I can give you a bounty but for that you have to wait.
@Abhijit No need, we both have adequate rep, don't need a boost. I'm good with Basil's answer being the accepted one.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.