我有一个类型为deadline_date
的{{1}}字段,值为timestamp with time zone
2018-05-03 19:00:00-05.
但是从我的Java代码查询时,它返回的值为select deadline_date from invoice_details where file_name='BHDHSB.pdf';
deadline_date
------------------------
2018-05-03 19:00:00-05
(1 row)
。
我认为它正在根据我的本地时区转换日期。
有什么方法可以获取表中存储的值?
我对Postgres使用以下Maven依赖项
2018-05-04 05:30:00+05:30
Test.java
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.4.1212</version>
</dependency>
答案 0 :(得分:2)
请勿使用getString()
来获取时间戳(实际上:仅仅用于字符串。不适用于数字,日期和时间戳)。
如果要处理时区识别的时间戳,则应在Java中使用OffsetDateTime
。
Postgres JDBC驱动程序直接通过getObject()
方法支持此操作:
OffsetDateTime deadline = resultSet.getObject("deadline_date", OffsetDateTime.class);
答案 1 :(得分:0)
Postgres 总是将时刻存储在UTC 的TIMESTAMP WITH TIME ZONE
类型的列中。
当心数据库访问工具:它可能会应用区域/偏移量调整来更改检索到的UTC值。这实际上是将其存储在该区域/偏移量中的瞬间产生了一种错觉,而实际上是将其存储在UTC中。
使用对象而非字符串与数据库交换日期时间值。
仅使用 java.time 类,而不使用旧版Date
/ Calendar
。对于UTC时刻,请使用java.time.Instant
类。
Instant instant = Instant.now() ;
myPreparedStatement.setObject( … , instant ) ;
检索。
Instant instant = myResultSet.getObject( … , Instant.class ) ;
在Java与数据库之间交换日期时间值时,建议您使用对象而不是字符串是正确的。重点是JDBC和您的JDBC driver,来回marshal data,同时调解差异和细节。
但是,其他答案错误地建议在Java中使用错误的类。
Postgres仅在UTC中保存时刻。输入类型TIMESTAMP WITH TIME ZONE
的数据库列的伴随输入的任何时区或UTC偏移信息都用于将值调整为UTC。然后,UTC值将保存到数据库,并且忘记了原始的区域/偏移量。
同样,当从类型为TIMESTAMP WITH TIME ZONE
的数据库列中检索值时,您总是以UTC形式获得值。
但是,可以选择在您和数据库之间使用的中间件或工具来更改传输中的UTC值,以应用时区或偏移量,从而调整该值。尽管我理解其背后的良好意图,但我认为这是一个糟糕的设计选择。但是这种行为会产生一种错觉,即存储的数据中存在区域/偏移量,而没有。
请注意,我在这里描述Postgres的行为。 SQL标准定义了我在这里讨论的数据类型,但没有定义它们的行为。不幸的是,SQL标准几乎没有涉及日期时间问题。因此,各种数据库实现的行为各不相同。 Postgres的适应UTC的行为对我来说很有意义。但是请注意,如果您关心日期时间值的原始区域/偏移量,则必须将其自己存储在单独的列中。
在Java方面,只需使用Instant
从类型TIMESTAMP WITH TIME ZONE
的数据库列发送和检索时刻。
发送。
Instant instant = Instant.now() ; // Capture the current moment in UTC.
myPreparedStatement.setObject( … , instant ) ;
检索。
Instant instant = myResultSet.getObject( … , Instant.class );
您可以将UTC调整为某个特定时区。
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
如果您正在使用OffsetDateTime
或ZonedDateTime
对象处理业务逻辑,请通过调用其Instant
方法来提取toInstant
。
Instant instant = myZonedDateTime.toInstant() ; // Extract an `Instant` object, effectively adjusting from some particular time zone to UTC.
一种完全不同的日期时间是一种故意缺少时区或UTC偏移量的概念的日期时间。因此,这种 not 表示特定时刻,是 not 在时间轴上的一点。此类型表示沿大约26-27小时(各个时区的范围)内的潜在时刻。
对于这种日期时间:
LocalDateTime
类。TIMESTAMP WITHOUT TIME ZONE
类型。将输入发送到Postgres中此类型的列时,将忽略所有伴随的区域/偏移信息。日期和日期保持原样并直接存储在数据库中。检索后,您将获得相同的日期和时间,而无需调整任何特定的时区。
java.time框架已内置在Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.Date
,Calendar
和SimpleDateFormat
。
目前位于Joda-Time的maintenance mode项目建议迁移到java.time类。
要了解更多信息,请参见Oracle Tutorial。并在Stack Overflow中搜索许多示例和说明。规格为JSR 310。
您可以直接与数据库交换 java.time 对象。使用符合JDBC driver或更高版本的JDBC 4.2。不需要字符串,不需要java.sql.*
类。
在哪里获取java.time类?
ThreeTen-Extra项目使用其他类扩展了java.time。该项目为将来可能在java.time中添加内容提供了一个试验场。您可能会在这里找到一些有用的类,例如Interval
,YearWeek
,YearQuarter
和more。
答案 2 :(得分:-1)
您可以在sql中完成此操作,只需更改查询即可。
select to_char(iiv_prescan_invoice_details.deadline_date, "yyyy:MM:dd HH24:MI:SS") as deadline_date
from iiv_prescan_invoice_details
或者您可以在Java中完成
LocalDateTime dateTime = resultSet.getTimestamp("deadline_date").toLocalDateTime();
System.out.println("Date Time: " + dateTime);