LocalDateTime, ZonedDateTime et Timestamp

j'ai une application SpringBoot. en utilisant Spring Initializer, embedded Tomcat, Thymeleaf template engine, et package comme un fichier JAR exécutable.

j'ai un objet de domaine avec 2 propriétés (initDate, endDate). Je veux créer 2 convertisseurs pour traiter avec mySQL DB

@Convert(converter = LocalDateTimeAttributeConverter.class) 
private LocalDateTime initDate;

@Convert(converter = ZonedDateTimeAttributeConverter.class) 
private ZonedDateTime endDate;

le convertisseur 1 (OK)

@Converter
public class LocalDateTimeAttributeConverter implements AttributeConverter<LocalDateTime, Timestamp> {

    @Override
    public Timestamp convertToDatabaseColumn(LocalDateTime localDateTime) {
        return (localDateTime == null ? null : Timestamp.valueOf(localDateTime));
    }

    @Override
    public LocalDateTime convertToEntityAttribute(Timestamp sqlTimestamp) {
        return (sqlTimestamp == null ? null : sqlTimestamp.toLocalDateTime());
    }
}

C'est celui que je veux créer

@Converter
public class ZonedDateTimeAttributeConverter implements AttributeConverter<ZonedDateTime, Timestamp> {

    @Override
    public Timestamp convertToDatabaseColumn(ZonedDateTime zoneDateTime) {
        return (zoneDateTime == null ? null : Timestamp.valueOf(zoneDateTime));
    }


    @Override
    public ZonedDateTime convertToEntityAttribute(Timestamp sqlTimestamp) {
        return (sqlTimestamp == null ? null : sqlTimestamp.toZonedDateTime());
    }
}

Mais je ne peux pas parce que j'ai 2 erreurs:

The method valueOf(String) in the type Timestamp is not applicable for the arguments (ZonedDateTime)

et la TimeStamp n'a pas la méthode toZonedDateTime()

et si je n'ajoute aucun convertisseur pour la ZonedDate, JPA crée une table avec le type varbinary(255)

8
demandé sur La Carbonell 2017-05-16 15:55:15

2 réponses

Timestamp extends Date pour fournir une précision de nanoseconde. Ni Date ni Timestamp sont conçus pour se référer à un fuseau horaire ZoneDateTime.

si vous devez convertir ZonedDateTime -> Timestamp vous devrez supprimer les informations du fuseau horaire/offset. E. g.

LocalDateTime withoutTimezone = zoneDateTime.toLocalDateTime();
Timestamp timestamp = Timestamp.valueOf(withoutTimezone));

et pour la conversion Timestamp -> ZonedDateTime vous devez spécifier un décalage:

LocalDateTime withoutTimezone = sqlTimestamp.toLocalDateTime();
ZonedDateTime withTimezone = withoutTimezone.atZone(ZoneId.of("+03:00"));

ou fuseau horaire:

ZonedDateTime withTimezone = withoutTimezone.atZone(ZoneId.of("Europe/Paris"));

si votre intention est enregistrer ZonedDateTime variables dans la base de données et de préserver les différents délais qui y sont spécifiés, je recommande de concevoir votre base de données en conséquence. Suggestions:

  1. utilisez une colonne de type DATETIME pour enregistrer un LocalDateTime et VARCHAR enregistrer un fuseau horaire comme "Europe/Paris" et SMALLINT sauvegarde d'un offset en quelques minutes.
  2. convertissez le ZonedDateTimeString et l'enregistrer dans un VARCHAR colonne "2017-05-16T14:12:48.983682+01:00[Europe/London]". Vous aurez alors à analyser lors de la lecture de l' la base de données.
7
répondu Manos Nikolaidis 2017-05-16 13:50:06

Jon Skeet l'a déjà dit:

@Override
public Timestamp convertToDatabaseColumn(ZonedDateTime zoneDateTime) {
    return zoneDateTime == null ? null : Timestamp.from(zoneDateTime.toInstant());
}

@Override
public ZonedDateTime convertToEntityAttribute(Timestamp sqlTimestamp) {
    return sqlTimestamp == null ? null : sqlTimestamp.toInstant().atZone(ZoneId.systemDefault());
}

Jon a aussi posé la bonne question, quel fuseau horaire voulez-vous? Je l'ai deviné à ZoneId.systemDefault(). Évidemment un fuseau horaire différent donnera un résultat différent, donc j'espère que vous allez réfléchir à deux fois et sera en mesure de trouver le bon fuseau horaire de votre but.

PS j'ai réduit l'usage des parenthèses car je l'ai trouvé plus lisible avec moins. Vous pouvez rajouter si vous le souhaitez.

6
répondu Ole V.V. 2017-05-16 13:19:05