2017-05-16 18 views
5

Tôi có một ứng dụng SpringBoot. sử dụng Spring Initializer, nhúng Tomcat, công cụ mẫu Thymeleaf và gói dưới dạng tệp JAR thực thi.LocalDateTime, ZonedDateTime và Timestamp

Tôi có đối tượng miền với 2 thuộc tính (initDate, endDate). Tôi muốn tạo ra 2 bộ chuyển đổi để đối phó với mySQL DB

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

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

bộ chuyển đổi 1 (là 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()); 
    } 
} 

Đây là một trong đó tôi muốn tạo

@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()); 
    } 
} 

Nhưng tôi không thể vì tôi có 2 lỗi:

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

và các dấu thời gian không có phương pháp toZonedDateTime()

và nếu tôi không thêm bất kỳ chuyển đổi cho ZonedDate, JPA tạo ra một bảng với kiểu varbinary(255)

+3

Bạn muốn sử dụng múi giờ nào? (Nó có vẻ khá bị hỏng hơn bạn có thể chuyển đổi một 'Dấu thời gian' thành một' LocalDateTime', nhưng chúng ta đi.) Bạn cũng có thể muốn đi qua 'Timestamp.toInstant()' và 'Timestamp.from (Instant)'. –

Trả lời

4

Timestamp mở rộng Date để cung cấp độ chính xác nano giây. Không phải Date cũng không phải Timestamp được thiết kế để chỉ một múi giờ cụ thể dưới dạng ZoneDateTime.

Nếu bạn cần chuyển đổi ZonedDateTime ->Timestamp, bạn sẽ phải hủy thông tin múi giờ/khoảng trống. Ví dụ.

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

và để chuyển đổi Timestamp ->ZonedDateTime bạn cần phải xác định một offset:

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

hoặc múi giờ:

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

Nếu mục đích của bạn là để tiết kiệm ZonedDateTime biến trong cơ sở dữ liệu và bảo tồn các múi giờ khác nhau được chỉ định ở đó, tôi khuyên bạn nên thiết kế cơ sở dữ liệu của bạn cho phù hợp. Gợi ý:

  1. Sử dụng một cột kiểu DATETIME để tiết kiệm một LocalDateTimeVARCHAR tiết kiệm một múi giờ như "Europe/Paris" hoặc một SMALLINT tiết kiệm một bù đắp trong vài phút.
  2. Chuyển đổi ZonedDateTime thành String và lưu trong cột VARCHAR như "2017-05-16T14:12:48.983682+01:00[Europe/London]". Sau đó, bạn sẽ phải phân tích cú pháp khi đọc từ cơ sở dữ liệu.
+2

Đã bỏ phiếu cho đề xuất rõ ràng tốt về thiết kế cơ sở dữ liệu để giữ thông tin múi giờ. –

5

Jon Skeet nói nó đã:

@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 cũng đã đặt câu hỏi hay, bạn muốn múi giờ nào? Tôi đã đoán tại ZoneId.systemDefault(). Rõ ràng là một múi giờ khác nhau sẽ cho kết quả khác nhau, vì vậy tôi hy vọng bạn sẽ suy nghĩ hai lần và sẽ có thể tìm ra múi giờ phù hợp với mục đích của bạn.

PS Tôi đã giảm việc sử dụng dấu ngoặc đơn vì tôi thấy nó dễ đọc hơn với ít hơn. Bạn có thể thêm lại chúng nếu muốn.

Các vấn đề liên quan