tl;dr
OffsetDateTime odt = OffsetDateTime.parse ( "2016-08-18 14:27:15.103+02" , DateTimeFormatter.ofPattern ( "yyyy-MM-dd HH:mm:ss.SSSX" ) ) ;
Details
The Answer by greg-449 is correct about the problem (using a date-only object for a date-time value) but not the solution.
That Answer uses LocalDateTime
which unnecessarily throws away valuable information about the offset-from-UTC. A LocalDateTime
does not represent a specific moment on the timeline, only a vague idea about possible moments depending on adjusting into a particular time zone.
The +02
is an offset-from-UTC meaning “two hours ahead of UTC”. So in UTC the time-of-day for this simultaneous moment is 12 hours, 2 hours less than your 14 hours. This does represent a specific moment on the timeline. This offset is the valuable information you are throwing away with a LocalDateTime
rather than an OffsetDateTime
.
The format of your string is in SQL format, which is close to standard ISO 8601 format. Merely replace the SPACE in the middle with a T
. The java.time classes use ISO 8601 formats by default, so no need to specify a formatting pattern.
String input = "2016-08-18 14:27:15.103+02";
String inputModified = input.replace ( " " , "T" );
Unfortunately, Java 8 has a bug in parsing offset values abbreviated to just an hour or offset values omitting the colon between hours and minutes. Fixed in Java 9. But in Java 8, we need to adjust the input.
// Workaround for Java 8 where 2-digit offset fails parsing. Fixed in Java 9.
int lengthOfAbbreviatedOffset = 3;
if ( inputModified.indexOf ( "+" ) == ( inputModified.length () - lengthOfAbbreviatedOffset ) ) {
// If third character from end is a PLUS SIGN, append ':00'.
inputModified = inputModified + ":00";
}
if ( inputModified.indexOf ( "-" ) == ( inputModified.length () - lengthOfAbbreviatedOffset ) ) {
// If third character from end is a PLUS SIGN, append ':00'.
inputModified = inputModified + ":00";
}
Now parse.
OffsetDateTime odt = OffsetDateTime.parse ( inputModified );
Dump to console. Note how we transformed +02
into +02:00
.
System.out.println ( "input: " + input + " | inputModified: " + inputModified + " | odt: " + odt );
input: 2016-08-18 14:27:15.103+02 | inputModified: 2016-08-18T14:27:15.103+02:00 | odt: 2016-08-18T14:27:15.103+02:00
Alternatively, specify a formatting pattern. The offset-parsing bug does not bite when using this formatting pattern.
DateTimeFormatter f = DateTimeFormatter.ofPattern ( "yyyy-MM-dd HH:mm:ss.SSSX" );
OffsetDateTime odt = OffsetDateTime.parse ( input , f );
Database
Coming from Postgres, you should be retrieving the value as a date-time object rather than a String.
If your JDBC driver complies with JDBC 4.2 you can call ResultSet::getObject
to get an Instant
or OffsetDateTime
. If not, call ResultSet::getTimestamp
to get a java.sql.Timestamp
, then immediately convert to java.time by calling toInstant
on the Timestamp object.
Stick with java.time for your business logic; use the java.sql types briefly and only for exchange with the database.