Reputation: 63777
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
Upvotes: 1
Views: 601
Reputation: 159165
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);
Upvotes: 4
Reputation: 339845
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
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.
Upvotes: 4