Java – Conditionally creates a LocalDateTime, ZonedDateTime, or OffsetDateTime based on the parsed TemporalAccessor

Conditionally creates a LocalDateTime, ZonedDateTime, or OffsetDateTime based on the parsed TemporalAccessor… here is a solution to the problem.

Conditionally creates a LocalDateTime, ZonedDateTime, or OffsetDateTime based on the parsed TemporalAccessor

Given a DateTimeFormatter is defined as:

public static final DateTimeFormatter DATE_TIME = new DateTimeFormatterBuilder()
        .parseCaseInsensitive()
        .append( ISO_LOCAL_DATE )
        .optionalStart().appendLiteral( ' ' ).optionalEnd()
        .optionalStart().appendLiteral( 'T' ).optionalEnd()
        .append( ISO_LOCAL_TIME )
        .optionalStart().appendLiteral( ' ' ).optionalEnd()
        .optionalStart().appendZoneOrOffsetId().optionalEnd()
        .toFormatter();

I want to conditionally create LocalDateTime, ZonedDateTime, or OffsetDateTime, or neither, depending on whether the resolution includes the zone ID, offset, or neither.

So far I have:

    DATE_TIME.parse(
            text,
            (temporal) -> {
                 see if there is an offset
                final ZoneOffset offset = temporal.query( TemporalQueries.offset() );
                if ( offset != null ) {
                    return OffsetDateTime.from( temporal );
                }

 see if there is a tz
                final ZoneId zoneId = temporal.query( TemporalQueries.zoneId() );
                if ( zoneId != null ) {
                    return ZonedDateTime.from( temporal );
                }

 otherwise its a LocalDateTime
                return LocalDateTime.from( temporal );
            }
    );

But I found that the region offset is never “recognized” – even if the text contains an offset, it is always reported as the region ID. For example. Given “1999-12-31 12:59:59 +02:00" I want to get an OffsetDateTime. However, “+02:00" is always resolved to the zone ID. Given the interrelationship between partitions and offsets, it will eventually work. But given the (and perhaps overhyped) correctness, I’d like to think of them as OffsetDateTime.

Am I missing something that distinguishes me?

Thanks!

Solution

It looks like this is actually a bug in Java 8. If you store the value of DateTimeFormatter#parse in a Temporal variable and print its getClass( ), you receive the following information when you compile and run with Java 8:

class java.time.ZonedDateTime

However, when compiled and run with Java 11, the output is what you expect:

class java.time.OffsetDateTime

I’ll go around for a specific bug report and edit this answer if I manage to find it. In this way, we can determine the cause of the error and the Java version that fixed the error.

Related Problems and Solutions