如何使用Java以正确的方式从数据库中检索日期?

3z6pesqy  于 2023-02-02  发布在  Java
关注(0)|答案(3)|浏览(157)

我尝试从数据库中检索日期时间值,并且我已将upload_date_time声明为Instant,这就是该值在数据库中的存储方式。

然而,当我尝试从数据库中检索该值时,它给我的是“2022-03- 01 T14:00:00 Z”。
上传订单表

@NotNull
@Column(name = "upload_date_time", nullable = false)
private Instant uploadDateTime;

public Instant getUploadDateTime() {
    return uploadDateTime;
}

public UploadOrder uploadDateTime(Instant uploadDateTime) {
    this.uploadDateTime= uploadDateTime;
    return this;
}

public void setUploadDateTime(Instant uploadDateTime) {
    this.uploadDateTime= uploadDateTime;
}

服务

public PrePickOrderOverPickEmailDTO generateOverPickEmails() {
log.debug("Request to retrieve Upload data : {}");
List<UploadOrder> uploadOrders = uploadPickRepository.findAllByEmailSent(false);
String data = "";
for (UploadOrder order : uploadOrders) {
        data = data +
        "Upload Date: " + order.getUploadDateTime() +"\n" +
         // do others
 }
}

很好奇我在这里做错了什么。任何帮助都是很好的。谢谢

qgzx9mmu

qgzx9mmu1#

由于您注解数据库时区为UTC+10:00,因此您看到的是正确的。
2022-03-02T00:00+10:002022-03-01T14:00:00Z是相同的日期,Z是UTC(+0),因此它们都表示相同的日期值,只是用不同的时区表示。
您可以通过以下方式进行验证:

jshell> java.time.OffsetDateTime.parse("2022-03-02T00:00+10:00").toInstant()
$4 ==> 2022-03-01T14:00:00Z

若要将UTC瞬间定位到不同的区域,可以使用Instant::atZone()Instant::atOffset()

3df52oht

3df52oht2#

Instant是一个时刻,没有指定任何时区,而实际存储的Instant是UTC 3月1日下午2点,也就是AEST 3月2日午夜。
当您通过SQL客户端查看此值时,SQL客户端将其转换为您的本地时间,因此您看到的是3月2日午夜。
当你用Java程序检索它时,你不需要指定时区或时间偏移量就可以显示它,当你对Instant这样做时,你可以看到它是UTC格式的。
实际上,你需要做的是在显示Instant之前将其转换为LocalDateTime-这样,你就可以在AEST中看到它,或者你的本地时区。LocalDateTime类有一个名为ofInstantstatic方法,它可以做到这一点。你需要传递你的时区的ZoneId,如下所示。

LocalDateTime timeInBrisbane = LocalDateTime.ofInstant(uploadDateTime, ZoneId.of("Australia/Brisbane"));

甚至像这样,获取系统默认时区。

LocalDateTime timeInDefaultZone = LocalDateTime.ofInstant(uploadDateTime, ZoneId.systemDefault());
vngu2lb8

vngu2lb83#

数据类型

问题上的标记表示您正在使用 Microsoft SQL Server 作为数据库引擎。
根据文档,您应该将列定义为数据类型datetimeoffset,该类型类似于SQL标准类型TIMESTAMP WITH TIME ZONE,它存储一个时刻

  • 不要 * 使用smalldatetimedatetimedatetime2类型。这些类型缺少时区或UTC偏移量的上下文。因此这些类型不能表示时刻,即时间线上的特定点。

👉 给定使用名称uploadDateTime的代码片段,您的业务逻辑需要跟踪时刻,因此您的表列必须是datetimeoffset类型。
你的第一句话是:
我正在尝试检索日期时间值
如果您的意思是字面上的datetime类型,那么您的列使用了错误的类型,这将给您带来混乱和麻烦。

OffsetDateTime

虽然您忽略了在@Column注解中使用的是什么框架库,但我不能肯定地说,但我可以猜测Instant是错误的Java类。
JDBC 4.2及更高版本的JDBC规范要求JDBC drivers支持 java.time 类。该规范将SQL标准类型TIMESTAMP WITH TIME ZONE的值Map到Java类java.time.OffsetDateTime。Java类Instant在JDBC中 * 根本没有 * Map。
检索OffsetDateTime后,如果需要,可以提取InstantInstant instant = myOffsetDateTime.toInstant() ; .

相关问题