LocalDateTime , ZonedDateTime 和 Timestamp

2022-09-03 05:10:34

我有一个SpringBoot应用程序,使用Spring Initializer,嵌入式Tomcat,Thymeleaf模板引擎,并打包为可执行JAR文件。

我有一个具有2个属性的域对象(initDate,endDate)。我想创建2个转换器来处理mySQL DB

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

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

转换器 1(正常)

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

这是我想创建的那个

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

但我不能,因为我有2个错误:

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

并且时间戳没有该方法toZonedDateTime()

如果我没有为ZonedDate添加任何转换器,JPA会创建一个表,其类型为varbinary(255)


答案 1

时间戳扩展以提供纳秒级精度。两者都不是旨在将特定时区称为 。DateDateTimestampZoneDateTime

如果需要转换 ->则必须丢弃时区/偏移量信息。例如:ZonedDateTimeTimestamp

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

并且要转换 ->您需要指定偏移量:TimestampZonedDateTime

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

或时区:

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

如果您打算将变量保存在数据库中并保留其中指定的各种时区,我建议您相应地设计数据库。建议:ZonedDateTime

  1. 使用类型的列保存 a 和保存时区(如)或保存偏移量(以分钟为单位)。DATETIMELocalDateTimeVARCHAR"Europe/Paris"SMALLINT
  2. 将 转换为 a 并保存在类似 .然后,您必须在从数据库读取时对其进行分析。ZonedDateTimeStringVARCHAR"2017-05-16T14:12:48.983682+01:00[Europe/London]"

答案 2

Jon Skeet已经说过了:

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

乔恩还问了一个好问题,你想要哪个时区?我已经猜到了.显然,不同的时区会给出不同的结果,所以我希望你能三思而后行,并能够找到适合你的目的的时区。ZoneId.systemDefault()

PS 我已经减少了括号的使用,因为我发现它更具可读性,更少。如果您愿意,可以将它们重新添加进来。