javadateparsingtimeinstant

Parse non ISO 8601 to ISO_INSTANT


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?


Solution

  • 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.