当前位置: 代码迷 >> java >> PostgreSQL日期与Java即时 TL;博士 细节 关于java.time
  详细解决方案

PostgreSQL日期与Java即时 TL;博士 细节 关于java.time

热度:99   发布时间:2023-07-17 20:32:39.0

假设我在Java应用程序中有一个类型为Instant的字段,并将其以类型存储在PostgreSQL数据库中。

如果我救例如21.02.2019 14:03:59它会被存储为21.02.2019 ,但如何将它重新编译,当我从数据库中读取?

那将会:

  • 21.02.2019 00:00:00.000
  • 21.02.2019 23:59:59.000

PS。 我知道我应该改用Timestamp :)

这取决于您的阅读方式。 Instant和SQL DATE是不等效的,而且我不知道任何可靠的库甚至可以让您将DATE读取为Instant 如果您编写自己的代码允许这样做,那么即使没有任何意义,也可以使其以小时,分钟,秒和毫秒的方式填充,即使这没有任何意义(因此,对您问题的真正回答是“除非明确编写了将java.sql.Date转换为java.time.Instant代码,否则都不会。

如果您正在设计将瞬间存储为日期的软件,则您的设计存在缺陷。 在Java端使用LocalDate ,或者在数据库中使用TIMESTAMP

TL;博士

  • 符合SQL标准的数据库(例如Postgres)中的DATE列仅存储日期,时间和区域。
  • 使用LocalDate作为仅日期的值,不带时间和区域。
  • 要从Instant获取LocalDate ,请指定您要通过其确定日期的特定区域(时区)的人们所使用的挂钟时间。
  • 如果要存储时刻(由Instant对象表示),请使用SQL标准类型TIMESTAMP WITH TIME ZONE而不是DATE

细节

Instant使用UTC

Instant对象始终以UTC表示的时刻。 换句话说,与的为零小时-分钟-秒的时刻。

确定日期需要时区

因此,从Instant获取日期需要一个 ( )。 23日说,巴黎午夜过后的一刻是一个新的约会日期,而魁北克蒙特利尔则是“昨天” 22日 在任何给定时刻,日期都会在全球范围内变化。

因此,如果您要说的是魁北克省的日期,请指定时区“美国/蒙特利尔”。

ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;

您说您的数据库列的类型为 。 在Postgres中,就像SQL标准一样,它表示仅日期的值,没有日期和时区。

要仅存储日期,没有日期和时区,请提取LocalDate “本地”一词是指任何一个地区或所有地区,但不是任何一个特定的地区。

LocalDate ld = zdt.toLocalDate() ;

JDBC 4.2

在准备好的语句中通过占位符交换该LocalDate

myPreparedStatement.setObject( … , ld ) ; 

恢复:

LocalDate ld = myResultSet.getObject( … , LocalDate.class ) ;

保存日期,检索日期

从数据库读取后如何重新翻译?

那将会:

21.02.2019 00:00:00.000或…

这个问题没有道理。 当您从符合SQL标准的数据库(如Postgres)中读取DATE ,您将获得一个日期,一个日期,没有日期,也没有时区。

如果在DATE列中存储值2019-02-21LocalDate ,则返回相同的值:值2019-02-21LocalDate

一天的第一刻

如果要在一天的第一时刻添加时间,请让java.time为您确定。 在某些时区的某些日期,日期不是从00:00:00开始,而是可以从01:00:00这样的时间开始。

LocalDate ld = myResultSet.getObject( … , LocalDate.class ) ;
ZoneId z = ZoneId.of( "Pacific/Auckland" ) ;
ZonedDateTime zdt = ld.atStartOfDay( z ) ;  // Returns a `ZonedDateTime` object set to the first moment of the day as seen on that date in that time zone. May or may not be the time 00:00:00. 

世界标准时间

如果要使用UTC作为时区从Instant提取日期, Instant从UTC偏移零小时-分钟-秒,请使用OffsetDateTime类和常量 。

OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;
LocalDate ld = odt.toLocalDate() ;
myPreparedStatement.setObject( … , ld ) ; 

关于java.time

框架内置于Java 8及更高版本中。 这些类取代了麻烦的旧的日期时间类,例如 , 和 。

要了解更多信息,请参见 。 并在Stack Overflow中搜索许多示例和说明。 规格为 。

现在处于的项目建议迁移到类。

您可以直接与数据库交换java.time对象。 使用与或更高版本兼容的 。 不需要字符串,不需要java.sql.*类。

在哪里获取java.time类?

  • , , , 和更高版本-标准Java API的一部分,具有捆绑的实现。
    • Java 9添加了一些次要功能和修复。
    • 大多数java.time功能都在 Backport中反向移植到Java 6和7。
    • 更高版本的Android捆绑了java.time类的实现。
    • 对于早期的Android(<26), 项目改编了 (如上所述)。 请参阅 。

项目使用其他类扩展了java.time。 该项目为将来可能在java.time中添加内容提供了一个试验场。 您可以在这里找到一些有用的类,比如 , , ,和 。

  相关解决方案