Java LocalDateTime 、 ZonedDateTime 和时间戳

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/44002104/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 01:16:27  来源:igfitidea点击:

LocalDateTime , ZonedDateTime and Timestamp

javamysqljava-8java-timejava-date

提问by La Carbonell

I have a SpringBoot app. using Spring Initializer, embedded Tomcat, Thymeleaf template engine, and package as an executable JAR file.

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

I have a domain object with 2 properties (initDate, endDate). I want to create 2 converters to deal with mySQL DB

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

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

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

the converter 1 (is OK)

转换器 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());
    }
}

This is the one that I want to create

这是我想要创建的

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

But I can't because I have 2 errors:

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

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

and the TimeStamp does not have the method toZonedDateTime()

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

and if I don't add any converter for the ZonedDate, JPA creates a table with the type varbinary(255)

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

采纳答案by Manos Nikolaidis

Timestampextends Dateto provide nanosecond accuracy. Neither Datenor Timestampare designed to refer to a specific timezone as ZoneDateTime.

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

If you need to convert ZonedDateTime-> Timestampyou will have to discard the timezone/offset information. E.g.

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

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

and for converting Timestamp-> ZonedDateTimeyou need to specify an offset:

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

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

or timezone:

或时区:

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

If your intention is to save ZonedDateTimevariables in the database and preserve the various timezones specified there, I recommend designing your database accordingly. Suggestions:

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

  1. Use a column of type DATETIMEto save a LocalDateTimeand a VARCHARsaving a timezone like "Europe/Paris"or a SMALLINTsaving an offset in minutes.
  2. Convert the ZonedDateTimeto a Stringand save in a VARCHARcolumn like "2017-05-16T14:12:48.983682+01:00[Europe/London]". You'll then have to parse it when reading from the database.
  1. 使用类型的列DATETIME来保存LocalDateTimeVARCHAR保存时区,"Europe/Paris"SMALLINT以分钟为单位保存偏移量。
  2. 将 转换ZonedDateTime为 aString并保存在VARCHAR"2017-05-16T14:12:48.983682+01:00[Europe/London]". 然后,您必须在从数据库中读取时对其进行解析。

回答by Ole V.V.

Jon Skeet said it already:

乔恩·斯基特已经说过:

@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 also asked the good question, which time zone do you want? I have guessed at ZoneId.systemDefault(). Obviously a different time zone will give a different result, so I hope you will think twice and will be able to find the right time zone for your purpose.

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

PS I have reduced the usage of parentheses since I found it more readable with fewer. You can add them back in if you prefer.

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