Missed opportunity to fix JDBC date handling in Java 8?

后端 未结 2 1022
孤街浪徒
孤街浪徒 2020-12-05 02:03

Can any Java 8 + JDBC expert tell me if something\'s wrong in the following reasoning? And, if in the secrets of Gods, why this hasn\'t been done?

A java.sql.D

2条回答
  •  忘掉有多难
    2020-12-05 02:27

    Short answer: no, date time handling is fixed in Java 8 / JDBC 4.2 because it has support for Java 8 Date and Time types. This can not be emulated using default methods.

    Java 8 could simply have added those default methods to PreparedStatement and ResultSet:

    This is not possible for several reasons:

    • java.time.OffsetDateTime has not equivalent in java.sql
    • java.time.LocalDateTime breaks on DST transitions when converting through java.sql.Timestamp because the latter depends on the JVM time zone, see code below
    • java.sql.Time has millisecond resolution but java.time.LocalTime has nanosecond resolution

    Therefore you need proper driver support, default methods would have to convert through java.sql types which introduces data loss.

    If you run this code in a JVM time zone with daylight savings time it will break. It searches the next transition in which the clocks are "set forward" and picks a LocalDateTime that is right in the middle of the transition. This is perfectly valid because Java LocalDateTime or SQL TIMESTAMP have no time zone and therefore no time zone rules and therefore no daylight saving time. java.sql.Timestamp on the other hand is bound to the JVM time zone and therefore subject to daylight saving time.

    ZoneId systemTimezone = ZoneId.systemDefault();
    Instant now = Instant.now();
    
    ZoneRules rules = systemTimezone.getRules();
    ZoneOffsetTransition transition = rules.nextTransition(now);
    assertNotNull(transition);
    if (!transition.getDateTimeBefore().isBefore(transition.getDateTimeAfter())) {
      transition = rules.nextTransition(transition.getInstant().plusSeconds(1L));
      assertNotNull(transition);
    }
    
    Duration gap = Duration.between(transition.getDateTimeBefore(), transition.getDateTimeAfter());
    LocalDateTime betweenTransitions = transition.getDateTimeBefore().plus(gap.dividedBy(2L));
    
    Timestamp timestamp = java.sql.Timestamp.valueOf(betweenTransitions);
    assertEquals(betweenTransitions, timestamp.toLocalDateTime());
    

提交回复
热议问题