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)
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:
- utilisez une colonne de type
DATETIME
pour enregistrer unLocalDateTime
etVARCHAR
enregistrer un fuseau horaire comme"Europe/Paris"
etSMALLINT
sauvegarde d'un offset en quelques minutes. - convertissez le
ZonedDateTime
String
et l'enregistrer dans unVARCHAR
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.
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.