2

I'm trying parse this String 2020-05-20 14:27:00.943000000 +00:00 and this Wed May 20 14:27:00 CEST 2020 to a ISO_INSTANT, but always return this exception

java.time.format.DateTimeParseException: Text '2020-05-20 14:27:00.943000000 +00:00' could not be parsed at index 10

My code is:

protected Instant parseDateTime(String fechaHora) {

        DateTimeFormatter formatter = DateTimeFormatter.ISO_INSTANT;
        TemporalAccessor temporalAccessor = formatter.parse(fechaHora);
        LocalDateTime localDateTime = LocalDateTime.from(temporalAccessor);
        ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, ZoneId.systemDefault());
        Instant result = Instant.from(zonedDateTime);
        return result; }

How can I convert this types?

Opsse
  • 1,851
  • 2
  • 22
  • 38
rolling
  • 23
  • 5

2 Answers2

4

tl;dr

OffsetDateTime.parse( 
    "2020-05-20 14:27:00.943000000 +00:00" , 
    DateTimeFormatter.ofPattern( "uuuu-MM-dd HH:mm:ss.SSSSSSSSS xxx" )
)
.toInstant()

Fixing your code

Your code is flawed in a few ways.

Use of TemporalAccessor is unnecessary and inappropriate here. To quote its Javadoc:

This interface is a framework-level interface that should not be widely used in application code. Instead, applications should create and pass around instances of concrete types

LocalDateTime is not appropriate here as it strips away vital information, the time zone or offset-from-UTC.

You specified a formatter whose formatting pattern does not match your inputs.

Solution

Manipulate your input string to comply with standard ISO 8601 format. Replace the SPACE between date and time with T. Delete SPACE between time and offset.

String input = "2020-05-20 14:27:00.943000000 +00:00" ;
String[] strings = input.split( " " ) ;
String modifiedInput = strings[0] + "T" + strings[1] + strings[2] ;

Parse as an OffsetDateTime, a date with time-of-day in the context of an offset-from-UTC.

OffsetDateTime odt = OffsetDateTime.parse( modifiedInput ) ;

Or, define a formatting pattern to match your input string. Use the DateTimeFormatter class. This has been covered many many times already on Stack Overflow, so search to learn more.

The predefined formatter DateTimeFormatter.ISO_INSTANT that you tried to use does not match your input. Your input does not comply with the ISO 8601 standard used by that formatter.

DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuu-MM-dd HH:mm:ss.SSSSSSSSS xxx" ) ;
String input = "2020-05-20 14:27:00.943000000 +00:00" ;
OffsetDateTime odt = OffsetDateTime.parse( input , f ) ;

See this code run live at IdeOne.com.

odt.toString(): 2020-05-20T14:27:00.943Z

If you need to return an Instant, call toInstant.

Instant instant = odt.toInstant() ;

To see that same moment in the context of a time zone, apply a ZoneId to get a ZonedDateTime object.

ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = odt.atZoneSameInstant( z ) ;

The OffsetDateTime and ZonedDateTime objects represent the same moment, same point on the timeline.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
  • Thanks for explanation, lot of useful informations. – dariosicily May 21 '20 at 17:06
  • @BasilBourque thank you very much, this works perfect. I'll try to change the origin of data to meet ISO 8601 like you suggest. Best regards. – rolling May 22 '20 at 07:10
  • @BasilBourque All work perfect with this code: "DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuu-MM-dd HH:mm:ss.SSSSSSSSS xxx" ) ; String input = "2020-05-20 14:27:00.943000000 +00:00" ; OffsetDateTime odt = OffsetDateTime.parse( input , f ) ;" Except when arrive a date like "2020-05-20 14:27:00.000000000 +00:00" or "2020-05-20 14:27:00.000000001 +00:00". If miliseconds are "00000000" the result of conversion is like "2020-05-20T14:27:00Z". How can i format it to "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"? – rolling May 26 '20 at 14:22
  • @rolling As [documented](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/time/OffsetDateTime.html#toString()), the default formatter suppresses unnecessary zeros in the fractional second to print digits in groups of three. If you want another format, use another `DateTimeFormatter`, perhaps using `DateTimeFormatterBuilder`. Those classes have been covered many many times, search to learn more. Start [here](https://stackoverflow.com/q/35184481/642706). – Basil Bourque May 26 '20 at 15:00
  • @rolling And, understand that the result of parsing a string into a date-time object is a date-time object, not a `String`, not text. Date-time objects like `OffsetDateTime` do not have a “format”. – Basil Bourque May 26 '20 at 15:02
1

The cause of your exception is the different format between your String 2020-05-20 14:27:00.943000000 +00:00 and ISO_INSTANT ; from DateTimeFormatter ISO_INSTANT accepts strings like 2011-12-03T10:15:30Z and this is not your case. A possible solution to this problem is use a custom DateTimeFormatter like below:

String fechaHora = "2020-05-20 14:27:00.943000000 +00:00";
DateTimeFormatter formatter =DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSSSSS ZZZZZ");
TemporalAccessor temporalAccessor = formatter.parse(fechaHora);
LocalDateTime localDateTime = LocalDateTime.from(temporalAccessor);
ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, ZoneId.systemDefault());
Instant result = Instant.from(zonedDateTime);
System.out.println(result); //<-- it will print 2020-05-20T12:27:00.943Z

dariosicily
  • 4,239
  • 2
  • 11
  • 17
  • `LocalDateTime` is not appropriate here as it strips away vital information, the time zone of offset-from-UTC. – Basil Bourque May 21 '20 at 15:46
  • Use of `TemporalAccessor` is unnecessary and inappropriate here. To quote [its Javadoc](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/time/temporal/TemporalAccessor.html): This interface is a framework-level interface that should not be widely used in application code. Instead, applications should create and pass around instances of concrete types – Basil Bourque May 21 '20 at 15:48
  • @BasilBourque Hello, I just copied code from the OP, this is the reason why I'm using it. – dariosicily May 21 '20 at 15:48
  • Hi, thanks but i've same exception with another format. java.time.format.DateTimeParseException: Text 'Wed May 20 14:27:00 CEST 2020' could not be parsed at index 0 – rolling May 21 '20 at 16:02
  • @BasilBourque In this case could be acceptable as an answer leave just the definition of the custom formatter and delete the OP code lines ? – dariosicily May 21 '20 at 16:10
  • @rolling You need to define a formatting pattern for each kind of string input. That other format of yours has been covered many times already on Stack Overflow. Search to find examples. Or simply read the `DateTimeFormatter` Javadoc and experiment. Furthermore, that other format of yours is a very poor choice for exchanging date-time values as text. I suggest you educate the publisher of your data about the ISO 8601 standard. – Basil Bourque May 21 '20 at 16:22