web-dev-qa-db-fra.com

LocalDateTime, ZonedDateTime et Timestamp

J'ai une application SpringBoot. en utilisant Spring Initializer, Tomcat intégré, le moteur de modèle Thymeleaf et le package en tant que fichier JAR exécutable.

J'ai un objet de domaine avec 2 propriétés (initDate, endDate). Je veux créer 2 convertisseurs pour gérer la base de données mySQL

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

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

le convertisseur 1 (est 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 car j'ai 2 erreurs:

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

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

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

12
La Carbonell

Timestamp étend Date pour fournir une précision en nanosecondes. Ni Date ni Timestamp ne sont conçus pour faire référence à un fuseau horaire spécifique en tant que ZoneDateTime.

Si vous devez convertir ZonedDateTime -> Timestamp, vous devrez supprimer les informations de fuseau horaire/décalage. Par exemple.

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

et pour convertir 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 de sauvegarder ZonedDateTime variables dans la base de données et de conserver les différents fuseaux horaires 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 un VARCHAR enregistrement d'un fuseau horaire comme "Europe/Paris" ou SMALLINT sauvegarde d'un décalage en minutes.
  2. Convertissez le ZonedDateTime en String et enregistrez-le dans une colonne VARCHAR comme "2017-05-16T14:12:48.983682+01:00[Europe/London]". Vous devrez ensuite l'analyser lors de la lecture de la base de données.
12
Manos Nikolaidis

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 également posé la bonne question, quel fuseau horaire voulez-vous? J'ai deviné ZoneId.systemDefault(). Évidemment, un fuseau horaire différent donnera un résultat différent, donc j'espère que vous y réfléchirez à deux fois et serez en mesure de trouver le bon fuseau horaire pour votre objectif.

PS J'ai réduit l'utilisation des parenthèses depuis que je l'ai trouvé plus lisible avec moins. Vous pouvez les rajouter si vous préférez.

8
Ole V.V.