LocalDateTime,ZonedDateTime和Timestamp

La *_*ell 13 java mysql java-8 java-time java-date

我有一个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;
Run Code Online (Sandbox Code Playgroud)

转换器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());
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我想要创建的那个

@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());
    }
}
Run Code Online (Sandbox Code Playgroud)

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

The method valueOf(String) in the type Timestamp is not applicable for the arguments (ZonedDateTime)
Run Code Online (Sandbox Code Playgroud)

而TimeStamp没有这个方法 toZonedDateTime()

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

Man*_*dis 13

时间戳扩展Date为提供纳秒精度.既不Date也不Timestamp旨在将特定时区称为ZoneDateTime.

如果您需要转换ZonedDateTime- >,Timestamp您将不得不丢弃时区/偏移信息.例如

LocalDateTime withoutTimezone = zoneDateTime.toLocalDateTime();
Timestamp timestamp = Timestamp.valueOf(withoutTimezone));
Run Code Online (Sandbox Code Playgroud)

和转换Timestamp- > ZonedDateTime你需要指定一个偏移量:

LocalDateTime withoutTimezone = sqlTimestamp.toLocalDateTime();
ZonedDateTime withTimezone = withoutTimezone.atZone(ZoneId.of("+03:00"));
Run Code Online (Sandbox Code Playgroud)

或时区:

ZonedDateTime withTimezone = withoutTimezone.atZone(ZoneId.of("Europe/Paris"));
Run Code Online (Sandbox Code Playgroud)

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

  1. 使用类型列DATETIME来保存LocalDateTimeVARCHAR保存时区,"Europe/Paris"或者SMALLINT以分钟为单位保存偏移量.
  2. 转换ZonedDateTime为a String并保存在VARCHAR列中"2017-05-16T14:12:48.983682+01:00[Europe/London]".然后,您必须在从数据库中读取时解析它.

  • 赞成设计数据库以保存时区信息的明显好建议. (3认同)

Ole*_*.V. 8

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());
}
Run Code Online (Sandbox Code Playgroud)

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

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