Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error java.time.format.DateTimeParseException: could not be parsed, unparsed text found at index 10

I´m trying to pase the next String using LocalDateTime, but I always get de unparsed text found error:

Error java.time.format.DateTimeParseException: Text '2016-08-18 14:27:15.103+02' could not be parsed, unparsed text found at index 10

Here is my String: convertDate: '2016-08-18 14:27:15.103+02'

And my code:

public static LocalDate conversorStringToLocalDateTime(String convertDate) throws ParseException {
    LocalDate dateTime =LocalDate.parse(convertDate);
    return dateTime;
}

I guess is not too complicated, buy I´m not able to see the error. Could the +02 in the String be the cause?

like image 499
Asier Pomposo Avatar asked Aug 19 '16 07:08

Asier Pomposo


People also ask

What does Java datetimeparseexception 7/14/2019 mean?

java.time.format.DateTimeParseException: Text '"07/14/2019 19:07"' could not be parsed at index 0 From the exception, you can see that the text in question is "07/14/2019 19:07".

What is parsing error class?

An exception thrown when an error occurs during parsing. This exception includes the text being parsed and the error index. This class is intended for use in a single thread. Constructs a new exception with the specified message. Constructs a new exception with the specified message and cause.

What is parse() method in datetimeformatter?

The parse () takes a String and parse into LocalDateTime instance based upon format specified by DateTimeFormatter. The parse () method is also overloaded and by default it uses ISO_LOCAL_DATE_TIME format which is “yyyy-MM-dd HH:mm” i.e. “2017-08-03T10:15:30”, but if your String is in a different format then you can specify a separate formatter.

What does it mean to parse date in Java?

Parsing date means you have a String which represents a date e.g. “2017-08-3” and you want to convert it into an object which represents the date in Java e.g. java.util.Date in pre-Java 8 world and LocalDate or LocalDatetime in Java 8 world.


2 Answers

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.

like image 98
Basil Bourque Avatar answered Sep 20 '22 17:09

Basil Bourque


Your code is using LocalDate which only parses a date - not a date and time so you are getting an error when the parse finds the space after the date.

So you should be using LocalDateTime but LocalDateTime.parse(String) expects an ISO format date which is not the format you are using.

So you need to use a DateTimeFormatter to specify the format of your input string. Something like:

DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSX");
LocalDateTime result = LocalDateTime.parse(convertDate, format);
like image 42
greg-449 Avatar answered Sep 18 '22 17:09

greg-449