使用Java在PostgreSQL中存储时间的最佳方法是什么?

时间:2011-07-08 16:13:13

标签: java postgresql date jdbc

我在PostgreSQL数据库中存储了两个日期。首先,是网页访问的数据,第二个日期是网页的最后修改日期(这是一个很长的时间)。

我怀疑存储这些值的最佳策略是什么。

我只需要日/月/年和小时:秒,这只适用于统计建议。

所以,有些疑惑:

  • 最好存储多久并转换为恢复信息或以上述数据格式存储?
  • 最好设置软件访问日期或数据库中的插入日期吗?
  • 在Java中,处理日期的最佳类是怎样的?

3 个答案:

答案 0 :(得分:70)

任何在Postgresql中存储日期和时间数据的策略都应该依赖于这两点:

  • 您的解决方案永远不会依赖于服务器或客户端时区设置。
  • 目前,Postgresql(与大多数数据库一样)没有数据类型来存储带有时区的完整日期和时间。因此,您需要(在概念上)决定InstantLocalDateTime数据类型。

我对每个场景的配方:


如果您想要在特定事件(通常是某些创建/修改/删除)发生时记录物理即时(真正的“时间戳”),那么使用方法:

(不要让Postgresql特有的数据类型WITH TIMEZONE / WITHOUT TIMEZONE混淆你:它们实际上都没有存储时区)

一些样板代码:以下假设psPreparedStatementrsResultSettzUTC是静态Calendar对象对应UTC时区。

public static final Calendar tzUTC = Calendar.getInstance(TimeZone.getTimeZone("UTC"));  

Instant写入数据库TIMESTAMPTZ

Instant instant = ...;
Timestamp ts = instant != null ? new Timestamp(instant.toEpochMilli()) : null;
ps.setTimestamp(col, ts, tzUTC);   // column is TIMESTAMPTZ!

从数据库Instant中读取TIMESTAMPTZ

Timestamp ts = rs.getTimestamp(col,tzUTC); // column is TIMESTAMPTZ
Instant inst = ts !=null ? Instant.ofEpochMilli(ts.getTime()) : null;

如果您的PG类型为TIMESTAMPTZ,则可以安全地工作(在这种情况下,calendarUTC对该代码没有影响;但始终建议不依赖于默认时区)。 “安全”意味着结果将不依赖于服务器或数据库时区,或时区信息:操作是完全可逆的,无论时区设置发生什么,您都将获得相同的“瞬间”时间“你原来在Java方面。


如果您有一个“民用”本地日期时间(即字段{year-month-day hour:min:sec}),而不是时间戳(物理时间轴上的瞬间),你应该使用

从数据库LocalDateTime中读取TIMESTAMP

Timestamp ts = rs.getTimestamp(col, tzUTC); //
LocalDateTime localDt = null;
if( ts != null ) 
    localDt =  LocalDateTime.ofInstant(Instant.ofEpochMilli(ts.getTime()), ZoneOffset.UTC);

LocalDateTime写入数据库TIMESTAMP

  Timestamp ts = null;
  if( localDt != null)    
      ts = new Timestamp(localDt.toInstant(ZoneOffset.UTC).toEpochMilli()), tzUTC);
  ps.setTimestamp(colNum,ts, tzUTC); 

同样,这个策略是安全的,你可以安静地睡觉:如果你存储2011-10-30 23:59:30,你将总是检索那些精确的字段(小时= 23,分钟= 59 ......等),无论如何 - 即使明天你的Postgresql服务器(或客户端)的时区发生了变化,或者你的JVM或你的操作系统时区,或者你的国家修改了其DST规则等等。


补充:如果你想(似乎是一个自然要求)存储完整的日期时间规范(ZonedDatetime:时间戳和时区,其中隐含地还包括完整的民用日期时间信息 - 加上时区) ,那么你运气不好:Postgresql没有这方面的数据类型(据我所知,其他数据库都没有)。您必须设计自己的存储,可能是在一对字段中:可能是上述两种类型(高度冗余,虽然检索和计算有效),或者其中一种加上时间偏移(您丢失了时区信息,一些计算成为困难,有些不可能),或其中一个加上时区(作为字符串;一些计算可能非常昂贵)。

答案 1 :(得分:3)

java.time

它并不漂亮,但这对于我使用Java {8}及更高版本(ZonedDateTime)中的新java.time框架的Tutorial实例起了作用:

ZonedDateTime receivedTimestamp = some_ts_value;
Timestamp ts = new Timestamp(receivedTimestamp.toInstant().toEpochMilli());
ps.setTimestamp(
   1, 
   ts, 
   Calendar.getInstance(TimeZone.getTimeZone(receivedTimestamp.getZone()))
); 

答案 2 :(得分:2)

在Java应用程序中使用java.util.Date,在数据库中使用timestamp with time zone