2017-05-16 4 views
5

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

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

@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 peut pas parce que 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 ne fais pas de convertisseur pour la ZonedDate, JPA crée une table avec le type varbinary(255)

+3

Eh bien, quel fuseau horaire voulez-vous? (Il semble assez cassé que vous pouvez convertir un 'Timestamp' à un' LocalDateTime', mais nous y allons.) Vous pouvez bien vouloir passer par 'Timestamp.toInstant()' et 'Timestamp.from (Instant)'. –

Répondre

4

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

Si vous avez besoin de convertir ZonedDateTime ->Timestamp vous devrez ignorer 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 sauver ZonedDateTime des variables dans la base de données Préserver 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 sauver un LocalDateTime et un VARCHAR sauver un fuseau horaire comme "Europe/Paris" ou SMALLINT sauver un décalage en quelques minutes.
  2. Convertissez le ZonedDateTime en String et enregistrez dans une colonne VARCHAR comme "2017-05-16T14:12:48.983682+01:00[Europe/London]". Vous devrez alors l'analyser lors de la lecture de la base de données.
+2

Remis à la hausse pour la suggestion évidemment bonne de concevoir la base de données pour contenir les informations de fuseau horaire aussi. –

5

Jon Skeet dit déjà:

@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é au ZoneId.systemDefault(). Évidemment, un fuseau horaire différent donnera un résultat différent, alors j'espère que vous réfléchirez à deux fois et que vous pourrez trouver le bon fuseau horaire pour votre objectif. PS J'ai réduit l'utilisation des parenthèses puisque je l'ai trouvé plus lisible avec moins de parenthèses. Vous pouvez les rajouter si vous préférez.